diff --git a/bus/dispatch.c b/bus/dispatch.c index c3019b1e..3f985261 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -5181,9 +5181,9 @@ bus_unix_fds_passing_test (const char *test_data_dir_cstr) DBUS_TYPE_INVALID)) _dbus_test_fatal ("Failed to attach fds."); - if (!_dbus_close_socket (one[0], &error)) + if (!_dbus_close_socket (&one[0], &error)) _dbus_test_fatal ("Failed to close pipe #1 "); - if (!_dbus_close_socket (two[0], &error)) + if (!_dbus_close_socket (&two[0], &error)) _dbus_test_fatal ("Failed to close pipe #2 "); if (!(dbus_connection_can_send_type(foo, DBUS_TYPE_UNIX_FD))) @@ -5250,9 +5250,9 @@ bus_unix_fds_passing_test (const char *test_data_dir_cstr) if (read(two[1].fd, &r, 1) != 1 || r != 'Z') _dbus_test_fatal ("Failed to read value from pipe."); - if (!_dbus_close_socket (one[1], &error)) + if (!_dbus_close_socket (&one[1], &error)) _dbus_test_fatal ("Failed to close pipe #1 "); - if (!_dbus_close_socket (two[1], &error)) + if (!_dbus_close_socket (&two[1], &error)) _dbus_test_fatal ("Failed to close pipe #2 "); _dbus_verbose ("Disconnecting foo\n"); diff --git a/bus/main.c b/bus/main.c index 5f756d5c..ddd9d952 100644 --- a/bus/main.c +++ b/bus/main.c @@ -387,11 +387,8 @@ close_reload_pipe (DBusWatch **watch) _dbus_watch_unref (*watch); *watch = NULL; - _dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL); - _dbus_socket_invalidate (&reload_pipe[RELOAD_READ_END]); - - _dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL); - _dbus_socket_invalidate (&reload_pipe[RELOAD_WRITE_END]); + _dbus_close_socket (&reload_pipe[RELOAD_READ_END], NULL); + _dbus_close_socket (&reload_pipe[RELOAD_WRITE_END], NULL); } #endif /* DBUS_UNIX */ diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index 01c80437..17b2e201 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -6,6 +6,7 @@ include(CheckTypeSize) include(CheckCSourceCompiles) include(CheckCSourceRuns) +check_include_files("winsock2.h;afunix.h" HAVE_AFUNIX_H) check_include_file(alloca.h HAVE_ALLOCA_H) check_include_file(byteswap.h HAVE_BYTESWAP_H) check_include_file(crt/externs.h HAVE_CRT_EXTERNS_H) diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index 75509524..b70f8390 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -94,6 +94,7 @@ #cmakedefine GLIB_VERSION_MAX_ALLOWED @GLIB_VERSION_MAX_ALLOWED@ // headers +#cmakedefine HAVE_AFUNIX_H 1 #cmakedefine HAVE_ALLOCA_H 1 #cmakedefine HAVE_BYTESWAP_H 1 #cmakedefine HAVE_CRT_EXTERNS_H 1 diff --git a/configure.ac b/configure.ac index d72d8f7c..0c5cdfea 100644 --- a/configure.ac +++ b/configure.ac @@ -430,6 +430,7 @@ sys/syscall.h sys/syslimits.h sys/time.h unistd.h +winsock2.h ws2tcpip.h ]) @@ -1052,6 +1053,13 @@ if test x$dbus_win = xyes ; then fi fi +AC_CHECK_HEADERS([afunix.h], [], [], + [AC_INCLUDES_DEFAULT[ + #ifdef HAVE_WINSOCK2_H + # include + #endif + ]]) + AC_SUBST([NETWORK_libs]) AC_ARG_WITH([valgrind], diff --git a/dbus/CMakeLists.txt b/dbus/CMakeLists.txt index 2f56e62c..4d92b79f 100644 --- a/dbus/CMakeLists.txt +++ b/dbus/CMakeLists.txt @@ -89,7 +89,6 @@ set(DBUS_LIB_HEADERS dbus-resources.h dbus-server-debug-pipe.h dbus-server-protected.h - dbus-server-unix.h dbus-sha.h dbus-timeout.h dbus-threads.h @@ -209,7 +208,6 @@ else(WIN32) dbus-userdb.c ) set(DBUS_SHARED_HEADERS ${DBUS_SHARED_HEADERS} - dbus-server-unix.h dbus-transport-unix.h dbus-sysdeps-unix.h dbus-userdb.h diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 3c2ea87c..4c6633f3 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -102,8 +102,7 @@ endif DBUS_LIB_arch_sources = \ dbus-uuidgen.c \ dbus-uuidgen.h \ - dbus-server-unix.c \ - dbus-server-unix.h + dbus-server-unix.c DBUS_SHARED_arch_sources = \ $(launchd_source) \ diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index ea0ffdd5..2c433677 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -334,18 +334,7 @@ _dbus_verbose_init (void) } } -/** @def DBUS_IS_DIR_SEPARATOR(c) - * macro for checking if character c is a patch separator - * - * @todo move to a header file so that others can use this too - */ -#ifdef DBUS_WIN -#define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/') -#else -#define DBUS_IS_DIR_SEPARATOR(c) (c == '/') -#endif - -/** +/** remove source root from file path the source root is determined by */ diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 1272e8c5..c7967d24 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -488,6 +488,19 @@ dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str, # define _DBUS_END_IGNORE_LEAKS do { } while (0) #endif +/** @def DBUS_IS_DIR_SEPARATOR(c) + * macro for checking if character c is a path separator + */ +#ifdef DBUS_WIN +#define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/') +#define DBUS_DIR_SEPARATOR '\\' +#define DBUS_DIR_SEPARATOR_S "\\" +#else +#define DBUS_IS_DIR_SEPARATOR(c) (c == '/') +#define DBUS_DIR_SEPARATOR '/' +#define DBUS_DIR_SEPARATOR_S "/" +#endif + DBUS_END_DECLS #endif /* DBUS_INTERNALS_H */ diff --git a/dbus/dbus-nonce.c b/dbus/dbus-nonce.c index ef5eb617..c6e0a086 100644 --- a/dbus/dbus-nonce.c +++ b/dbus/dbus-nonce.c @@ -194,8 +194,7 @@ _dbus_accept_with_noncefile (DBusSocket listen_fd, const DBusNonceFile *noncefil if (do_check_nonce(fd, &nonce, NULL) != TRUE) { _dbus_verbose ("nonce check failed. Closing socket.\n"); - _dbus_close_socket(fd, NULL); - _dbus_socket_invalidate (&fd); + _dbus_close_socket (&fd, NULL); goto out; } diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c index c396bc82..4f9f4ffb 100644 --- a/dbus/dbus-server-debug-pipe.c +++ b/dbus/dbus-server-debug-pipe.c @@ -260,8 +260,8 @@ _dbus_transport_debug_pipe_new (const char *server_name, NULL, &address); if (client_transport == NULL) { - _dbus_close_socket (client_fd, NULL); - _dbus_close_socket (server_fd, NULL); + _dbus_close_socket (&client_fd, NULL); + _dbus_close_socket (&server_fd, NULL); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&address); return NULL; @@ -276,7 +276,7 @@ _dbus_transport_debug_pipe_new (const char *server_name, if (server_transport == NULL) { _dbus_transport_unref (client_transport); - _dbus_close_socket (server_fd, NULL); + _dbus_close_socket (&server_fd, NULL); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h index 650963f1..d9254f47 100644 --- a/dbus/dbus-server-protected.h +++ b/dbus/dbus-server-protected.h @@ -126,6 +126,10 @@ typedef enum DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED /**< address is already used */ } DBusServerListenResult; +DBusServerListenResult _dbus_server_listen_unix_socket (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); + DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error); diff --git a/dbus/dbus-server-socket.c b/dbus/dbus-server-socket.c index bc5e3a9d..188d9789 100644 --- a/dbus/dbus-server-socket.c +++ b/dbus/dbus-server-socket.c @@ -103,7 +103,7 @@ handle_new_client_fd_and_unlock (DBusServer *server, transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL); if (transport == NULL) { - _dbus_close_socket (client_fd, NULL); + _dbus_close_socket (&client_fd, NULL); SERVER_UNLOCK (server); return FALSE; } @@ -242,10 +242,7 @@ socket_disconnect (DBusServer *server) } if (_dbus_socket_is_valid (socket_server->fds[i])) - { - _dbus_close_socket (socket_server->fds[i], NULL); - _dbus_socket_invalidate (&socket_server->fds[i]); - } + _dbus_close_socket (&socket_server->fds[i], NULL); } if (socket_server->socket_name != NULL) @@ -513,7 +510,7 @@ failed: if (listen_fds != NULL) { for (i = 0; i < nlisten_fds; i++) - _dbus_close_socket (listen_fds[i], NULL); + _dbus_close_socket (&listen_fds[i], NULL); dbus_free (listen_fds); } @@ -596,5 +593,298 @@ _dbus_server_socket_own_filename (DBusServer *server, socket_server->socket_name = filename; } +/** + * 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; + DBusSocket listen_fd; + DBusString address; + char *path_copy; + DBusString path_str; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + _dbus_string_init_const (&path_str, path); + if ((abstract && + !_dbus_string_append (&address, "unix:abstract=")) || + (!abstract && + !_dbus_string_append (&address, "unix:path=")) || + !_dbus_address_append_escaped (&address, &path_str)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_0; + } + + if (abstract) + { + path_copy = NULL; + } + else + { + path_copy = _dbus_strdup (path); + if (path_copy == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_0; + } + } + + listen_fd = _dbus_listen_unix_socket (path, abstract, error); + + if (!_dbus_socket_is_valid (listen_fd)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed_1; + } + + server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error); + if (server == NULL) + { + goto failed_2; + } + + if (path_copy != NULL) + _dbus_server_socket_own_filename(server, path_copy); + + _dbus_string_free (&address); + + return server; + + failed_2: + _dbus_close_socket (&listen_fd, NULL); + failed_1: + dbus_free (path_copy); + failed_0: + _dbus_string_free (&address); + + return NULL; +} + +/** + * Creates a new Unix domain socket server listening under the given directory. + * This function is used for "unix:dir/tmpdir" kind of addresses. + * + * @param dir the path to a directory. + * @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_dir (const char *dir, + dbus_bool_t use_abstract, + DBusError *error) +{ + DBusServer *server; + DBusString full_path; + DBusString filename; + + if (!_dbus_string_init (&full_path)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (!_dbus_string_init (&filename)) + { + _dbus_string_free (&full_path); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (!_dbus_string_append (&filename, "dbus-")) + { + _dbus_string_free (&full_path); + _dbus_string_free (&filename); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (!_dbus_generate_random_ascii (&filename, 10, error)) + { + _dbus_string_free (&full_path); + _dbus_string_free (&filename); + return NULL; + } + + if (!_dbus_string_append (&full_path, dir) || + !_dbus_concat_dir_and_file (&full_path, &filename)) + { + _dbus_string_free (&full_path); + _dbus_string_free (&filename); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + server = + _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), + use_abstract, + error); + + _dbus_string_free (&full_path); + _dbus_string_free (&filename); + + return server; +} + +/** + * Tries to interpret the address entry for UNIX socket + * addresses. + * + * Sets error if the result is not OK. + * + * @param entry an address entry + * @param server_p location to store a new DBusServer, or #NULL on failure. + * @param error location to store rationale for failure on bad address + * @returns the outcome + * + */ +DBusServerListenResult +_dbus_server_listen_unix_socket (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error) +{ + const char *method; + + *server_p = NULL; + + method = dbus_address_entry_get_method (entry); + + if (strcmp (method, "unix") == 0) + { + const char *path = dbus_address_entry_get_value (entry, "path"); + const char *dir = dbus_address_entry_get_value (entry, "dir"); + const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); + const char *abstract = dbus_address_entry_get_value (entry, "abstract"); + const char *runtime = dbus_address_entry_get_value (entry, "runtime"); + int mutually_exclusive_modes = 0; + + mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) + + (abstract != NULL) + (runtime != NULL) + (dir != NULL); + + if (mutually_exclusive_modes < 1) + { + _dbus_set_bad_address(error, "unix", + "path or tmpdir or abstract or runtime or dir", + NULL); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } + + if (mutually_exclusive_modes > 1) + { + _dbus_set_bad_address(error, NULL, NULL, + "cannot specify two of \"path\", \"tmpdir\", \"abstract\", \"runtime\" and \"dir\" at the same time"); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } + + if (runtime != NULL) + { + DBusString full_path; + DBusString filename; + const char *runtimedir; + + if (strcmp (runtime, "yes") != 0) + { + _dbus_set_bad_address(error, NULL, NULL, + "if given, the only value allowed for \"runtime\" is \"yes\""); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } + + runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR"); + + if (runtimedir == NULL) + { + dbus_set_error (error, + DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set"); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + _dbus_string_init_const (&filename, "bus"); + + if (!_dbus_string_init (&full_path)) + { + _DBUS_SET_OOM (error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + if (!_dbus_string_append (&full_path, runtimedir) || + !_dbus_concat_dir_and_file (&full_path, &filename)) + { + _dbus_string_free (&full_path); + _DBUS_SET_OOM (error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + /* We can safely use filesystem sockets in the runtime directory, + * and they are preferred because they can be bind-mounted between + * Linux containers. */ + *server_p = _dbus_server_new_for_domain_socket ( + _dbus_string_get_const_data (&full_path), + FALSE, error); + + _dbus_string_free (&full_path); + } + else if (tmpdir != NULL || dir != NULL) + { + dbus_bool_t use_abstract = FALSE; + + if (tmpdir != NULL) + { + dir = tmpdir; + +#ifdef __linux__ + /* Use abstract sockets for tmpdir if supported, so that it + * never needs to be cleaned up. Use dir instead if you want a + * path-based socket. */ + use_abstract = TRUE; +#endif + } + + *server_p = _dbus_server_new_for_dir (dir, use_abstract, error); + } + else + { + if (path) + *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); + else + *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); + } + + if (*server_p != NULL) + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_OK; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + } + else + { + /* If we don't handle the method, we return NULL with the + * error unset + */ + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_NOT_HANDLED; + } +} + /** @} */ diff --git a/dbus/dbus-server-socket.h b/dbus/dbus-server-socket.h index ee5bf45f..8324dbfb 100644 --- a/dbus/dbus-server-socket.h +++ b/dbus/dbus-server-socket.h @@ -43,6 +43,9 @@ DBusServer* _dbus_server_new_for_tcp_socket (const char *host, const char *family, DBusError *error, dbus_bool_t use_nonce); +DBusServer* _dbus_server_new_for_dir (const char *dir, + dbus_bool_t use_abstract, + DBusError *error); DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error); @@ -51,6 +54,9 @@ DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry, void _dbus_server_socket_own_filename (DBusServer *server, char *filename); +DBusServer* _dbus_server_new_for_domain_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); DBUS_END_DECLS #endif /* DBUS_SERVER_SOCKET_H */ diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index c7ace2bc..3a0a75cd 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -23,7 +23,6 @@ #include #include "dbus-internals.h" -#include "dbus-server-unix.h" #include "dbus-server-socket.h" #include "dbus-server-launchd.h" #include "dbus-transport-unix.h" @@ -60,164 +59,7 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry, *server_p = NULL; method = dbus_address_entry_get_method (entry); - - if (strcmp (method, "unix") == 0) - { - const char *path = dbus_address_entry_get_value (entry, "path"); - const char *dir = dbus_address_entry_get_value (entry, "dir"); - const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); - const char *abstract = dbus_address_entry_get_value (entry, "abstract"); - const char *runtime = dbus_address_entry_get_value (entry, "runtime"); - int mutually_exclusive_modes = 0; - - mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) + - (abstract != NULL) + (runtime != NULL) + (dir != NULL); - - if (mutually_exclusive_modes < 1) - { - _dbus_set_bad_address(error, "unix", - "path or tmpdir or abstract or runtime or dir", - NULL); - return DBUS_SERVER_LISTEN_BAD_ADDRESS; - } - - if (mutually_exclusive_modes > 1) - { - _dbus_set_bad_address(error, NULL, NULL, - "cannot specify two of \"path\", \"tmpdir\", \"abstract\", \"runtime\" and \"dir\" at the same time"); - return DBUS_SERVER_LISTEN_BAD_ADDRESS; - } - - if (runtime != NULL) - { - DBusString full_path; - DBusString filename; - const char *runtimedir; - - if (strcmp (runtime, "yes") != 0) - { - _dbus_set_bad_address(error, NULL, NULL, - "if given, the only value allowed for \"runtime\" is \"yes\""); - return DBUS_SERVER_LISTEN_BAD_ADDRESS; - } - - runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR"); - - if (runtimedir == NULL) - { - dbus_set_error (error, - DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set"); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - - _dbus_string_init_const (&filename, "bus"); - - if (!_dbus_string_init (&full_path)) - { - _DBUS_SET_OOM (error); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - - if (!_dbus_string_append (&full_path, runtimedir) || - !_dbus_concat_dir_and_file (&full_path, &filename)) - { - _dbus_string_free (&full_path); - _DBUS_SET_OOM (error); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - - /* We can safely use filesystem sockets in the runtime directory, - * and they are preferred because they can be bind-mounted between - * Linux containers. */ - *server_p = _dbus_server_new_for_domain_socket ( - _dbus_string_get_const_data (&full_path), - FALSE, error); - - _dbus_string_free (&full_path); - } - else if (tmpdir != NULL || dir != NULL) - { - DBusString full_path; - DBusString filename; - dbus_bool_t use_abstract = FALSE; - - if (tmpdir != NULL) - { - dir = tmpdir; - -#ifdef __linux__ - /* Use abstract sockets for tmpdir if supported, so that it - * never needs to be cleaned up. Use dir instead if you want a - * path-based socket. */ - use_abstract = TRUE; -#endif - } - - if (!_dbus_string_init (&full_path)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - - if (!_dbus_string_init (&filename)) - { - _dbus_string_free (&full_path); - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - - if (!_dbus_string_append (&filename, "dbus-")) - { - _dbus_string_free (&full_path); - _dbus_string_free (&filename); - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - - if (!_dbus_generate_random_ascii (&filename, 10, error)) - { - _dbus_string_free (&full_path); - _dbus_string_free (&filename); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - - if (!_dbus_string_append (&full_path, dir) || - !_dbus_concat_dir_and_file (&full_path, &filename)) - { - _dbus_string_free (&full_path); - _dbus_string_free (&filename); - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - - *server_p = - _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), - use_abstract, - error); - - _dbus_string_free (&full_path); - _dbus_string_free (&filename); - } - else - { - if (path) - *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); - else - *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); - } - - if (*server_p != NULL) - { - _DBUS_ASSERT_ERROR_IS_CLEAR(error); - return DBUS_SERVER_LISTEN_OK; - } - else - { - _DBUS_ASSERT_ERROR_IS_SET(error); - return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; - } - } - else if (strcmp (method, "systemd") == 0) + if (strcmp (method, "systemd") == 0) { int i, n; DBusSocket *fds; @@ -258,7 +100,7 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry, systemd_err: for (i = 0; i < n; i++) { - _dbus_close_socket (fds[i], NULL); + _dbus_close_socket (&fds[i], NULL); } dbus_free (fds); _dbus_string_free (&address); @@ -298,87 +140,4 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry, } } -/** - * 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; - DBusSocket listen_fd; - DBusString address; - char *path_copy; - DBusString path_str; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - if (!_dbus_string_init (&address)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return NULL; - } - - _dbus_string_init_const (&path_str, path); - if ((abstract && - !_dbus_string_append (&address, "unix:abstract=")) || - (!abstract && - !_dbus_string_append (&address, "unix:path=")) || - !_dbus_address_append_escaped (&address, &path_str)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - goto failed_0; - } - - if (abstract) - { - path_copy = NULL; - } - else - { - path_copy = _dbus_strdup (path); - if (path_copy == NULL) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - goto failed_0; - } - } - - listen_fd.fd = _dbus_listen_unix_socket (path, abstract, error); - - if (listen_fd.fd < 0) - { - _DBUS_ASSERT_ERROR_IS_SET (error); - goto failed_1; - } - - server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error); - if (server == NULL) - { - goto failed_2; - } - - if (path_copy != NULL) - _dbus_server_socket_own_filename(server, path_copy); - - _dbus_string_free (&address); - - return server; - - failed_2: - _dbus_close_socket (listen_fd, NULL); - failed_1: - dbus_free (path_copy); - failed_0: - _dbus_string_free (&address); - - return NULL; -} - /** @} */ diff --git a/dbus/dbus-server-unix.h b/dbus/dbus-server-unix.h deleted file mode 100644 index be33fa70..00000000 --- a/dbus/dbus-server-unix.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* dbus-server-unix.h Server implementation for Unix network protocols. - * - * Copyright (C) 2002 Red Hat Inc. - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#ifndef DBUS_SERVER_UNIX_H -#define DBUS_SERVER_UNIX_H - -#include -#include - -DBUS_BEGIN_DECLS - -DBusServer* _dbus_server_new_for_domain_socket (const char *path, - dbus_bool_t abstract, - DBusError *error); - -DBUS_END_DECLS - -#endif /* DBUS_SERVER_UNIX_H */ diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index cde3c986..b58c4e75 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -23,7 +23,6 @@ #include #include "dbus-server.h" -#include "dbus-server-unix.h" #include "dbus-server-socket.h" #include "dbus-string.h" #ifdef DBUS_ENABLE_EMBEDDED_TESTS @@ -527,6 +526,7 @@ static const struct { DBusError *error); } listen_funcs[] = { { _dbus_server_listen_socket } + , { _dbus_server_listen_unix_socket } , { _dbus_server_listen_platform_specific } #ifdef DBUS_ENABLE_EMBEDDED_TESTS , { _dbus_server_listen_debug_pipe } diff --git a/dbus/dbus-spawn-unix.c b/dbus/dbus-spawn-unix.c index f3577e70..fb5b4267 100644 --- a/dbus/dbus-spawn-unix.c +++ b/dbus/dbus-spawn-unix.c @@ -560,7 +560,7 @@ close_socket_to_babysitter (DBusBabysitter *sitter) if (sitter->socket_to_babysitter.fd >= 0) { - _dbus_close_socket (sitter->socket_to_babysitter, NULL); + _dbus_close_socket (&sitter->socket_to_babysitter, NULL); sitter->socket_to_babysitter.fd = -1; } } diff --git a/dbus/dbus-spawn-win.c b/dbus/dbus-spawn-win.c index 61961901..c879688d 100644 --- a/dbus/dbus-spawn-win.c +++ b/dbus/dbus-spawn-win.c @@ -160,7 +160,7 @@ close_socket_to_babysitter (DBusBabysitter *sitter) if (sitter->socket_to_babysitter.sock != INVALID_SOCKET) { - _dbus_close_socket (sitter->socket_to_babysitter, NULL); + _dbus_close_socket (&sitter->socket_to_babysitter, NULL); sitter->socket_to_babysitter.sock = INVALID_SOCKET; } } @@ -188,7 +188,7 @@ _dbus_babysitter_unref (DBusBabysitter *sitter) if (sitter->socket_to_main.sock != INVALID_SOCKET) { - _dbus_close_socket (sitter->socket_to_main, NULL); + _dbus_close_socket (&sitter->socket_to_main, NULL); sitter->socket_to_main.sock = INVALID_SOCKET; } diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 24a4a242..18bd1282 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -293,22 +293,34 @@ static dbus_bool_t _dbus_open_unix_socket (int *fd, DBusError *error) { - return _dbus_open_socket(fd, PF_UNIX, SOCK_STREAM, 0, error); + return _dbus_open_socket(fd, AF_UNIX, SOCK_STREAM, 0, error); } /** - * Closes a socket. Should not be used on non-socket - * file descriptors or handles. + * Closes a socket and invalidates it. Should not be used on non-socket file + * descriptors or handles. + * + * If an error is detected, this function returns #FALSE and sets the error, but + * the socket is still closed and invalidated. Callers can use the error in a + * diagnostic message, but should not retry closing the socket. * * @param fd the socket * @param error return location for an error * @returns #FALSE if error is set */ dbus_bool_t -_dbus_close_socket (DBusSocket fd, +_dbus_close_socket (DBusSocket *fd, DBusError *error) { - return _dbus_close (fd.fd, error); + dbus_bool_t rv; + + _dbus_assert (fd != NULL); + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + rv = _dbus_close (fd->fd, error); + _dbus_socket_invalidate (fd); + + return rv; } /** @@ -923,21 +935,6 @@ _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 @@ -952,14 +949,14 @@ _dbus_write_two (int fd, * @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 + * @returns a valid socket on success or an invalid socket on error */ -int +DBusSocket _dbus_connect_unix_socket (const char *path, dbus_bool_t abstract, DBusError *error) { - int fd; + DBusSocket fd = DBUS_SOCKET_INIT; size_t path_len; struct sockaddr_un addr; _DBUS_STATIC_ASSERT (sizeof (addr.sun_path) > _DBUS_MAX_SUN_PATH_LENGTH); @@ -970,10 +967,10 @@ _dbus_connect_unix_socket (const char *path, path, abstract); - if (!_dbus_open_unix_socket (&fd, error)) + if (!_dbus_open_unix_socket (&fd.fd, error)) { _DBUS_ASSERT_ERROR_IS_SET(error); - return -1; + return fd; } _DBUS_ASSERT_ERROR_IS_CLEAR(error); @@ -991,8 +988,8 @@ _dbus_connect_unix_socket (const char *path, { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Abstract socket name too long\n"); - _dbus_close (fd, NULL); - return -1; + _dbus_close_socket (&fd, NULL); + return fd; } strncpy (&addr.sun_path[1], path, sizeof (addr.sun_path) - 2); @@ -1000,8 +997,8 @@ _dbus_connect_unix_socket (const char *path, #else /* !__linux__ */ dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "Operating system does not support abstract socket namespace\n"); - _dbus_close (fd, NULL); - return -1; + _dbus_close_socket (&fd, NULL); + return fd; #endif /* !__linux__ */ } else @@ -1010,30 +1007,30 @@ _dbus_connect_unix_socket (const char *path, { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Socket name too long\n"); - _dbus_close (fd, NULL); - return -1; + _dbus_close_socket (&fd, NULL); + return fd; } strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1); } - if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) + if (connect (fd.fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to connect to socket %s: %s", path, _dbus_strerror (errno)); - _dbus_close (fd, NULL); - return -1; + _dbus_close_socket (&fd, NULL); + return fd; } - if (!_dbus_set_fd_nonblocking (fd, error)) + if (!_dbus_set_fd_nonblocking (fd.fd, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); - _dbus_close (fd, NULL); - return -1; + _dbus_close_socket (&fd, NULL); + return fd; } return fd; @@ -1049,13 +1046,14 @@ _dbus_connect_unix_socket (const char *path, * @param argv the argument list for the process to execute. * argv[0] typically is identical to the path of the executable * @param error return location for error code - * @returns connection file descriptor or -1 on error + * @returns a valid socket on success or an invalid socket on error */ -int +DBusSocket _dbus_connect_exec (const char *path, char *const argv[], DBusError *error) { + DBusSocket s = DBUS_SOCKET_INIT; int fds[2]; pid_t pid; int retval; @@ -1081,7 +1079,8 @@ _dbus_connect_exec (const char *path, _dbus_error_from_errno (errno), "Failed to create socket pair: %s", _dbus_strerror (errno)); - return -1; + _dbus_assert (!_dbus_socket_is_valid (s)); + return s; } if (!cloexec_done) @@ -1104,7 +1103,8 @@ _dbus_connect_exec (const char *path, path, _dbus_strerror (errno)); close (fds[0]); close (fds[1]); - return -1; + _dbus_assert (!_dbus_socket_is_valid (s)); + return s; } if (pid == 0) @@ -1139,10 +1139,12 @@ _dbus_connect_exec (const char *path, _DBUS_ASSERT_ERROR_IS_SET (error); close (fds[0]); - return -1; + _dbus_assert (!_dbus_socket_is_valid (s)); + return s; } - return fds[0]; + s.fd = fds[0]; + return s; } /** @@ -1160,13 +1162,14 @@ _dbus_connect_exec (const char *path, * @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 + * @returns a valid socket on success or an invalid socket on error */ -int +DBusSocket _dbus_listen_unix_socket (const char *path, dbus_bool_t abstract, DBusError *error) { + DBusSocket s = DBUS_SOCKET_INIT; int listen_fd; struct sockaddr_un addr; size_t path_len; @@ -1180,7 +1183,7 @@ _dbus_listen_unix_socket (const char *path, if (!_dbus_open_unix_socket (&listen_fd, error)) { _DBUS_ASSERT_ERROR_IS_SET(error); - return -1; + return s; } _DBUS_ASSERT_ERROR_IS_CLEAR(error); @@ -1202,7 +1205,7 @@ _dbus_listen_unix_socket (const char *path, dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Abstract socket name too long\n"); _dbus_close (listen_fd, NULL); - return -1; + return s; } strncpy (&addr.sun_path[1], path, sizeof (addr.sun_path) - 2); @@ -1211,7 +1214,7 @@ _dbus_listen_unix_socket (const char *path, dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "Operating system does not support abstract socket namespace\n"); _dbus_close (listen_fd, NULL); - return -1; + return s; #endif /* !__linux__ */ } else @@ -1239,8 +1242,8 @@ _dbus_listen_unix_socket (const char *path, dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Socket name too long\n"); _dbus_close (listen_fd, NULL); - return -1; - } + return s; + } strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1); } @@ -1251,7 +1254,7 @@ _dbus_listen_unix_socket (const char *path, "Failed to bind socket \"%s\": %s", path, _dbus_strerror (errno)); _dbus_close (listen_fd, NULL); - return -1; + return s; } if (listen (listen_fd, SOMAXCONN /* backlog */) < 0) @@ -1260,14 +1263,14 @@ _dbus_listen_unix_socket (const char *path, "Failed to listen on socket \"%s\": %s", path, _dbus_strerror (errno)); _dbus_close (listen_fd, NULL); - return -1; + return s; } if (!_dbus_set_fd_nonblocking (listen_fd, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_close (listen_fd, NULL); - return -1; + return s; } /* Try opening up the permissions, but if we can't, just go ahead @@ -1276,7 +1279,8 @@ _dbus_listen_unix_socket (const char *path, if (!abstract && chmod (path, 0777) < 0) _dbus_warn ("Could not set mode 0777 on socket %s", path); - return listen_fd; + s.fd = listen_fd; + return s; } /** @@ -1491,7 +1495,6 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, _dbus_error_from_gai (res, errno), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host, port, gai_strerror(res), res); - _dbus_socket_invalidate (&fd); goto out; } @@ -1509,8 +1512,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, if (connect (fd.fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0) { saved_errno = errno; - _dbus_close (fd.fd, NULL); - _dbus_socket_invalidate (&fd); + _dbus_close_socket (&fd, NULL); connect_error = dbus_new0 (DBusError, 1); @@ -1557,16 +1559,14 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, if (!ret) { - _dbus_close (fd.fd, NULL); - _dbus_socket_invalidate (&fd); + _dbus_close_socket (&fd, NULL); goto out; } } if (!_dbus_set_fd_nonblocking (fd.fd, error)) { - _dbus_close (fd.fd, NULL); - _dbus_socket_invalidate (&fd); + _dbus_close_socket (&fd, NULL); goto out; } diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h index f0b4c728..06614ecc 100644 --- a/dbus/dbus-sysdeps-unix.h +++ b/dbus/dbus-sysdeps-unix.h @@ -66,17 +66,6 @@ _dbus_write_two (int fd, int start2, int len2); -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_exec (const char *path, - char *const argv[], - DBusError *error); - int _dbus_listen_systemd_sockets (DBusSocket **fd, DBusError *error); diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index 508057e2..e71f35d2 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -48,6 +48,9 @@ #include #include #include +#ifdef HAVE_AFUNIX_H +#include +#endif /* Declarations missing in mingw's and windows sdk 7.0 headers */ extern BOOL WINAPI ConvertStringSidToSidA (LPCSTR StringSid, PSID *Sid); @@ -483,20 +486,21 @@ _dbus_write_socket (DBusSocket fd, /** - * Closes a file descriptor. + * Closes a socket and invalidates it. * * @param fd the file descriptor * @param error error object * @returns #FALSE if error set */ dbus_bool_t -_dbus_close_socket (DBusSocket fd, - DBusError *error) +_dbus_close_socket (DBusSocket *fd, + DBusError *error) { + _dbus_assert (fd != NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (error); again: - if (closesocket (fd.sock) == SOCKET_ERROR) + if (closesocket (fd->sock) == SOCKET_ERROR) { DBUS_SOCKET_SET_ERRNO (); @@ -505,11 +509,13 @@ _dbus_close_socket (DBusSocket fd, dbus_set_error (error, _dbus_error_from_errno (errno), "Could not close socket: socket=%Iu, , %s", - fd.sock, _dbus_strerror_from_errno ()); + fd->sock, _dbus_strerror_from_errno ()); + _dbus_socket_invalidate (fd); return FALSE; } - _dbus_verbose ("socket=%Iu, \n", fd.sock); + _dbus_verbose ("socket=%Iu, \n", fd->sock); + _dbus_socket_invalidate (fd); return TRUE; } @@ -1642,7 +1648,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, _dbus_error_from_errno (saved_errno), "Failed to open socket: %s", _dbus_strerror (saved_errno)); - _dbus_socket_invalidate (&fd); + _dbus_assert (!_dbus_socket_is_valid (fd)); goto out; } _DBUS_ASSERT_ERROR_IS_CLEAR(error); @@ -1650,8 +1656,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, if (connect (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR) { saved_errno = _dbus_get_low_level_socket_errno (); - closesocket(fd.sock); - _dbus_socket_invalidate (&fd); + _dbus_close_socket (&fd, NULL); connect_error = dbus_new0 (DBusError, 1); @@ -1698,8 +1703,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, if (!ret) { - closesocket (fd.sock); - _dbus_socket_invalidate (&fd); + _dbus_close_socket (&fd, NULL); goto out; } } @@ -1709,8 +1713,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, if (!_dbus_set_socket_nonblocking (fd, error)) { - closesocket (fd.sock); - _dbus_socket_invalidate (&fd); + _dbus_close_socket (&fd, NULL); goto out; } @@ -1828,6 +1831,7 @@ _dbus_listen_tcp_socket (const char *host, _dbus_error_from_errno (saved_errno), "Failed to open socket: %s", _dbus_strerror (saved_errno)); + _dbus_assert (!_dbus_socket_is_valid (fd)); goto failed; } _DBUS_ASSERT_ERROR_IS_CLEAR(error); @@ -1848,7 +1852,7 @@ _dbus_listen_tcp_socket (const char *host, host ? host : "*", port, _dbus_strerror (saved_errno)); } - if (bind (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR) + if (bind (fd.sock, (struct sockaddr *) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR) { saved_errno = _dbus_get_low_level_socket_errno (); closesocket (fd.sock); @@ -2112,6 +2116,56 @@ again: return TRUE; } +#ifdef HAVE_AFUNIX_H +/* + * Returns false with no error set if the socket is non-AF_UNIX + * (contrary to our usual convention). + * + * Returns false with an error set on failure to identify it. + */ +static dbus_bool_t +_dbus_socket_is_af_unix (DBusSocket s, + DBusError *error) +{ + struct sockaddr_un saddr; + int len; + + len = sizeof (saddr); + if (getsockname (s.sock, (struct sockaddr *)&saddr, &len) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to getsockname: %s", + _dbus_strerror_from_errno ()); + return FALSE; + } + + return saddr.sun_family == AF_UNIX; +} + +/** + * @brief return peer process id from Unix domain socket handle + * @param handle AF_UNIX socket descriptor + * @return process id or 0 in case the process id could not be fetched + */ +static dbus_pid_t +_dbus_get_peer_pid_from_uds_handle (int handle) +{ + DWORD pid, drc; + + if (WSAIoctl (handle, SIO_AF_UNIX_GETPEERPID, + NULL, 0U, + &pid, sizeof (pid), &drc, + NULL, NULL) == SOCKET_ERROR) + { + _dbus_verbose ("failed to get peer's pid\n"); + return 0; + } + + return pid; +} +#endif + /** * Reads a single byte which must be nul (an error occurs otherwise), * and reads unix credentials if available. Fills in pid/uid/gid with @@ -2137,6 +2191,9 @@ _dbus_read_credentials_socket (DBusSocket handle, { int bytes_read = 0; DBusString buf; +#ifdef HAVE_AFUNIX_H + dbus_bool_t uds = FALSE; +#endif char *sid = NULL; dbus_pid_t pid; @@ -2153,7 +2210,16 @@ _dbus_read_credentials_socket (DBusSocket handle, _dbus_string_free (&buf); } - pid = _dbus_get_peer_pid_from_tcp_handle (handle.sock); +#ifdef HAVE_AFUNIX_H + uds = _dbus_socket_is_af_unix (handle, error); + if (dbus_error_is_set (error)) + return FALSE; + + if (uds) + pid = _dbus_get_peer_pid_from_uds_handle (handle.sock); + else +#endif + pid = _dbus_get_peer_pid_from_tcp_handle (handle.sock); if (pid == 0) return TRUE; @@ -2524,8 +2590,7 @@ _dbus_generate_random_bytes (DBusString *str, } /** - * Gets the temporary files directory by inspecting the environment variables - * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned + * Gets the temporary files directory, using GetTempPath() * * @returns location of temp directory, or #NULL if no memory for locking */ @@ -4408,5 +4473,228 @@ _dbus_win_event_free (HANDLE handle, DBusError *error) return FALSE; } +#ifdef HAVE_AFUNIX_H +static dbus_bool_t +_dbus_open_socket (SOCKET *socket_p, + int domain, + int type, + int protocol, + DBusError *error) +{ + if (!_dbus_win_startup_winsock ()) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + *socket_p = socket (domain, type, protocol); + if (*socket_p == INVALID_SOCKET) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to open socket: %s", + _dbus_strerror_from_errno ()); + return FALSE; + } + + _dbus_win_handle_set_close_on_exec ((HANDLE) *socket_p); + return TRUE; +} + +/** + * Opens a UNIX domain socket (as in the socket() call). + * Does not bind the socket. + * + * This will set CLOEXEC for the socket returned + * + * @param return location for socket descriptor + * @param error return location for an error + * @returns #FALSE if error is set + */ +static dbus_bool_t +_dbus_open_unix_socket (SOCKET *socket, + DBusError *error) +{ + return _dbus_open_socket (socket, AF_UNIX, SOCK_STREAM, 0, error); +} +#endif /* HAVE_AFUNIX_H */ + +/** + * Creates a socket and connects it to the UNIX domain socket at the + * given path. The socket is returned, and is set up as + * nonblocking. + * + * Abstract socket usage always fails. + * + * This will set FD_CLOEXEC for the socket returned. + * + * @param path the path to UNIX domain socket + * @param abstract #TRUE to use abstract namespace + * @param error return location for error code + * @returns a valid socket on success or an invalid socket on error + */ +DBusSocket +_dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ + DBusSocket s = DBUS_SOCKET_INIT; + +#ifdef HAVE_AFUNIX_H + struct sockaddr_un addr; + size_t path_len; + + _DBUS_STATIC_ASSERT (sizeof (addr.sun_path) > _DBUS_MAX_SUN_PATH_LENGTH); + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("connecting to unix socket %s abstract=%d\n", + path, abstract); + + if (abstract) + { + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Failed to connect: UNIX abstract socket is not supported on this system"); + return s; + } + + path_len = strlen (path); + if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Failed to connect: socket name too long"); + return s; + } + + if (!_dbus_open_unix_socket (&s.sock, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return s; + } + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _DBUS_ZERO (addr); + addr.sun_family = AF_UNIX; + strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1); + + if (connect (s.sock, (struct sockaddr *) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to connect to socket %s: %s", + path, _dbus_strerror (errno)); + + _dbus_close_socket (&s, NULL); + return s; + } + + if (!_dbus_set_socket_nonblocking (s, error)) + _dbus_close_socket (&s, NULL); + +#else + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Failed to connect: UNIX socket is not supported with this build"); +#endif + + return s; +} + +/** + * Creates a socket and binds it to the given path, + * then listens on the socket. The socket is + * set to be nonblocking. + * + * Abstract socket usage always fails. + * + * This will set CLOEXEC for the socket returned + * + * @param path the socket name + * @param abstract #TRUE to use abstract namespace + * @param error return location for errors + * @returns a valid socket on success or an invalid socket on error + */ +DBusSocket +_dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ + DBusSocket s = DBUS_SOCKET_INIT; + +#ifdef HAVE_AFUNIX_H + struct sockaddr_un addr; + size_t path_len; + _DBUS_STATIC_ASSERT (sizeof (addr.sun_path) > _DBUS_MAX_SUN_PATH_LENGTH); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("listening on unix socket %s abstract=%d\n", + path, abstract); + + if (abstract) + { + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Failed to listen: UNIX abstract socket is not supported on this system"); + return s; + } + + if (!_dbus_open_unix_socket (&s.sock, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return s; + } + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _DBUS_ZERO (addr); + addr.sun_family = AF_UNIX; + path_len = strlen (path); + + /* see related comment in dbus-sysdeps-unix.c */ + /* there is no S_ISSOCK on windows yet, so just unlink the path */ + unlink (path); + + if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Failed to listen: socket name too long"); + _dbus_close_socket (&s, NULL); + return s; + } + + strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1); + + if (bind (s.sock, (struct sockaddr *) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to bind socket \"%s\": %s", + path, _dbus_strerror (errno)); + _dbus_close_socket (&s, NULL); + return s; + } + + if (listen (s.sock, SOMAXCONN /* backlog */) < 0) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to listen on socket \"%s\": %s", + path, _dbus_strerror (errno)); + _dbus_close_socket (&s, NULL); + return s; + } + + if (!_dbus_set_socket_nonblocking (s, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_close_socket (&s, NULL); + return s; + } +#else + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Failed to listen: UNIX socket is not supported with this build"); +#endif + + return s; +} + /** @} end of sysdeps-win */ /* tests in dbus-sysdeps-util.c */ diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 0e51b32c..5270a5de 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -212,7 +212,7 @@ dbus_bool_t _dbus_set_socket_nonblocking (DBusSocket fd, DBusError *error); DBUS_PRIVATE_EXPORT -dbus_bool_t _dbus_close_socket (DBusSocket fd, +dbus_bool_t _dbus_close_socket (DBusSocket *fd, DBusError *error); DBUS_PRIVATE_EXPORT int _dbus_read_socket (DBusSocket fd, @@ -561,6 +561,18 @@ typedef struct dbus_bool_t _dbus_stat (const DBusString *filename, DBusStat *statbuf, DBusError *error); + +DBusSocket _dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); +DBusSocket _dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); + +DBusSocket _dbus_connect_exec (const char *path, + char *const argv[], + DBusError *error); + DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_socketpair (DBusSocket *fd1, DBusSocket *fd2, @@ -718,6 +730,20 @@ void _dbus_combine_tcp_errors (DBusList **sources, const char *port, DBusError *dest); +/** + * @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. + */ +#define _DBUS_MAX_SUN_PATH_LENGTH 99 + /** @} */ DBUS_END_DECLS diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c index fa1307bd..9f9d9539 100644 --- a/dbus/dbus-transport-socket.c +++ b/dbus/dbus-transport-socket.c @@ -22,6 +22,9 @@ */ #include + +#include + #include "dbus-internals.h" #include "dbus-connection-internal.h" #include "dbus-nonce.h" @@ -1042,8 +1045,7 @@ socket_disconnect (DBusTransport *transport) free_watches (transport); - _dbus_close_socket (socket_transport->fd, NULL); - _dbus_socket_invalidate (&socket_transport->fd); + _dbus_close_socket (&socket_transport->fd, NULL); } static dbus_bool_t @@ -1430,8 +1432,7 @@ _dbus_transport_new_for_tcp_socket (const char *host, if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - _dbus_close_socket (fd, NULL); - _dbus_socket_invalidate (&fd); + _dbus_close_socket (&fd, NULL); } return transport; @@ -1502,4 +1503,141 @@ _dbus_transport_open_socket(DBusAddressEntry *entry, } } +/** + * 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) +{ + DBusSocket fd = DBUS_SOCKET_INIT; + DBusTransport *transport; + DBusString address; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + 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, abstract, error); + if (!_dbus_socket_is_valid (fd)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed_0; + } + + _dbus_verbose ("Successfully connected to unix socket %s\n", + path); + + transport = _dbus_transport_new_for_socket (fd, NULL, &address); + if (transport == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_1; + } + + _dbus_string_free (&address); + + return transport; + + failed_1: + _dbus_close_socket (&fd, NULL); + failed_0: + _dbus_string_free (&address); + return NULL; +} + +/** + * Opens a UNIX socket transport. + * + * @param entry the address entry to try opening as a unix transport. + * @param transport_p return location for the opened transport + * @param error error to be set + * @returns result of the attempt + */ +DBusTransportOpenResult +_dbus_transport_open_unix_socket (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error) +{ + const char *method; + + method = dbus_address_entry_get_method (entry); + _dbus_assert (method != NULL); + + if (strcmp (method, "unix") == 0) + { + const char *path = dbus_address_entry_get_value (entry, "path"); + const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); + const char *abstract = dbus_address_entry_get_value (entry, "abstract"); + + if (tmpdir != NULL) + { + _dbus_set_bad_address (error, NULL, NULL, + "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on"); + return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; + } + + if (path == NULL && abstract == NULL) + { + _dbus_set_bad_address (error, "unix", + "path or abstract", + NULL); + return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; + } + + if (path != NULL && abstract != NULL) + { + _dbus_set_bad_address (error, NULL, NULL, + "can't specify both \"path\" and \"abstract\" options in an address"); + return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; + } + + if (path) + *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE, + error); + else + *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE, + error); + if (*transport_p == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_OK; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_NOT_HANDLED; + } +} + /** @} */ diff --git a/dbus/dbus-transport-socket.h b/dbus/dbus-transport-socket.h index 24e4b6a2..7c8efd2a 100644 --- a/dbus/dbus-transport-socket.h +++ b/dbus/dbus-transport-socket.h @@ -39,7 +39,13 @@ DBusTransportOpenResult _dbus_transport_open_socket (DBusAddressEntry *e DBusTransport **transport_p, DBusError *error); +DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); +DBusTransportOpenResult _dbus_transport_open_unix_socket (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error); DBUS_END_DECLS diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index 30c3ba44..f2e7228d 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -42,73 +42,6 @@ * @{ */ -/** - * 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) -{ - DBusSocket fd = DBUS_SOCKET_INIT; - DBusTransport *transport; - DBusString address; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - if (!_dbus_string_init (&address)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return NULL; - } - - 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.fd = _dbus_connect_unix_socket (path, abstract, error); - if (fd.fd < 0) - { - _DBUS_ASSERT_ERROR_IS_SET (error); - goto failed_0; - } - - _dbus_verbose ("Successfully connected to unix socket %s\n", - path); - - transport = _dbus_transport_new_for_socket (fd, NULL, &address); - if (transport == NULL) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - goto failed_1; - } - - _dbus_string_free (&address); - - return transport; - - failed_1: - _dbus_close_socket (fd, NULL); - failed_0: - _dbus_string_free (&address); - return NULL; -} - /** * Creates a new transport for the given binary and arguments. This * creates a client-side of a transport. The process will be forked @@ -180,8 +113,8 @@ _dbus_transport_new_for_exec (const char *path, } } - fd.fd = _dbus_connect_exec (path, argv, error); - if (fd.fd < 0) + fd = _dbus_connect_exec (path, argv, error); + if (!_dbus_socket_is_valid (fd)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed; @@ -202,77 +135,25 @@ _dbus_transport_new_for_exec (const char *path, return transport; failed: - if (fd.fd >= 0) - _dbus_close_socket (fd, NULL); + if (_dbus_socket_is_valid (fd)) + _dbus_close_socket (&fd, NULL); _dbus_string_free (&address); return NULL; } -/** - * Opens platform specific transport types. - * - * @param entry the address entry to try opening - * @param transport_p return location for the opened transport - * @param error error to be set - * @returns result of the attempt - */ + DBusTransportOpenResult -_dbus_transport_open_platform_specific (DBusAddressEntry *entry, - DBusTransport **transport_p, - DBusError *error) +_dbus_transport_open_unixexec (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error) { const char *method; - + method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); - if (strcmp (method, "unix") == 0) - { - const char *path = dbus_address_entry_get_value (entry, "path"); - const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); - const char *abstract = dbus_address_entry_get_value (entry, "abstract"); - - if (tmpdir != NULL) - { - _dbus_set_bad_address (error, NULL, NULL, - "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on"); - return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; - } - - if (path == NULL && abstract == NULL) - { - _dbus_set_bad_address (error, "unix", - "path or abstract", - NULL); - return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; - } - - if (path != NULL && abstract != NULL) - { - _dbus_set_bad_address (error, NULL, NULL, - "can't specify both \"path\" and \"abstract\" options in an address"); - return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; - } - - if (path) - *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE, - error); - else - *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE, - error); - if (*transport_p == NULL) - { - _DBUS_ASSERT_ERROR_IS_SET (error); - return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; - } - else - { - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - return DBUS_TRANSPORT_OPEN_OK; - } - } - else if (strcmp (method, "unixexec") == 0) + if (strcmp (method, "unixexec") == 0) { const char *path; unsigned i; @@ -346,8 +227,33 @@ _dbus_transport_open_platform_specific (DBusAddressEntry *entry, return DBUS_TRANSPORT_OPEN_OK; } } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_NOT_HANDLED; + } +} + +/** + * Opens platform specific transport types. + * + * @param entry the address entry to try opening + * @param transport_p return location for the opened transport + * @param error error to be set + * @returns result of the attempt + */ +DBusTransportOpenResult +_dbus_transport_open_platform_specific (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error) +{ #ifdef DBUS_ENABLE_LAUNCHD - else if (strcmp (method, "launchd") == 0) + const char *method; + + method = dbus_address_entry_get_method (entry); + _dbus_assert (method != NULL); + + if (strcmp (method, "launchd") == 0) { DBusError tmp_error = DBUS_ERROR_INIT; const char *launchd_env_var = dbus_address_entry_get_value (entry, "env"); @@ -398,8 +304,8 @@ _dbus_transport_open_platform_specific (DBusAddressEntry *entry, return DBUS_TRANSPORT_OPEN_OK; } } -#endif else +#endif /* DBUS_ENABLE_LAUNCHD */ { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; diff --git a/dbus/dbus-transport-unix.h b/dbus/dbus-transport-unix.h index 5124e0b6..7d3741a5 100644 --- a/dbus/dbus-transport-unix.h +++ b/dbus/dbus-transport-unix.h @@ -23,15 +23,13 @@ #ifndef DBUS_TRANSPORT_UNIX_H #define DBUS_TRANSPORT_UNIX_H -#include +#include DBUS_BEGIN_DECLS -DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, - dbus_bool_t abstract, - DBusError *error); - - +DBusTransportOpenResult _dbus_transport_open_unixexec (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error); DBUS_END_DECLS #endif /* DBUS_TRANSPORT_UNIX_H */ diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index 592abf9f..0a18db16 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -348,6 +348,10 @@ static const struct { DBusError *error); } open_funcs[] = { { _dbus_transport_open_socket }, + { _dbus_transport_open_unix_socket }, +#ifndef _WIN32 + { _dbus_transport_open_unixexec }, +#endif { _dbus_transport_open_platform_specific }, { _dbus_transport_open_autolaunch } #ifdef DBUS_ENABLE_EMBEDDED_TESTS diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index a43b9256..d256cffd 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -3655,18 +3655,14 @@ - When a socket is opened by the D-Bus library it truncates the path - name right before the first trailing Nul byte. This is true for both - normal paths and abstract paths. Note that this is a departure from - previous versions of D-Bus that would create sockets with a fixed - length path name. Names which were shorter than the fixed length - would be padded by Nul bytes. + When a Unix socket is opened by the D-Bus library, the socket address + length does not include the whole struct sockaddr_un, + but only the length of the pathname or abstract string (beside other + fields). - Unix domain sockets are not available on Windows. - On all other platforms, they are the recommended transport for - D-Bus, either used alone or in conjunction with - systemd or + They are the recommended transport for D-Bus, either used alone or in + conjunction with systemd or launchd addresses. @@ -3967,14 +3963,6 @@ information on situations where these transports have been used, and alternatives to these transports. - - Implementations of D-Bus on Windows operating systems normally - use a nonce-tcp transport via the local loopback interface. - This is because the - unix - transport, which would otherwise be recommended, is not - available on these operating systems. - On start, the server generates a random 16 byte nonce and writes it diff --git a/meson.build b/meson.build index 3e11cb00..8c45522f 100644 --- a/meson.build +++ b/meson.build @@ -607,6 +607,7 @@ foreach function : check_functions endforeach check_headers = [ + 'afunix.h', 'alloca.h', 'byteswap.h', 'crt_externs.h', diff --git a/test/corrupt.c b/test/corrupt.c index 758084a4..e5d15df4 100644 --- a/test/corrupt.c +++ b/test/corrupt.c @@ -86,9 +86,10 @@ setup (Fixture *f, dbus_error_init (&f->e); g_queue_init (&f->client_messages); - if ((g_str_has_prefix (addr, "tcp:") || - g_str_has_prefix (addr, "nonce-tcp:")) && - !test_check_tcp_works ()) + if ((g_str_has_prefix (addr, "unix:") && !test_check_af_unix_works ()) || + ((g_str_has_prefix (addr, "tcp:") || + g_str_has_prefix (addr, "nonce-tcp:")) && + !test_check_tcp_works ())) { f->skip = TRUE; return; @@ -406,26 +407,31 @@ main (int argc, char **argv) { int ret; +#ifdef DBUS_UNIX + char *tmp = _dbus_strdup ("/tmp"); +#else + char *tmp = dbus_address_escape_value (g_get_tmp_dir ()); +#endif + gchar *unix_tmpdir = g_strdup_printf ("unix:tmpdir=%s", tmp); test_init (&argc, &argv); g_test_add ("/corrupt/tcp", Fixture, "tcp:host=127.0.0.1", setup, test_corrupt, teardown); -#ifdef DBUS_UNIX - g_test_add ("/corrupt/unix", Fixture, "unix:tmpdir=/tmp", setup, + g_test_add ("/corrupt/unix", Fixture, unix_tmpdir, setup, test_corrupt, teardown); -#endif g_test_add ("/corrupt/byte-order/tcp", Fixture, "tcp:host=127.0.0.1", setup, test_byte_order, teardown); -#ifdef DBUS_UNIX - g_test_add ("/corrupt/byte-order/unix", Fixture, "unix:tmpdir=/tmp", setup, + g_test_add ("/corrupt/byte-order/unix", Fixture, unix_tmpdir, setup, test_byte_order, teardown); -#endif ret = g_test_run (); dbus_shutdown (); + + g_free (unix_tmpdir); + dbus_free (tmp); return ret; } diff --git a/test/internals/server-oom.c b/test/internals/server-oom.c index dc3127fa..d1688416 100644 --- a/test/internals/server-oom.c +++ b/test/internals/server-oom.c @@ -94,6 +94,10 @@ test_oom_wrapper (gconstpointer data) { const OOMTestCase *test = data; + if (g_str_has_prefix (test->data, "unix:") && + !test_check_af_unix_works ()) + return; + if ((g_str_has_prefix (test->data, "tcp:") || g_str_has_prefix (test->data, "nonce-tcp:")) && !test_check_tcp_works ()) @@ -131,6 +135,12 @@ main (int argc, char **argv) { int ret; +#ifdef DBUS_UNIX + char *tmp = _dbus_strdup ("/tmp"); +#else + char *tmp = dbus_address_escape_value (g_get_tmp_dir ()); +#endif + gchar *unix_tmpdir = g_strdup_printf ("unix:tmpdir=%s", tmp); test_init (&argc, &argv); @@ -139,13 +149,13 @@ main (int argc, add_oom_test ("/server/new-nonce-tcp", test_new_server, "nonce-tcp:host=127.0.0.1,bind=127.0.0.1"); add_oom_test ("/server/new-tcp-star", test_new_server, "tcp:host=127.0.0.1,bind=*"); add_oom_test ("/server/new-tcp-v4", test_new_server, "tcp:host=127.0.0.1,bind=127.0.0.1,family=ipv4"); -#ifdef DBUS_UNIX - add_oom_test ("/server/unix", test_new_server, "unix:tmpdir=/tmp"); -#endif + add_oom_test ("/server/unix", test_new_server, unix_tmpdir); ret = g_test_run (); g_queue_free_full (test_cases_to_free, g_free); dbus_shutdown (); + g_free (unix_tmpdir); + dbus_free (tmp); return ret; } diff --git a/test/loopback.c b/test/loopback.c index f89f5a95..8c4197e5 100644 --- a/test/loopback.c +++ b/test/loopback.c @@ -99,9 +99,10 @@ setup (Fixture *f, dbus_error_init (&f->e); g_queue_init (&f->server_messages); - if ((g_str_has_prefix (addr, "tcp:") || - g_str_has_prefix (addr, "nonce-tcp:")) && - !test_check_tcp_works ()) + if ((g_str_has_prefix (addr, "unix:") && !test_check_af_unix_works ()) || + ((g_str_has_prefix (addr, "tcp:") || + g_str_has_prefix (addr, "nonce-tcp:")) && + !test_check_tcp_works ())) { f->skip = TRUE; return; @@ -116,7 +117,6 @@ setup (Fixture *f, test_server_setup (f->ctx, f->server); } -#ifdef DBUS_UNIX static void setup_runtime (Fixture *f, gconstpointer addr) @@ -131,6 +131,7 @@ setup_runtime (Fixture *f, /* we're relying on being single-threaded for this to be safe */ f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR")); g_setenv ("XDG_RUNTIME_DIR", f->tmp_runtime_dir, TRUE); + g_test_message ("XDG_RUNTIME_DIR %s", f->tmp_runtime_dir); setup (f, addr); @@ -140,9 +141,12 @@ setup_runtime (Fixture *f, listening_at = dbus_server_get_address (f->server); g_test_message ("listening at %s", listening_at); g_assert (g_str_has_prefix (listening_at, "unix:path=")); +#ifndef DBUS_WIN + /* FIXME: on gitlab CI win32, it doesn't use runtime dir, why..? */ g_assert (strstr (listening_at, "dbus%3ddaemon%3dtest.") != NULL); - g_assert (strstr (listening_at, "/bus,") != NULL || - g_str_has_suffix (listening_at, "/bus")); + g_assert (strstr (listening_at, DBUS_DIR_SEPARATOR_S "bus,") != NULL || + g_str_has_suffix (listening_at, DBUS_DIR_SEPARATOR_S "bus")); +#endif dbus_free (listening_at); } @@ -166,11 +170,12 @@ setup_no_runtime (Fixture *f, g_test_message ("listening at %s", listening_at); /* we have fallen back to something in /tmp, either abstract or not */ g_assert (g_str_has_prefix (listening_at, "unix:")); - g_assert (strstr (listening_at, "=/tmp/") != NULL); +#ifdef DBUS_UNIX + g_assert (strstr (listening_at, "=/tmp" DBUS_DIR_SEPARATOR_S) != NULL); +#endif dbus_free (listening_at); } -#endif static void test_connect (Fixture *f, @@ -221,8 +226,7 @@ test_connect (Fixture *f, g_assert_cmpstr (dbus_address_entry_get_value (entries[0], "noncefile"), !=, NULL); } -#ifdef DBUS_UNIX - else if (g_strcmp0 (listening_address, "unix:tmpdir=/tmp") == 0) + else if (g_str_has_prefix (listening_address, "unix:tmpdir=")) { g_assert_cmpstr (dbus_address_entry_get_method (entries[0]), ==, "unix"); @@ -231,7 +235,7 @@ test_connect (Fixture *f, const char *abstract = dbus_address_entry_get_value (entries[0], "abstract"); - g_assert_true (g_str_has_prefix (abstract, "/tmp/dbus-")); + g_assert_true (g_str_has_prefix (abstract, "/tmp" DBUS_DIR_SEPARATOR_S "dbus-")); g_assert_cmpstr (dbus_address_entry_get_value (entries[0], "path"), ==, NULL); } @@ -241,26 +245,29 @@ test_connect (Fixture *f, "path"); g_assert_nonnull (path); - g_assert_true (g_str_has_prefix (path, "/tmp/dbus-")); +#ifdef DBUS_UNIX + g_assert_true (g_str_has_prefix (path, "/tmp" DBUS_DIR_SEPARATOR_S "dbus-")); +#endif } } - else if (g_strcmp0 (listening_address, "unix:dir=/tmp") == 0) + else if (g_str_has_prefix (listening_address, "unix:dir=")) { const char *path = dbus_address_entry_get_value (entries[0], "path"); g_assert_cmpstr (dbus_address_entry_get_method (entries[0]), ==, "unix"); g_assert_nonnull (path); - g_assert_true (g_str_has_prefix (path, "/tmp/dbus-")); +#ifdef DBUS_UNIX + g_assert_true (g_str_has_prefix (path, "/tmp" DBUS_DIR_SEPARATOR_S "dbus-")); +#endif } - else if (g_strcmp0 (listening_address, - "unix:runtime=yes;unix:tmpdir=/tmp") == 0) + else if (g_str_has_prefix (listening_address, + "unix:runtime=yes;unix:tmpdir=")) { g_assert_cmpstr (dbus_address_entry_get_method (entries[0]), ==, "unix"); /* No particular statement about the path here: for that see * setup_runtime() and setup_no_runtime() */ } -#endif else { g_assert_not_reached (); @@ -441,7 +448,6 @@ teardown (Fixture *f, test_main_context_unref (f->ctx); } -#ifdef DBUS_UNIX static void teardown_no_runtime (Fixture *f, gconstpointer addr) @@ -479,13 +485,20 @@ teardown_runtime (Fixture *f, g_free (f->saved_runtime_dir); g_free (f->tmp_runtime_dir); } -#endif int main (int argc, char **argv) { int ret; +#ifdef DBUS_UNIX + char *tmp = _dbus_strdup ("/tmp"); +#else + char *tmp = dbus_address_escape_value (g_get_tmp_dir ()); +#endif + gchar *unix_tmpdir = g_strdup_printf ("unix:tmpdir=%s", tmp); + gchar *unix_dir = g_strdup_printf ("unix:dir=%s", tmp); + gchar *unix_runtime_or_fallback = g_strdup_printf ("unix:runtime=yes;%s", unix_tmpdir); test_init (&argc, &argv); @@ -502,28 +515,31 @@ main (int argc, g_test_add ("/message/bad-guid/tcp", Fixture, "tcp:host=127.0.0.1", setup, test_bad_guid, teardown); -#ifdef DBUS_UNIX - g_test_add ("/connect/unix/tmpdir", Fixture, "unix:tmpdir=/tmp", setup, + g_test_add ("/connect/unix/tmpdir", Fixture, unix_tmpdir, setup, test_connect, teardown); - g_test_add ("/message/unix/tmpdir", Fixture, "unix:tmpdir=/tmp", setup, + g_test_add ("/message/unix/tmpdir", Fixture, unix_tmpdir, setup, test_message, teardown); - g_test_add ("/connect/unix/dir", Fixture, "unix:dir=/tmp", setup, + g_test_add ("/connect/unix/dir", Fixture, unix_dir, setup, test_connect, teardown); - g_test_add ("/message/unix/dir", Fixture, "unix:dir=/tmp", setup, + g_test_add ("/message/unix/dir", Fixture, unix_dir, setup, test_message, teardown); g_test_add ("/connect/unix/runtime", Fixture, - "unix:runtime=yes;unix:tmpdir=/tmp", setup_runtime, test_connect, + unix_runtime_or_fallback, setup_runtime, test_connect, teardown_runtime); g_test_add ("/connect/unix/no-runtime", Fixture, - "unix:runtime=yes;unix:tmpdir=/tmp", setup_no_runtime, test_connect, + unix_runtime_or_fallback, setup_no_runtime, test_connect, teardown_no_runtime); - g_test_add ("/message/bad-guid/unix", Fixture, "unix:tmpdir=/tmp", setup, + g_test_add ("/message/bad-guid/unix", Fixture, unix_tmpdir, setup, test_bad_guid, teardown); -#endif ret = g_test_run (); dbus_shutdown (); + + g_free (unix_tmpdir); + g_free (unix_dir); + g_free (unix_runtime_or_fallback); + dbus_free (tmp); return ret; } diff --git a/test/relay.c b/test/relay.c index 044260af..8bddec8c 100644 --- a/test/relay.c +++ b/test/relay.c @@ -129,9 +129,10 @@ setup (Fixture *f, dbus_error_init (&f->e); g_queue_init (&f->messages); - if ((g_str_has_prefix (address, "tcp:") || - g_str_has_prefix (address, "nonce-tcp:")) && - !test_check_tcp_works ()) + if ((g_str_has_prefix (address, "unix:") && !test_check_af_unix_works ()) || + ((g_str_has_prefix (address, "tcp:") || + g_str_has_prefix (address, "nonce-tcp:")) && + !test_check_tcp_works ())) { f->skip = TRUE; return; @@ -338,6 +339,12 @@ main (int argc, char **argv) { int ret; +#ifdef DBUS_UNIX + char *tmp = _dbus_strdup ("/tmp"); +#else + char *tmp = dbus_address_escape_value (g_get_tmp_dir ()); +#endif + gchar *unix_tmpdir = g_strdup_printf ("unix:tmpdir=%s", tmp); test_init (&argc, &argv); @@ -348,16 +355,16 @@ main (int argc, g_test_add ("/limit/tcp", Fixture, "tcp:host=127.0.0.1", setup, test_limit, teardown); -#ifdef DBUS_UNIX - g_test_add ("/connect/unix", Fixture, "unix:tmpdir=/tmp", setup, + g_test_add ("/connect/unix", Fixture, unix_tmpdir, setup, test_connect, teardown); - g_test_add ("/relay/unix", Fixture, "unix:tmpdir=/tmp", setup, + g_test_add ("/relay/unix", Fixture, unix_tmpdir, setup, test_relay, teardown); - g_test_add ("/limit/unix", Fixture, "unix:tmpdir=/tmp", setup, + g_test_add ("/limit/unix", Fixture, unix_tmpdir, setup, test_limit, teardown); -#endif ret = g_test_run (); dbus_shutdown (); + g_free (unix_tmpdir); + dbus_free (tmp); return ret; } diff --git a/test/test-utils-glib.c b/test/test-utils-glib.c index 2aafb03e..30b9836c 100644 --- a/test/test-utils-glib.c +++ b/test/test-utils-glib.c @@ -899,6 +899,25 @@ test_check_tcp_works (void) #endif } +gboolean +test_check_af_unix_works (void) +{ +#if defined(G_OS_WIN32) && !defined(HAVE_AFUNIX_H) + /* AFUNIX support is compiled out, skip system check */ + return FALSE; +#else +#ifdef G_OS_WIN32 + SOCKET fd = socket (AF_UNIX, SOCK_STREAM, 0); + closesocket (fd); + return fd != INVALID_SOCKET; +#else + int fd = socket (AF_UNIX, SOCK_STREAM, 0); + close (fd); + return fd >= 0; +#endif +#endif +} + /* * Store the result of an async operation. @user_data is a pointer to a * variable that can store @result, initialized to %NULL. diff --git a/test/test-utils-glib.h b/test/test-utils-glib.h index eda468b9..bfc36941 100644 --- a/test/test-utils-glib.h +++ b/test/test-utils-glib.h @@ -143,6 +143,7 @@ backported_g_steal_pointer (gpointer pointer_to_pointer) #endif gboolean test_check_tcp_works (void); +gboolean test_check_af_unix_works (void); void test_store_result_cb (GObject *source_object, GAsyncResult *result,