From 44ed933284589134603913b05f55ca55e8c5a566 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 1 Apr 2003 05:33:01 +0000 Subject: 2003-04-01 Havoc Pennington * dbus/dbus-server.c (dbus_server_set_auth_mechanisms): new function * dbus/dbus-auth.c (_dbus_auth_set_mechanisms): new * dbus/dbus-internals.c (_dbus_dup_string_array): new function * dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): chmod the socket 0777, and unlink any existing socket. * bus/bus.c (bus_context_new): change our UID/GID and fork if the configuration file so specifies; set up auth mechanism restrictions * bus/config-parser.c (bus_config_parser_content): add support for option and fill in code for * bus/system.conf.in: add to default configuration, and limit auth mechanisms to EXTERNAL * doc/config-file.txt (Elements): add * dbus/dbus-sysdeps.c (_dbus_become_daemon): new function (_dbus_change_identity): new function --- dbus/dbus-sysdeps.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 5 deletions(-) (limited to 'dbus/dbus-sysdeps.c') diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index cab970a0..71863ef6 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -313,6 +313,21 @@ _dbus_write_two (int fd, #endif /* !HAVE_WRITEV */ } +#define _DBUS_MAX_SUN_PATH_LENGTH 99 + +/** + * @def _DBUS_MAX_SUN_PATH_LENGTH + * + * Maximum length of the path to a UNIX domain socket, + * sockaddr_un::sun_path member. POSIX requires that all systems + * support at least 100 bytes here, including the nul termination. + * We use 99 for the max value to allow for the nul. + * + * We could probably also do sizeof (addr.sun_path) + * but this way we are the same on all platforms + * which is probably a good idea. + */ + /** * 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 @@ -345,8 +360,7 @@ _dbus_connect_unix_socket (const char *path, _DBUS_ZERO (addr); addr.sun_family = AF_UNIX; - strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH); - addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH-1] = '\0'; + strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0) { @@ -377,7 +391,13 @@ _dbus_connect_unix_socket (const char *path, /** * Creates a socket and binds it to the given path, * then listens on the socket. The socket is - * set to be nonblocking. + * set to be nonblocking. + * + * @todo we'd like to be able to use the abstract namespace on linux + * (see "man 7 unix"). The question is whether to silently move all + * paths into that namespace if we can (I think that's best) or to + * require it to be specified explicitly in the dbus address. Also, + * need to sort out how to check for abstract namespace support. * * @param path the socket name * @param error return location for errors @@ -402,10 +422,27 @@ _dbus_listen_unix_socket (const char *path, return -1; } + /* FIXME discussed security implications of this with Nalin, + * and we couldn't think of where it would kick our ass, but + * it still seems a bit sucky. It also has non-security suckage; + * really we'd prefer to exit if the socket is already in use. + * But there doesn't seem to be a good way to do this. + * + * Just to be extra careful, I threw in the stat() - clearly + * the stat() can't *fix* any security issue, but it probably + * makes it harder to exploit. + */ + { + struct stat sb; + + if (stat (path, &sb) == 0 && + S_ISSOCK (sb.st_mode)) + unlink (path); + } + _DBUS_ZERO (addr); addr.sun_family = AF_UNIX; - strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH); - addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH-1] = '\0'; + strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0) { @@ -431,6 +468,13 @@ _dbus_listen_unix_socket (const char *path, close (listen_fd); return -1; } + + /* Try opening up the permissions, but if we can't, just go ahead + * and continue, maybe it will be good enough. + */ + if (chmod (path, 0777) < 0) + _dbus_warn ("Could not set mode 0777 on socket %s\n", + path); return listen_fd; } @@ -3063,4 +3107,101 @@ _dbus_print_backtrace (void) #endif } +/** + * Does the chdir, fork, setsid, etc. to become a daemon process. + * + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_become_daemon (DBusError *error) +{ + const char *s; + + /* This is so we don't prevent unmounting of devices. We divert + * all messages to syslog + */ + if (chdir ("/") < 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Could not chdir() to root directory"); + return FALSE; + } + + s = _dbus_getenv ("DBUS_DEBUG_OUTPUT"); + if (s == NULL || *s == '\0') + { + int dev_null_fd; + + /* silently ignore failures here, if someone + * doesn't have /dev/null we may as well try + * to continue anyhow + */ + + dev_null_fd = open ("/dev/null", O_RDWR); + if (dev_null_fd >= 0) + { + dup2 (dev_null_fd, 0); + dup2 (dev_null_fd, 1); + dup2 (dev_null_fd, 2); + } + } + + /* Get a predictable umask */ + umask (022); + + switch (fork ()) + { + case -1: + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to fork daemon: %s", _dbus_strerror (errno)); + return FALSE; + break; + + case 0: + break; + + default: + _exit (0); + break; + } + + if (setsid () == -1) + _dbus_assert_not_reached ("setsid() failed"); + + return TRUE; +} + +/** + * Changes the user and group the bus is running as. + * + * @param uid the new user ID + * @param gid the new group ID + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_change_identity (unsigned long uid, + unsigned long gid, + DBusError *error) +{ + 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; + } + + 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; + } + + return TRUE; +} + /** @} end of sysdeps */ -- cgit