1 /* SPDX-License-Identifier: LGPL-2.1+ */
13 #include "bus-common-errors.h"
14 #include "errno-util.h"
15 #include "in-addr-util.h"
18 #include "resolved-def.h"
19 #include "signal-util.h"
20 #include "string-util.h"
22 NSS_GETHOSTBYNAME_PROTOTYPES(resolve
);
23 NSS_GETHOSTBYADDR_PROTOTYPES(resolve
);
25 static bool bus_error_shall_fallback(sd_bus_error
*e
) {
26 return sd_bus_error_has_name(e
, SD_BUS_ERROR_SERVICE_UNKNOWN
) ||
27 sd_bus_error_has_name(e
, SD_BUS_ERROR_NAME_HAS_NO_OWNER
) ||
28 sd_bus_error_has_name(e
, SD_BUS_ERROR_NO_REPLY
) ||
29 sd_bus_error_has_name(e
, SD_BUS_ERROR_ACCESS_DENIED
);
32 static int count_addresses(sd_bus_message
*m
, int af
, const char **canonical
) {
38 r
= sd_bus_message_enter_container(m
, 'a', "(iiay)");
42 while ((r
= sd_bus_message_enter_container(m
, 'r', "iiay")) > 0) {
45 assert_cc(sizeof(int32_t) == sizeof(int));
47 r
= sd_bus_message_read(m
, "ii", &ifindex
, &family
);
51 r
= sd_bus_message_skip(m
, "ay");
55 r
= sd_bus_message_exit_container(m
);
59 if (af
!= AF_UNSPEC
&& family
!= af
)
67 r
= sd_bus_message_exit_container(m
);
71 r
= sd_bus_message_read(m
, "s", canonical
);
75 r
= sd_bus_message_rewind(m
, true);
82 static uint32_t ifindex_to_scopeid(int family
, const void *a
, int ifindex
) {
85 if (family
!= AF_INET6
)
88 /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
90 assert(sizeof(in6
) == FAMILY_ADDRESS_SIZE(AF_INET6
));
91 memcpy(&in6
, a
, sizeof(struct in6_addr
));
93 return IN6_IS_ADDR_LINKLOCAL(&in6
) ? ifindex
: 0;
96 static bool avoid_deadlock(void) {
98 /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
99 * code activating systemd-resolved.service. After all, we shouldn't synchronously do lookups to
100 * systemd-resolved if we are required to finish before it can be started. This of course won't detect all
101 * possible dead locks of this kind, but it should work for the most obvious cases. */
103 if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
106 return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-resolved.service") &&
107 streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
110 enum nss_status
_nss_resolve_gethostbyname4_r(
112 struct gaih_addrtuple
**pat
,
113 char *buffer
, size_t buflen
,
114 int *errnop
, int *h_errnop
,
117 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
118 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
119 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
120 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
121 const char *canonical
= NULL
;
127 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
135 if (avoid_deadlock()) {
140 r
= sd_bus_open_system(&bus
);
144 r
= sd_bus_message_new_method_call(
147 "org.freedesktop.resolve1",
148 "/org/freedesktop/resolve1",
149 "org.freedesktop.resolve1.Manager",
154 r
= sd_bus_message_set_auto_start(req
, false);
158 r
= sd_bus_message_append(req
, "isit", 0, name
, AF_UNSPEC
, (uint64_t) 0);
162 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
164 if (sd_bus_error_has_name(&error
, _BUS_ERROR_DNS
"NXDOMAIN") ||
165 !bus_error_shall_fallback(&error
))
168 /* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails,
169 allowing falling back to other nss modules. Treat all other error conditions as
170 NOTFOUND. This includes DNSSEC errors and suchlike. (We don't use UNAVAIL in this
171 case so that the nsswitch.conf configuration can distuingish such executed but
172 negative replies from complete failure to talk to resolved). */
176 c
= count_addresses(reply
, AF_UNSPEC
, &canonical
);
184 if (isempty(canonical
))
187 l
= strlen(canonical
);
188 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
192 *h_errnop
= NETDB_INTERNAL
;
193 return NSS_STATUS_TRYAGAIN
;
196 /* First, append name */
198 memcpy(r_name
, canonical
, l
+1);
201 /* Second, append addresses */
202 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
204 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
208 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
213 assert_cc(sizeof(int32_t) == sizeof(int));
215 r
= sd_bus_message_read(reply
, "ii", &ifindex
, &family
);
224 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
228 r
= sd_bus_message_exit_container(reply
);
232 if (!IN_SET(family
, AF_INET
, AF_INET6
))
235 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
240 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
241 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
242 r_tuple
->name
= r_name
;
243 r_tuple
->family
= family
;
244 r_tuple
->scopeid
= ifindex_to_scopeid(family
, a
, ifindex
);
245 memcpy(r_tuple
->addr
, a
, sz
);
247 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
257 **pat
= *r_tuple_first
;
259 *pat
= r_tuple_first
;
264 /* Explicitly reset both *h_errnop and h_errno to work around
265 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
266 *h_errnop
= NETDB_SUCCESS
;
269 return NSS_STATUS_SUCCESS
;
274 *h_errnop
= NO_RECOVERY
;
275 return NSS_STATUS_UNAVAIL
;
278 *h_errnop
= HOST_NOT_FOUND
;
279 return NSS_STATUS_NOTFOUND
;
282 enum nss_status
_nss_resolve_gethostbyname3_r(
285 struct hostent
*result
,
286 char *buffer
, size_t buflen
,
287 int *errnop
, int *h_errnop
,
291 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
292 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
293 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
294 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
295 size_t l
, idx
, ms
, alen
;
296 const char *canonical
;
300 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
311 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
316 if (avoid_deadlock()) {
321 r
= sd_bus_open_system(&bus
);
325 r
= sd_bus_message_new_method_call(
328 "org.freedesktop.resolve1",
329 "/org/freedesktop/resolve1",
330 "org.freedesktop.resolve1.Manager",
335 r
= sd_bus_message_set_auto_start(req
, false);
339 r
= sd_bus_message_append(req
, "isit", 0, name
, af
, (uint64_t) 0);
343 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
345 if (sd_bus_error_has_name(&error
, _BUS_ERROR_DNS
"NXDOMAIN") ||
346 !bus_error_shall_fallback(&error
))
352 c
= count_addresses(reply
, af
, &canonical
);
360 if (isempty(canonical
))
363 alen
= FAMILY_ADDRESS_SIZE(af
);
364 l
= strlen(canonical
);
366 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
371 *h_errnop
= NETDB_INTERNAL
;
372 return NSS_STATUS_TRYAGAIN
;
375 /* First, append name */
377 memcpy(r_name
, canonical
, l
+1);
380 /* Second, create empty aliases array */
381 r_aliases
= buffer
+ idx
;
382 ((char**) r_aliases
)[0] = NULL
;
383 idx
+= sizeof(char*);
385 /* Third, append addresses */
386 r_addr
= buffer
+ idx
;
388 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
392 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
397 r
= sd_bus_message_read(reply
, "ii", &ifindex
, &family
);
406 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
410 r
= sd_bus_message_exit_container(reply
);
422 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
429 idx
+= c
* ALIGN(alen
);
431 /* Fourth, append address pointer array */
432 r_addr_list
= buffer
+ idx
;
433 for (i
= 0; i
< c
; i
++)
434 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
436 ((char**) r_addr_list
)[i
] = NULL
;
437 idx
+= (c
+1) * sizeof(char*);
441 result
->h_name
= r_name
;
442 result
->h_aliases
= (char**) r_aliases
;
443 result
->h_addrtype
= af
;
444 result
->h_length
= alen
;
445 result
->h_addr_list
= (char**) r_addr_list
;
453 /* Explicitly reset both *h_errnop and h_errno to work around
454 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
455 *h_errnop
= NETDB_SUCCESS
;
458 return NSS_STATUS_SUCCESS
;
463 *h_errnop
= NO_RECOVERY
;
464 return NSS_STATUS_UNAVAIL
;
467 *h_errnop
= HOST_NOT_FOUND
;
468 return NSS_STATUS_NOTFOUND
;
471 enum nss_status
_nss_resolve_gethostbyaddr2_r(
472 const void* addr
, socklen_t len
,
474 struct hostent
*result
,
475 char *buffer
, size_t buflen
,
476 int *errnop
, int *h_errnop
,
479 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
480 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
481 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
482 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
483 unsigned c
= 0, i
= 0;
489 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
497 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
499 *errnop
= EAFNOSUPPORT
;
501 return NSS_STATUS_UNAVAIL
;
504 if (len
!= FAMILY_ADDRESS_SIZE(af
)) {
509 if (avoid_deadlock()) {
514 r
= sd_bus_open_system(&bus
);
518 r
= sd_bus_message_new_method_call(
521 "org.freedesktop.resolve1",
522 "/org/freedesktop/resolve1",
523 "org.freedesktop.resolve1.Manager",
528 r
= sd_bus_message_set_auto_start(req
, false);
532 r
= sd_bus_message_append(req
, "ii", 0, af
);
536 r
= sd_bus_message_append_array(req
, 'y', addr
, len
);
540 r
= sd_bus_message_append(req
, "t", (uint64_t) 0);
544 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
546 if (sd_bus_error_has_name(&error
, _BUS_ERROR_DNS
"NXDOMAIN") ||
547 !bus_error_shall_fallback(&error
))
553 r
= sd_bus_message_enter_container(reply
, 'a', "(is)");
557 while ((r
= sd_bus_message_read(reply
, "(is)", &ifindex
, &n
)) > 0) {
565 ms
+= ALIGN(strlen(n
) + 1);
570 r
= sd_bus_message_rewind(reply
, false);
577 ms
+= ALIGN(len
) + /* the address */
578 2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
579 c
* sizeof(char*); /* pointers to aliases, plus trailing NULL */
584 *h_errnop
= NETDB_INTERNAL
;
585 return NSS_STATUS_TRYAGAIN
;
588 /* First, place address */
590 memcpy(r_addr
, addr
, len
);
593 /* Second, place address list */
594 r_addr_list
= buffer
+ idx
;
595 ((char**) r_addr_list
)[0] = r_addr
;
596 ((char**) r_addr_list
)[1] = NULL
;
597 idx
+= sizeof(char*) * 2;
599 /* Third, reserve space for the aliases array */
600 r_aliases
= buffer
+ idx
;
601 idx
+= sizeof(char*) * c
;
603 /* Fourth, place aliases */
605 r_name
= buffer
+ idx
;
606 while ((r
= sd_bus_message_read(reply
, "(is)", &ifindex
, &n
)) > 0) {
615 ((char**) r_aliases
)[i
-1] = p
;
623 ((char**) r_aliases
)[c
-1] = NULL
;
626 result
->h_name
= r_name
;
627 result
->h_aliases
= (char**) r_aliases
;
628 result
->h_addrtype
= af
;
629 result
->h_length
= len
;
630 result
->h_addr_list
= (char**) r_addr_list
;
635 /* Explicitly reset both *h_errnop and h_errno to work around
636 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
637 *h_errnop
= NETDB_SUCCESS
;
640 return NSS_STATUS_SUCCESS
;
645 *h_errnop
= NO_RECOVERY
;
646 return NSS_STATUS_UNAVAIL
;
649 *h_errnop
= HOST_NOT_FOUND
;
650 return NSS_STATUS_NOTFOUND
;
653 NSS_GETHOSTBYNAME_FALLBACKS(resolve
);
654 NSS_GETHOSTBYADDR_FALLBACKS(resolve
);