diff options
author | Simon McVittie <smcv@collabora.com> | 2018-06-04 16:27:46 +0100 |
---|---|---|
committer | Simon McVittie <smcv@collabora.com> | 2018-06-04 17:55:21 +0100 |
commit | 8ec0b5ae2d9bce65d8246204b90a9d2552f337e7 (patch) | |
tree | b4745421d94001540baba0bfa34182a992b5e228 | |
parent | 6c3e82af25e584acf769419be84c04ab7b944859 (diff) | |
download | dbus-8ec0b5ae2d9bce65d8246204b90a9d2552f337e7.tar.gz |
sysdeps-unix: Handle errors from getaddrinfo correctly
getaddrinfo and getnameinfo have their own error-handling convention
in which the library call returns either 0 or an EAI_* error code
unrelated to errno. If the error code is not EAI_SYSTEM, then
the value of errno is undefined (in particular it might be carried
over from a previous system call or library call). Introduce a
new helper function _dbus_error_from_gai() to handle this.
The equivalent code paths in Windows appear to be OK: the Windows
implementation of getaddrinfo() is documented to return a Winsock
error code, which we seem to be handling correctly.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Reviewed-by: Philip Withnall <withnall@endlessm.com>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=106395
(cherry picked from commit 60cedd0cfd775c9fcf7260e12af9b2ffeefc2bbe)
-rw-r--r-- | dbus/dbus-sysdeps-unix.c | 70 |
1 files changed, 65 insertions, 5 deletions
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index b0ba8991..222c8c84 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -1320,6 +1320,56 @@ _dbus_listen_systemd_sockets (DBusSocket **fds, #endif } +/* Convert an error code from getaddrinfo() or getnameinfo() into + * a D-Bus error name. */ +static const char * +_dbus_error_from_gai (int gai_res, + int saved_errno) +{ + switch (gai_res) + { +#ifdef EAI_FAMILY + case EAI_FAMILY: + /* ai_family not supported (at all) */ + return DBUS_ERROR_NOT_SUPPORTED; +#endif + +#ifdef EAI_SOCKTYPE + case EAI_SOCKTYPE: + /* ai_socktype not supported (at all) */ + return DBUS_ERROR_NOT_SUPPORTED; +#endif + +#ifdef EAI_MEMORY + case EAI_MEMORY: + /* Out of memory */ + return DBUS_ERROR_NO_MEMORY; +#endif + +#ifdef EAI_SYSTEM + case EAI_SYSTEM: + /* Unspecified system error, details in errno */ + return _dbus_error_from_errno (saved_errno); +#endif + + case 0: + /* It succeeded, but we didn't get any addresses? */ + return DBUS_ERROR_FAILED; + + /* EAI_AGAIN: Transient failure */ + /* EAI_BADFLAGS: invalid ai_flags (programming error) */ + /* EAI_FAIL: Non-recoverable failure */ + /* EAI_NODATA: host exists but has no addresses */ + /* EAI_NONAME: host does not exist */ + /* EAI_OVERFLOW: argument buffer overflow */ + /* EAI_SERVICE: service not available for specified socket + * type (we should never see this because we use numeric + * ports) */ + default: + return DBUS_ERROR_FAILED; + } +} + /** * Creates a socket and connects to a socket at the given host * and port. The connection fd is returned, and is set up as @@ -1379,7 +1429,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, if ((res = getaddrinfo(host, port, &hints, &ai)) != 0) { dbus_set_error (error, - _dbus_error_from_errno (errno), + _dbus_error_from_gai (res, errno), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host, port, gai_strerror(res), res); return _dbus_socket_get_invalid (); @@ -1501,7 +1551,7 @@ _dbus_listen_tcp_socket (const char *host, if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai) { dbus_set_error (error, - _dbus_error_from_errno (errno), + _dbus_error_from_gai (res, errno), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host ? host : "*", port, gai_strerror(res), res); goto failed; @@ -1601,16 +1651,26 @@ _dbus_listen_tcp_socket (const char *host, addrlen = sizeof(addr); result = getsockname(fd, (struct sockaddr*) &addr, &addrlen); - if (result == -1 || - (res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0, + if (result == -1) + { + saved_errno = errno; + dbus_set_error (error, _dbus_error_from_errno (saved_errno), + "Failed to retrieve socket name for \"%s:%s\": %s", + host ? host : "*", port, _dbus_strerror (saved_errno)); + goto failed; + } + + if ((res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0, portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { - dbus_set_error (error, _dbus_error_from_errno (errno), + saved_errno = errno; + dbus_set_error (error, _dbus_error_from_gai (res, saved_errno), "Failed to resolve port \"%s:%s\": %s (%d)", host ? host : "*", port, gai_strerror(res), res); goto failed; } + if (!_dbus_string_append(retport, portbuf)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); |