X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-sysdeps-util-unix.c;h=631c199f46cd6ac8e2991c137d87a179e0ade7b2;hb=7d9239c9c78cb6d0b9c282376fcf3cda1de23209;hp=cf77f0a67f7980fbd39ff6e7c2df5dc2e8a3724a;hpb=6db588b8544e117241a3be2c595dfc8fdcdc8f59;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c index cf77f0a..631c199 100644 --- a/dbus/dbus-sysdeps-util-unix.c +++ b/dbus/dbus-sysdeps-util-unix.c @@ -21,9 +21,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ + +#include #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 @@ -39,16 +42,24 @@ #include #include #include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif #include #include #include #include + +#ifdef HAVE_SYSLOG_H #include +#endif #ifdef HAVE_SYS_SYSLIMITS_H #include #endif +#include "sd-daemon.h" + #ifndef O_BINARY #define O_BINARY 0 #endif @@ -117,6 +128,7 @@ _dbus_become_daemon (const DBusString *pidfile, dup2 (dev_null_fd, 2); else _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n"); + close (dev_null_fd); } if (!keep_umask) @@ -248,7 +260,8 @@ _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile, 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)) { @@ -303,36 +316,201 @@ _dbus_verify_daemon_user (const char *user) 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 @@ -376,7 +554,7 @@ _dbus_user_at_console (const char *username, DBusError *error) { - DBusString f; + DBusString u, f; dbus_bool_t result; result = FALSE; @@ -392,8 +570,9 @@ _dbus_user_at_console (const char *username, 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; @@ -514,54 +693,14 @@ _dbus_directory_open (const DBusString *filename, 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 @@ -572,37 +711,24 @@ _dbus_directory_get_next_file (DBusDirIter *iter, 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] == '.' && @@ -616,12 +742,10 @@ _dbus_directory_get_next_file (DBusDirIter *iter, { 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; } } @@ -958,7 +1082,7 @@ _dbus_string_get_dirname (const DBusString *filename, static void string_squash_nonprintable (DBusString *str) { - char *buf; + unsigned char *buf; int i, len; buf = _dbus_string_get_data (str); @@ -966,11 +1090,11 @@ string_squash_nonprintable (DBusString *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] = '?'; } } @@ -1040,10 +1164,10 @@ _dbus_command_for_pid (unsigned long pid, 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; @@ -1054,3 +1178,180 @@ fail: _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); +}