* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+
+#include <config.h>
#include "dbus-sysdeps.h"
#include "dbus-sysdeps-unix.h"
#include "dbus-internals.h"
+#include "dbus-pipe.h"
#include "dbus-protocol.h"
#include "dbus-string.h"
#define DBUS_USERDB_INCLUDES_PRIVATE 1
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
#include <grp.h>
#include <sys/socket.h>
#include <dirent.h>
#include <sys/un.h>
+
+#ifdef HAVE_SYSLOG_H
#include <syslog.h>
+#endif
#ifdef HAVE_SYS_SYSLIMITS_H
#include <sys/syslimits.h>
#endif
+#include "sd-daemon.h"
+
#ifndef O_BINARY
#define O_BINARY 0
#endif
dup2 (dev_null_fd, 2);
else
_dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
+ close (dev_null_fd);
}
if (!keep_umask)
DBusString pid;
int bytes;
- _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd_or_handle);
+ _dbus_verbose ("writing our pid to pipe %d\n",
+ print_pid_pipe->fd);
if (!_dbus_string_init (&pid))
{
return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
}
-void
-_dbus_init_system_log (void)
+
+/* The HAVE_LIBAUDIT case lives in selinux.c */
+#ifndef HAVE_LIBAUDIT
+/**
+ * Changes the user and group the bus is running as.
+ *
+ * @param user the user to become
+ * @param error return location for errors
+ * @returns #FALSE on failure
+ */
+dbus_bool_t
+_dbus_change_to_daemon_user (const char *user,
+ DBusError *error)
+{
+ dbus_uid_t uid;
+ dbus_gid_t gid;
+ DBusString u;
+
+ _dbus_string_init_const (&u, user);
+
+ if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "User '%s' does not appear to exist?",
+ user);
+ return FALSE;
+ }
+
+ /* setgroups() only works if we are a privileged process,
+ * so we don't return error on failure; the only possible
+ * failure is that we don't have perms to do it.
+ *
+ * not sure this is right, maybe if setuid()
+ * is going to work then setgroups() should also work.
+ */
+ if (setgroups (0, NULL) < 0)
+ _dbus_warn ("Failed to drop supplementary groups: %s\n",
+ _dbus_strerror (errno));
+
+ /* Set GID first, or the setuid may remove our permission
+ * to change the GID
+ */
+ if (setgid (gid) < 0)
+ {
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Failed to set GID to %lu: %s", gid,
+ _dbus_strerror (errno));
+ return FALSE;
+ }
+
+ if (setuid (uid) < 0)
+ {
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Failed to set UID to %lu: %s", uid,
+ _dbus_strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif /* !HAVE_LIBAUDIT */
+
+
+/**
+ * Attempt to ensure that the current process can open
+ * at least @p limit file descriptors.
+ *
+ * If @p limit is lower than the current, it will not be
+ * lowered. No error is returned if the request can
+ * not be satisfied.
+ *
+ * @param limit number of file descriptors
+ */
+void
+_dbus_request_file_descriptor_limit (unsigned int limit)
+{
+#ifdef HAVE_SETRLIMIT
+ struct rlimit lim;
+ struct rlimit target_lim;
+
+ /* No point to doing this practically speaking
+ * if we're not uid 0. We expect the system
+ * bus to use this before we change UID, and
+ * the session bus takes the Linux default
+ * of 1024 for both cur and max.
+ */
+ if (getuid () != 0)
+ return;
+
+ if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
+ return;
+
+ if (lim.rlim_cur >= limit)
+ return;
+
+ /* Ignore "maximum limit", assume we have the "superuser"
+ * privileges. On Linux this is CAP_SYS_RESOURCE.
+ */
+ target_lim.rlim_cur = target_lim.rlim_max = limit;
+ /* Also ignore errors; if we fail, we will at least work
+ * up to whatever limit we had, which seems better than
+ * just outright aborting.
+ *
+ * However, in the future we should probably log this so OS builders
+ * have a chance to notice any misconfiguration like dbus-daemon
+ * being started without CAP_SYS_RESOURCE.
+ */
+ setrlimit (RLIMIT_NOFILE, &target_lim);
+#endif
+}
+
+void
+_dbus_init_system_log (dbus_bool_t is_daemon)
{
- openlog ("dbus", LOG_PID, LOG_DAEMON);
+#ifdef HAVE_SYSLOG_H
+ int logopts = LOG_PID;
+
+#if HAVE_DECL_LOG_PERROR
+#ifdef HAVE_SYSTEMD
+ if (!is_daemon || sd_booted () <= 0)
+#endif
+ logopts |= LOG_PERROR;
+#endif
+
+ openlog ("dbus", logopts, LOG_DAEMON);
+#endif
}
/**
- * Log an informative message. Intended for use primarily by
- * the system bus.
+ * Log a message to the system log file (e.g. syslog on Unix).
*
+ * @param severity a severity value
* @param msg a printf-style format string
- * @param args arguments for the format string
*/
-void
-_dbus_log_info (const char *msg, va_list args)
+void
+_dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...)
{
- vsyslog (LOG_DAEMON|LOG_NOTICE, msg, args);
+ va_list args;
+
+ va_start (args, msg);
+
+ _dbus_system_logv (severity, msg, args);
+
+ va_end (args);
}
/**
- * Log a security-related message. Intended for use primarily by
- * the system bus.
+ * Log a message to the system log file (e.g. syslog on Unix).
*
+ * @param severity a severity value
* @param msg a printf-style format string
* @param args arguments for the format string
+ *
+ * If the FATAL severity is given, this function will terminate the program
+ * with an error code.
*/
-void
-_dbus_log_security (const char *msg, va_list args)
+void
+_dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args)
{
- vsyslog (LOG_AUTH|LOG_NOTICE, msg, args);
+ va_list tmp;
+#ifdef HAVE_SYSLOG_H
+ int flags;
+ switch (severity)
+ {
+ case DBUS_SYSTEM_LOG_INFO:
+ flags = LOG_DAEMON | LOG_NOTICE;
+ break;
+ case DBUS_SYSTEM_LOG_SECURITY:
+ flags = LOG_AUTH | LOG_NOTICE;
+ break;
+ case DBUS_SYSTEM_LOG_FATAL:
+ flags = LOG_DAEMON|LOG_CRIT;
+ break;
+ default:
+ return;
+ }
+
+ DBUS_VA_COPY (tmp, args);
+ vsyslog (flags, msg, tmp);
+ va_end (tmp);
+#endif
+
+#if !defined(HAVE_SYSLOG_H) || !HAVE_DECL_LOG_PERROR
+ {
+ /* vsyslog() won't write to stderr, so we'd better do it */
+ DBUS_VA_COPY (tmp, args);
+ fprintf (stderr, "dbus[" DBUS_PID_FORMAT "]: ", _dbus_getpid ());
+ vfprintf (stderr, msg, tmp);
+ fputc ('\n', stderr);
+ va_end (tmp);
+ }
+#endif
+
+ if (severity == DBUS_SYSTEM_LOG_FATAL)
+ exit (1);
}
/** Installs a UNIX signal handler
DBusError *error)
{
- DBusString f;
+ DBusString u, f;
dbus_bool_t result;
result = FALSE;
goto out;
}
+ _dbus_string_init_const (&u, username);
- if (!_dbus_string_append (&f, username))
+ if (!_dbus_concat_dir_and_file (&f, &u))
{
_DBUS_SET_OOM (error);
goto out;
return iter;
}
-/* Calculate the required buffer size (in bytes) for directory
- * entries read from the given directory handle. Return -1 if this
- * this cannot be done.
- *
- * If you use autoconf, include fpathconf and dirfd in your
- * AC_CHECK_FUNCS list. Otherwise use some other method to detect
- * and use them where available.
- */
-static dbus_bool_t
-dirent_buf_size(DIR * dirp, size_t *size)
-{
- long name_max;
-# if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
-# if defined(HAVE_DIRFD)
- name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
-# elif defined(HAVE_DDFD)
- name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
-# else
- name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
-# endif /* HAVE_DIRFD */
- if (name_max == -1)
-# if defined(NAME_MAX)
- name_max = NAME_MAX;
-# else
- return FALSE;
-# endif
-# elif defined(MAXNAMELEN)
- name_max = MAXNAMELEN;
-# else
-# if defined(NAME_MAX)
- name_max = NAME_MAX;
-# else
-# error "buffer size for readdir_r cannot be determined"
-# endif
-# endif
- if (size)
- *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
- else
- return FALSE;
-
- return TRUE;
-}
-
/**
* Get next file in the directory. Will not return "." or ".." on
* UNIX. If an error occurs, the contents of "filename" are
* undefined. The error is never set if the function succeeds.
*
+ * This function is not re-entrant, and not necessarily thread-safe.
+ * Only use it for test code or single-threaded utilities.
+ *
* @param iter the iterator
* @param filename string to be set to the next file in the dir
* @param error return location for error
DBusString *filename,
DBusError *error)
{
- struct dirent *d, *ent;
- size_t buf_size;
+ struct dirent *ent;
int err;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
- if (!dirent_buf_size (iter->d, &buf_size))
- {
- dbus_set_error (error, DBUS_ERROR_FAILED,
- "Can't calculate buffer size when reading directory");
- return FALSE;
- }
-
- d = (struct dirent *)dbus_malloc (buf_size);
- if (!d)
- {
- dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
- "No memory to read directory entry");
- return FALSE;
- }
again:
- err = readdir_r (iter->d, d, &ent);
- if (err || !ent)
+ errno = 0;
+ ent = readdir (iter->d);
+
+ if (!ent)
{
+ err = errno;
+
if (err != 0)
dbus_set_error (error,
_dbus_error_from_errno (err),
"%s", _dbus_strerror (err));
- dbus_free (d);
return FALSE;
}
else if (ent->d_name[0] == '.' &&
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
"No memory to read directory entry");
- dbus_free (d);
return FALSE;
}
else
{
- dbus_free (d);
return TRUE;
}
}
static void
string_squash_nonprintable (DBusString *str)
{
- char *buf;
+ unsigned char *buf;
int i, len;
buf = _dbus_string_get_data (str);
for (i = 0; i < len; i++)
{
- unsigned char c = (unsigned char) buf[i];
+ unsigned char c = (unsigned char) buf[i];
if (c == '\0')
- c = ' ';
+ buf[i] = ' ';
else if (c < 0x20 || c > 127)
- c = '?';
+ buf[i] = '?';
}
}
goto fail;
string_squash_nonprintable (&cmdline);
-
+
if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
goto oom;
-
+
_dbus_string_free (&cmdline);
_dbus_string_free (&path);
return TRUE;
_dbus_string_free (&path);
return FALSE;
}
+
+/*
+ * replaces the term DBUS_PREFIX in configure_time_path by the
+ * current dbus installation directory. On unix this function is a noop
+ *
+ * @param configure_time_path
+ * @return real path
+ */
+const char *
+_dbus_replace_install_prefix (const char *configure_time_path)
+{
+ return configure_time_path;
+}
+
+#define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
+#define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
+
+/**
+ * Returns the standard directories for a session bus to look for 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
+ */
+
+dbus_bool_t
+_dbus_get_standard_session_servicedirs (DBusList **dirs)
+{
+ 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");
+
+ if (xdg_data_home != NULL)
+ {
+ if (!_dbus_string_append (&servicedir_path, xdg_data_home))
+ goto oom;
+ }
+ 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;
+ }
+
+ if (!_dbus_string_append (&servicedir_path, ":"))
+ goto oom;
+
+ if (xdg_data_dirs != NULL)
+ {
+ if (!_dbus_string_append (&servicedir_path, xdg_data_dirs))
+ goto oom;
+
+ if (!_dbus_string_append (&servicedir_path, ":"))
+ goto oom;
+ }
+ else
+ {
+ if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:"))
+ goto oom;
+ }
+
+ /*
+ * 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_SESSION_SERVICEDIR,
+ dirs))
+ goto oom;
+
+ _dbus_string_free (&servicedir_path);
+ return TRUE;
+
+ oom:
+ _dbus_string_free (&servicedir_path);
+ return FALSE;
+}
+
+
+/**
+ * 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)
+{
+ /*
+ * DBUS_DATADIR may be the same as one of the standard directories. However,
+ * the config parser should take care of the duplicates.
+ *
+ * Also, append /lib as counterpart of /usr/share on the root
+ * directory (the root directory does not know /share), in order to
+ * facilitate early boot system bus activation where /usr might not
+ * be available.
+ */
+ static const char standard_search_path[] =
+ "/usr/local/share:"
+ "/usr/share:"
+ DBUS_DATADIR ":"
+ "/lib";
+ DBusString servicedir_path;
+
+ _dbus_string_init_const (&servicedir_path, standard_search_path);
+
+ return _dbus_split_paths_and_append (&servicedir_path,
+ DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR,
+ dirs);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * Append the absolute path of the session.conf file.
+ *
+ * @param str the string to append to
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_append_session_config_file (DBusString *str)
+{
+ return _dbus_string_append (str, DBUS_SESSION_CONFIG_FILE);
+}