1 /* SPDX-License-Identifier: LGPL-2.1+ */
12 #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
) ||
30 sd_bus_error_has_name(e
, SD_BUS_ERROR_DISCONNECTED
) ||
31 sd_bus_error_has_name(e
, SD_BUS_ERROR_TIMEOUT
);
34 static int count_addresses(sd_bus_message
*m
, int af
, const char **canonical
) {
40 r
= sd_bus_message_enter_container(m
, 'a', "(iiay)");
44 while ((r
= sd_bus_message_enter_container(m
, 'r', "iiay")) > 0) {
47 assert_cc(sizeof(int32_t) == sizeof(int));
49 r
= sd_bus_message_read(m
, "ii", &ifindex
, &family
);
53 r
= sd_bus_message_skip(m
, "ay");
57 r
= sd_bus_message_exit_container(m
);
61 if (af
!= AF_UNSPEC
&& family
!= af
)
69 r
= sd_bus_message_exit_container(m
);
73 r
= sd_bus_message_read(m
, "s", canonical
);
77 r
= sd_bus_message_rewind(m
, true);
84 static uint32_t ifindex_to_scopeid(int family
, const void *a
, int ifindex
) {
87 if (family
!= AF_INET6
)
90 /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
92 assert(sizeof(in6
) == FAMILY_ADDRESS_SIZE(AF_INET6
));
93 memcpy(&in6
, a
, sizeof(struct in6_addr
));
95 return IN6_IS_ADDR_LINKLOCAL(&in6
) ? ifindex
: 0;
98 static bool avoid_deadlock(void) {
100 /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
101 * code activating systemd-resolved.service. After all, we shouldn't synchronously do lookups to
102 * systemd-resolved if we are required to finish before it can be started. This of course won't detect all
103 * possible dead locks of this kind, but it should work for the most obvious cases. */
105 if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
108 return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-resolved.service") &&
109 streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
112 enum nss_status
_nss_resolve_gethostbyname4_r(
114 struct gaih_addrtuple
**pat
,
115 char *buffer
, size_t buflen
,
116 int *errnop
, int *h_errnop
,
119 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
120 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
121 struct gaih_addrtuple
*r_tuple
, *r_tuple_first
= NULL
;
122 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
123 const char *canonical
= NULL
;
129 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
137 if (avoid_deadlock()) {
142 r
= sd_bus_open_system(&bus
);
146 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveHostname");
150 r
= sd_bus_message_set_auto_start(req
, false);
154 r
= sd_bus_message_append(req
, "isit", 0, name
, AF_UNSPEC
, (uint64_t) 0);
158 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
160 if (!bus_error_shall_fallback(&error
))
163 /* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails,
164 allowing falling back to other nss modules. Treat all other error conditions as
165 NOTFOUND. This includes DNSSEC errors and suchlike. (We don't use UNAVAIL in this
166 case so that the nsswitch.conf configuration can distinguish such executed but
167 negative replies from complete failure to talk to resolved). */
171 c
= count_addresses(reply
, AF_UNSPEC
, &canonical
);
179 if (isempty(canonical
))
182 l
= strlen(canonical
);
183 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * c
;
187 *h_errnop
= NETDB_INTERNAL
;
188 return NSS_STATUS_TRYAGAIN
;
191 /* First, append name */
193 memcpy(r_name
, canonical
, l
+1);
196 /* Second, append addresses */
197 r_tuple_first
= (struct gaih_addrtuple
*) (buffer
+ idx
);
199 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
203 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
208 assert_cc(sizeof(int32_t) == sizeof(int));
210 r
= sd_bus_message_read(reply
, "ii", &ifindex
, &family
);
219 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
223 r
= sd_bus_message_exit_container(reply
);
227 if (!IN_SET(family
, AF_INET
, AF_INET6
))
230 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
235 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
236 r_tuple
->next
= i
== c
-1 ? NULL
: (struct gaih_addrtuple
*) ((char*) r_tuple
+ ALIGN(sizeof(struct gaih_addrtuple
)));
237 r_tuple
->name
= r_name
;
238 r_tuple
->family
= family
;
239 r_tuple
->scopeid
= ifindex_to_scopeid(family
, a
, ifindex
);
240 memcpy(r_tuple
->addr
, a
, sz
);
242 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
252 **pat
= *r_tuple_first
;
254 *pat
= r_tuple_first
;
259 /* Explicitly reset both *h_errnop and h_errno to work around
260 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
261 *h_errnop
= NETDB_SUCCESS
;
264 return NSS_STATUS_SUCCESS
;
269 *h_errnop
= NO_RECOVERY
;
270 return NSS_STATUS_UNAVAIL
;
273 *h_errnop
= HOST_NOT_FOUND
;
274 return NSS_STATUS_NOTFOUND
;
277 enum nss_status
_nss_resolve_gethostbyname3_r(
280 struct hostent
*result
,
281 char *buffer
, size_t buflen
,
282 int *errnop
, int *h_errnop
,
286 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
287 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
288 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
289 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
290 size_t l
, idx
, ms
, alen
;
291 const char *canonical
;
295 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
306 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
311 if (avoid_deadlock()) {
316 r
= sd_bus_open_system(&bus
);
320 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveHostname");
324 r
= sd_bus_message_set_auto_start(req
, false);
328 r
= sd_bus_message_append(req
, "isit", 0, name
, af
, (uint64_t) 0);
332 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
334 if (!bus_error_shall_fallback(&error
))
340 c
= count_addresses(reply
, af
, &canonical
);
348 if (isempty(canonical
))
351 alen
= FAMILY_ADDRESS_SIZE(af
);
352 l
= strlen(canonical
);
354 ms
= ALIGN(l
+1) + c
* ALIGN(alen
) + (c
+2) * sizeof(char*);
359 *h_errnop
= NETDB_INTERNAL
;
360 return NSS_STATUS_TRYAGAIN
;
363 /* First, append name */
365 memcpy(r_name
, canonical
, l
+1);
368 /* Second, create empty aliases array */
369 r_aliases
= buffer
+ idx
;
370 ((char**) r_aliases
)[0] = NULL
;
371 idx
+= sizeof(char*);
373 /* Third, append addresses */
374 r_addr
= buffer
+ idx
;
376 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
380 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
385 r
= sd_bus_message_read(reply
, "ii", &ifindex
, &family
);
394 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
398 r
= sd_bus_message_exit_container(reply
);
410 memcpy(r_addr
+ i
*ALIGN(alen
), a
, alen
);
417 idx
+= c
* ALIGN(alen
);
419 /* Fourth, append address pointer array */
420 r_addr_list
= buffer
+ idx
;
421 for (i
= 0; i
< c
; i
++)
422 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
424 ((char**) r_addr_list
)[i
] = NULL
;
425 idx
+= (c
+1) * sizeof(char*);
429 result
->h_name
= r_name
;
430 result
->h_aliases
= (char**) r_aliases
;
431 result
->h_addrtype
= af
;
432 result
->h_length
= alen
;
433 result
->h_addr_list
= (char**) r_addr_list
;
441 /* Explicitly reset both *h_errnop and h_errno to work around
442 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
443 *h_errnop
= NETDB_SUCCESS
;
446 return NSS_STATUS_SUCCESS
;
451 *h_errnop
= NO_RECOVERY
;
452 return NSS_STATUS_UNAVAIL
;
455 *h_errnop
= HOST_NOT_FOUND
;
456 return NSS_STATUS_NOTFOUND
;
459 enum nss_status
_nss_resolve_gethostbyaddr2_r(
460 const void* addr
, socklen_t len
,
462 struct hostent
*result
,
463 char *buffer
, size_t buflen
,
464 int *errnop
, int *h_errnop
,
467 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
468 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
469 char *r_name
, *r_aliases
, *r_addr
, *r_addr_list
;
470 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
471 unsigned c
= 0, i
= 0;
477 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
485 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
487 *errnop
= EAFNOSUPPORT
;
489 return NSS_STATUS_UNAVAIL
;
492 if (len
!= FAMILY_ADDRESS_SIZE(af
)) {
497 if (avoid_deadlock()) {
502 r
= sd_bus_open_system(&bus
);
506 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveAddress");
510 r
= sd_bus_message_set_auto_start(req
, false);
514 r
= sd_bus_message_append(req
, "ii", 0, af
);
518 r
= sd_bus_message_append_array(req
, 'y', addr
, len
);
522 r
= sd_bus_message_append(req
, "t", (uint64_t) 0);
526 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
528 if (!bus_error_shall_fallback(&error
))
534 r
= sd_bus_message_enter_container(reply
, 'a', "(is)");
538 while ((r
= sd_bus_message_read(reply
, "(is)", &ifindex
, &n
)) > 0) {
546 ms
+= ALIGN(strlen(n
) + 1);
551 r
= sd_bus_message_rewind(reply
, false);
558 ms
+= ALIGN(len
) + /* the address */
559 2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
560 c
* sizeof(char*); /* pointers to aliases, plus trailing NULL */
565 *h_errnop
= NETDB_INTERNAL
;
566 return NSS_STATUS_TRYAGAIN
;
569 /* First, place address */
571 memcpy(r_addr
, addr
, len
);
574 /* Second, place address list */
575 r_addr_list
= buffer
+ idx
;
576 ((char**) r_addr_list
)[0] = r_addr
;
577 ((char**) r_addr_list
)[1] = NULL
;
578 idx
+= sizeof(char*) * 2;
580 /* Third, reserve space for the aliases array */
581 r_aliases
= buffer
+ idx
;
582 idx
+= sizeof(char*) * c
;
584 /* Fourth, place aliases */
586 r_name
= buffer
+ idx
;
587 while ((r
= sd_bus_message_read(reply
, "(is)", &ifindex
, &n
)) > 0) {
596 ((char**) r_aliases
)[i
-1] = p
;
604 ((char**) r_aliases
)[c
-1] = NULL
;
607 result
->h_name
= r_name
;
608 result
->h_aliases
= (char**) r_aliases
;
609 result
->h_addrtype
= af
;
610 result
->h_length
= len
;
611 result
->h_addr_list
= (char**) r_addr_list
;
616 /* Explicitly reset both *h_errnop and h_errno to work around
617 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
618 *h_errnop
= NETDB_SUCCESS
;
621 return NSS_STATUS_SUCCESS
;
626 *h_errnop
= NO_RECOVERY
;
627 return NSS_STATUS_UNAVAIL
;
630 *h_errnop
= HOST_NOT_FOUND
;
631 return NSS_STATUS_NOTFOUND
;
634 NSS_GETHOSTBYNAME_FALLBACKS(resolve
);
635 NSS_GETHOSTBYADDR_FALLBACKS(resolve
);