summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2018-06-04 16:27:46 +0100
committerSimon McVittie <smcv@collabora.com>2018-06-04 17:55:21 +0100
commit8ec0b5ae2d9bce65d8246204b90a9d2552f337e7 (patch)
treeb4745421d94001540baba0bfa34182a992b5e228
parent6c3e82af25e584acf769419be84c04ab7b944859 (diff)
downloaddbus-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.c70
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);