diff options
Diffstat (limited to 'dbus')
-rw-r--r-- | dbus/dbus-server-unix.c | 9 | ||||
-rw-r--r-- | dbus/dbus-server-unix.h | 1 | ||||
-rw-r--r-- | dbus/dbus-server.c | 32 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.c | 91 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.h | 2 | ||||
-rw-r--r-- | dbus/dbus-transport-unix.c | 14 | ||||
-rw-r--r-- | dbus/dbus-transport-unix.h | 1 | ||||
-rw-r--r-- | dbus/dbus-transport.c | 20 |
8 files changed, 126 insertions, 44 deletions
diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index fe4dbaa4..036446af 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -268,11 +268,13 @@ _dbus_server_new_for_fd (int fd, * Creates a new server listening on the given Unix domain socket. * * @param path the path for the domain socket. + * @param abstract #TRUE to use abstract socket namespace * @param error location to store reason for failure. * @returns the new server, or #NULL on failure. */ DBusServer* _dbus_server_new_for_domain_socket (const char *path, + dbus_bool_t abstract, DBusError *error) { DBusServer *server; @@ -289,7 +291,10 @@ _dbus_server_new_for_domain_socket (const char *path, return NULL; } - if (!_dbus_string_append (&address, "unix:path=") || + if ((abstract && + !_dbus_string_append (&address, "unix:abstract=")) || + (!abstract && + !_dbus_string_append (&address, "unix:path=")) || !_dbus_string_append (&address, path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); @@ -303,7 +308,7 @@ _dbus_server_new_for_domain_socket (const char *path, goto failed_0; } - listen_fd = _dbus_listen_unix_socket (path, error); + listen_fd = _dbus_listen_unix_socket (path, abstract, error); _dbus_fd_set_close_on_exec (listen_fd); if (listen_fd < 0) diff --git a/dbus/dbus-server-unix.h b/dbus/dbus-server-unix.h index 1d038db0..95f0b756 100644 --- a/dbus/dbus-server-unix.h +++ b/dbus/dbus-server-unix.h @@ -31,6 +31,7 @@ DBUS_BEGIN_DECLS; DBusServer* _dbus_server_new_for_fd (int fd, const DBusString *address); DBusServer* _dbus_server_new_for_domain_socket (const char *path, + dbus_bool_t abstract, DBusError *error); DBusServer* _dbus_server_new_for_tcp_socket (const char *host, dbus_uint32_t port, diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index e62c0284..4007d7a5 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -295,17 +295,20 @@ dbus_server_listen (const char *address, { const char *path = dbus_address_entry_get_value (entries[i], "path"); const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir"); + const char *abstract = dbus_address_entry_get_value (entries[i], "abstract"); - if (path == NULL && tmpdir == NULL) + if (path == NULL && tmpdir == NULL && abstract == NULL) { address_problem_type = "unix"; - address_problem_field = "path or tmpdir"; + address_problem_field = "path or tmpdir or abstract"; goto bad_address; } - if (path && tmpdir) + if ((path && tmpdir) || + (path && abstract) || + (tmpdir && abstract)) { - address_problem_other = "cannot specify both \"path\" and \"tmpdir\" at the same time"; + address_problem_other = "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"; goto bad_address; } @@ -339,14 +342,22 @@ dbus_server_listen (const char *address, goto out; } - /* FIXME - we will unconditionally unlink() the path. - * unlink() does not follow symlinks, but would like - * independent confirmation this is safe enough. See - * also _dbus_listen_unix_socket() and comments therein. + /* FIXME - we will unconditionally unlink() the path if + * we don't support abstract namespace. unlink() does + * not follow symlinks, but would like independent + * confirmation this is safe enough. See also + * _dbus_listen_unix_socket() and comments therein. */ + + /* Always use abstract namespace if possible with tmpdir */ server = _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), +#ifdef HAVE_ABSTRACT_SOCKETS + TRUE, +#else + FALSE, +#endif error); _dbus_string_free (&full_path); @@ -354,7 +365,10 @@ dbus_server_listen (const char *address, } else { - server = _dbus_server_new_for_domain_socket (path, error); + if (path) + server = _dbus_server_new_for_domain_socket (path, FALSE, error); + else + server = _dbus_server_new_for_domain_socket (abstract, TRUE, error); } } else if (strcmp (method, "tcp") == 0) diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index ab79a722..35900d70 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -373,13 +373,19 @@ _dbus_write_two (int fd, * 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 * nonblocking. + * + * Uses abstract sockets instead of filesystem-linked sockets if + * requested (it's possible only on Linux; see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails. * * @param path the path to UNIX domain socket + * @param abstract #TRUE to use abstract namespace * @param error return location for error code * @returns connection file descriptor or -1 on error */ int _dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, DBusError *error) { int fd; @@ -401,7 +407,23 @@ _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 - 1); + + if (abstract) + { +#ifdef HAVE_ABSTRACT_SOCKETS + addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ + strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2); +#else /* HAVE_ABSTRACT_SOCKETS */ + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Operating system does not support abstract socket namespace\n"); + close (fd); + return -1; +#endif /* ! HAVE_ABSTRACT_SOCKETS */ + } + else + { + strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); + } if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0) { @@ -434,18 +456,19 @@ _dbus_connect_unix_socket (const char *path, * then listens on the socket. The socket is * 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. + * Uses abstract sockets instead of filesystem-linked + * sockets if requested (it's possible only on Linux; + * see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails. * * @param path the socket name + * @param abstract #TRUE to use abstract namespace * @param error return location for errors * @returns the listening file descriptor or -1 on error */ int _dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, DBusError *error) { int listen_fd; @@ -463,27 +486,43 @@ _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 at least - * avoids inadvertent/accidental data loss. - */ - { - 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 - 1); + + if (abstract) + { +#ifdef HAVE_ABSTRACT_SOCKETS + addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ + strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2); +#else /* HAVE_ABSTRACT_SOCKETS */ + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Operating system does not support abstract socket namespace\n"); + close (listen_fd); + return -1; +#endif /* ! HAVE_ABSTRACT_SOCKETS */ + } + else + { + /* 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 at least + * avoids inadvertent/accidental data loss. + */ + { + struct stat sb; + + if (stat (path, &sb) == 0 && + S_ISSOCK (sb.st_mode)) + unlink (path); + } + + strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); + } if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0) { @@ -513,7 +552,7 @@ _dbus_listen_unix_socket (const char *path, /* 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) + if (!abstract && chmod (path, 0777) < 0) _dbus_warn ("Could not set mode 0777 on socket %s\n", path); diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 7a4696f3..cfe0cd25 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -105,8 +105,10 @@ typedef struct } DBusCredentials; int _dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, DBusError *error); int _dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, DBusError *error); int _dbus_connect_tcp_socket (const char *host, dbus_uint32_t port, diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index 5df1c461..e5e446c2 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -1080,12 +1080,17 @@ _dbus_transport_new_for_fd (int fd, * Creates a new transport for the given Unix domain socket * path. This creates a client-side of a transport. * + * @todo once we add a way to escape paths in a dbus + * address, this function needs to do escaping. + * * @param path the path to the domain socket. + * @param abstract #TRUE to use abstract socket namespace * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, + dbus_bool_t abstract, DBusError *error) { int fd; @@ -1101,15 +1106,18 @@ _dbus_transport_new_for_domain_socket (const char *path, } fd = -1; - - if (!_dbus_string_append (&address, "unix:path=") || + + if ((abstract && + !_dbus_string_append (&address, "unix:abstract=")) || + (!abstract && + !_dbus_string_append (&address, "unix:path=")) || !_dbus_string_append (&address, path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } - fd = _dbus_connect_unix_socket (path, error); + fd = _dbus_connect_unix_socket (path, abstract, error); if (fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); diff --git a/dbus/dbus-transport-unix.h b/dbus/dbus-transport-unix.h index ef7ac9b1..8d3f5b10 100644 --- a/dbus/dbus-transport-unix.h +++ b/dbus/dbus-transport-unix.h @@ -31,6 +31,7 @@ DBusTransport* _dbus_transport_new_for_fd (int fd, dbus_bool_t server, const DBusString *address); DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, + dbus_bool_t abstract, DBusError *error); DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host, dbus_int32_t port, diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index af1cb421..59ec6ea1 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -243,21 +243,33 @@ _dbus_transport_open (const char *address, { const char *path = dbus_address_entry_get_value (entries[i], "path"); const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir"); - + const char *abstract = dbus_address_entry_get_value (entries[i], "abstract"); + if (tmpdir != NULL) { address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on"; goto bad_address; } - if (path == NULL) + if (path == NULL && abstract == NULL) { address_problem_type = "unix"; - address_problem_field = "path"; + address_problem_field = "path or abstract"; goto bad_address; } - transport = _dbus_transport_new_for_domain_socket (path, &tmp_error); + if (path != NULL && abstract != NULL) + { + address_problem_other = "can't specify both \"path\" and \"abstract\" options in an address"; + goto bad_address; + } + + if (path) + transport = _dbus_transport_new_for_domain_socket (path, FALSE, + &tmp_error); + else + transport = _dbus_transport_new_for_domain_socket (abstract, TRUE, + &tmp_error); } else if (strcmp (method, "tcp") == 0) { |