]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
4d1cf1e2 | 2 | |
4d1cf1e2 | 3 | #include <errno.h> |
07630cea LP |
4 | #include <netdb.h> |
5 | #include <nss.h> | |
4d1cf1e2 | 6 | #include <stdlib.h> |
ca78ad1d ZJS |
7 | #include <sys/types.h> |
8 | #include <unistd.h> | |
4d1cf1e2 LP |
9 | |
10 | #include "sd-bus.h" | |
07630cea | 11 | |
96aad8d1 | 12 | #include "bus-common-errors.h" |
2b2fec7d | 13 | #include "errno-util.h" |
07630cea | 14 | #include "in-addr-util.h" |
4d1cf1e2 LP |
15 | #include "macro.h" |
16 | #include "nss-util.h" | |
4cbfd62b | 17 | #include "resolved-def.h" |
0c5eb056 | 18 | #include "signal-util.h" |
2b2fec7d | 19 | #include "string-util.h" |
4d1cf1e2 LP |
20 | |
21 | NSS_GETHOSTBYNAME_PROTOTYPES(resolve); | |
22 | NSS_GETHOSTBYADDR_PROTOTYPES(resolve); | |
23 | ||
7c2a5e26 LP |
24 | static bool bus_error_shall_fallback(sd_bus_error *e) { |
25 | return sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) || | |
26 | sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER) || | |
27 | sd_bus_error_has_name(e, SD_BUS_ERROR_NO_REPLY) || | |
8baaf650 LP |
28 | sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED) || |
29 | sd_bus_error_has_name(e, SD_BUS_ERROR_DISCONNECTED) || | |
30 | sd_bus_error_has_name(e, SD_BUS_ERROR_TIMEOUT); | |
7c2a5e26 LP |
31 | } |
32 | ||
0dd25fb9 | 33 | static int count_addresses(sd_bus_message *m, int af, const char **canonical) { |
78c6a153 | 34 | int c = 0, r; |
4d1cf1e2 LP |
35 | |
36 | assert(m); | |
309e9d86 LP |
37 | assert(canonical); |
38 | ||
78c6a153 | 39 | r = sd_bus_message_enter_container(m, 'a', "(iiay)"); |
309e9d86 LP |
40 | if (r < 0) |
41 | return r; | |
4d1cf1e2 | 42 | |
78c6a153 LP |
43 | while ((r = sd_bus_message_enter_container(m, 'r', "iiay")) > 0) { |
44 | int family, ifindex; | |
51323288 | 45 | |
78c6a153 | 46 | assert_cc(sizeof(int32_t) == sizeof(int)); |
4d1cf1e2 | 47 | |
78c6a153 | 48 | r = sd_bus_message_read(m, "ii", &ifindex, &family); |
4d1cf1e2 LP |
49 | if (r < 0) |
50 | return r; | |
51 | ||
51323288 | 52 | r = sd_bus_message_skip(m, "ay"); |
4d1cf1e2 LP |
53 | if (r < 0) |
54 | return r; | |
55 | ||
56 | r = sd_bus_message_exit_container(m); | |
57 | if (r < 0) | |
58 | return r; | |
59 | ||
60 | if (af != AF_UNSPEC && family != af) | |
61 | continue; | |
62 | ||
313cefa1 | 63 | c++; |
4d1cf1e2 LP |
64 | } |
65 | if (r < 0) | |
66 | return r; | |
67 | ||
309e9d86 LP |
68 | r = sd_bus_message_exit_container(m); |
69 | if (r < 0) | |
70 | return r; | |
71 | ||
72 | r = sd_bus_message_read(m, "s", canonical); | |
4d1cf1e2 LP |
73 | if (r < 0) |
74 | return r; | |
75 | ||
309e9d86 LP |
76 | r = sd_bus_message_rewind(m, true); |
77 | if (r < 0) | |
78 | return r; | |
79 | ||
80 | return c; | |
4d1cf1e2 LP |
81 | } |
82 | ||
27007eff LP |
83 | static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) { |
84 | struct in6_addr in6; | |
85 | ||
86 | if (family != AF_INET6) | |
87 | return 0; | |
88 | ||
89 | /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */ | |
90 | ||
11814bbb | 91 | assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET6)); |
27007eff LP |
92 | memcpy(&in6, a, sizeof(struct in6_addr)); |
93 | ||
94 | return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0; | |
95 | } | |
96 | ||
2f28018c LP |
97 | static bool avoid_deadlock(void) { |
98 | ||
99 | /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager | |
100 | * code activating systemd-resolved.service. After all, we shouldn't synchronously do lookups to | |
101 | * systemd-resolved if we are required to finish before it can be started. This of course won't detect all | |
102 | * possible dead locks of this kind, but it should work for the most obvious cases. */ | |
103 | ||
104 | if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */ | |
105 | return false; | |
106 | ||
107 | return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-resolved.service") && | |
108 | streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system"); | |
109 | } | |
110 | ||
4d1cf1e2 LP |
111 | enum nss_status _nss_resolve_gethostbyname4_r( |
112 | const char *name, | |
113 | struct gaih_addrtuple **pat, | |
114 | char *buffer, size_t buflen, | |
115 | int *errnop, int *h_errnop, | |
116 | int32_t *ttlp) { | |
117 | ||
4afd3348 LP |
118 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; |
119 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
4d1cf1e2 | 120 | struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; |
4afd3348 | 121 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; |
309e9d86 | 122 | const char *canonical = NULL; |
4d1cf1e2 LP |
123 | size_t l, ms, idx; |
124 | char *r_name; | |
78c6a153 | 125 | int c, r, i = 0; |
4d1cf1e2 | 126 | |
06202b9e | 127 | PROTECT_ERRNO; |
0c5eb056 LP |
128 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
129 | ||
4d1cf1e2 LP |
130 | assert(name); |
131 | assert(pat); | |
132 | assert(buffer); | |
133 | assert(errnop); | |
134 | assert(h_errnop); | |
135 | ||
2f28018c LP |
136 | if (avoid_deadlock()) { |
137 | r = -EDEADLK; | |
138 | goto fail; | |
139 | } | |
140 | ||
4d1cf1e2 LP |
141 | r = sd_bus_open_system(&bus); |
142 | if (r < 0) | |
5486a31d | 143 | goto fail; |
4d1cf1e2 LP |
144 | |
145 | r = sd_bus_message_new_method_call( | |
146 | bus, | |
147 | &req, | |
148 | "org.freedesktop.resolve1", | |
149 | "/org/freedesktop/resolve1", | |
150 | "org.freedesktop.resolve1.Manager", | |
151 | "ResolveHostname"); | |
152 | if (r < 0) | |
153 | goto fail; | |
154 | ||
155 | r = sd_bus_message_set_auto_start(req, false); | |
156 | if (r < 0) | |
157 | goto fail; | |
158 | ||
51323288 | 159 | r = sd_bus_message_append(req, "isit", 0, name, AF_UNSPEC, (uint64_t) 0); |
4d1cf1e2 LP |
160 | if (r < 0) |
161 | goto fail; | |
162 | ||
4cbfd62b | 163 | r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply); |
4d1cf1e2 | 164 | if (r < 0) { |
547fde47 | 165 | if (!bus_error_shall_fallback(&error)) |
06202b9e | 166 | goto not_found; |
4d1cf1e2 | 167 | |
5486a31d ZJS |
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 | |
5238e957 | 171 | case so that the nsswitch.conf configuration can distinguish such executed but |
5486a31d | 172 | negative replies from complete failure to talk to resolved). */ |
a464cf80 | 173 | goto fail; |
4d1cf1e2 LP |
174 | } |
175 | ||
309e9d86 LP |
176 | c = count_addresses(reply, AF_UNSPEC, &canonical); |
177 | if (c < 0) { | |
178 | r = c; | |
4d1cf1e2 | 179 | goto fail; |
309e9d86 | 180 | } |
06202b9e YW |
181 | if (c == 0) |
182 | goto not_found; | |
4d1cf1e2 | 183 | |
309e9d86 LP |
184 | if (isempty(canonical)) |
185 | canonical = name; | |
186 | ||
187 | l = strlen(canonical); | |
4d1cf1e2 LP |
188 | ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; |
189 | if (buflen < ms) { | |
cdccd29f | 190 | UNPROTECT_ERRNO; |
0192cbdb | 191 | *errnop = ERANGE; |
e36c6e48 | 192 | *h_errnop = NETDB_INTERNAL; |
4d1cf1e2 LP |
193 | return NSS_STATUS_TRYAGAIN; |
194 | } | |
195 | ||
196 | /* First, append name */ | |
197 | r_name = buffer; | |
309e9d86 | 198 | memcpy(r_name, canonical, l+1); |
4d1cf1e2 LP |
199 | idx = ALIGN(l+1); |
200 | ||
201 | /* Second, append addresses */ | |
202 | r_tuple_first = (struct gaih_addrtuple*) (buffer + idx); | |
309e9d86 | 203 | |
78c6a153 | 204 | r = sd_bus_message_enter_container(reply, 'a', "(iiay)"); |
309e9d86 LP |
205 | if (r < 0) |
206 | goto fail; | |
207 | ||
78c6a153 LP |
208 | while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { |
209 | int family, ifindex; | |
4d1cf1e2 | 210 | const void *a; |
4d1cf1e2 LP |
211 | size_t sz; |
212 | ||
78c6a153 LP |
213 | assert_cc(sizeof(int32_t) == sizeof(int)); |
214 | ||
215 | r = sd_bus_message_read(reply, "ii", &ifindex, &family); | |
4d1cf1e2 LP |
216 | if (r < 0) |
217 | goto fail; | |
218 | ||
78c6a153 LP |
219 | if (ifindex < 0) { |
220 | r = -EINVAL; | |
221 | goto fail; | |
222 | } | |
223 | ||
4d1cf1e2 LP |
224 | r = sd_bus_message_read_array(reply, 'y', &a, &sz); |
225 | if (r < 0) | |
226 | goto fail; | |
227 | ||
4d1cf1e2 LP |
228 | r = sd_bus_message_exit_container(reply); |
229 | if (r < 0) | |
230 | goto fail; | |
231 | ||
232 | if (!IN_SET(family, AF_INET, AF_INET6)) | |
233 | continue; | |
234 | ||
9d485985 | 235 | if (sz != FAMILY_ADDRESS_SIZE(family)) { |
4d1cf1e2 LP |
236 | r = -EINVAL; |
237 | goto fail; | |
238 | } | |
239 | ||
4d1cf1e2 LP |
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; | |
27007eff | 244 | r_tuple->scopeid = ifindex_to_scopeid(family, a, ifindex); |
4d1cf1e2 LP |
245 | memcpy(r_tuple->addr, a, sz); |
246 | ||
247 | idx += ALIGN(sizeof(struct gaih_addrtuple)); | |
248 | i++; | |
249 | } | |
4d1cf1e2 LP |
250 | if (r < 0) |
251 | goto fail; | |
252 | ||
309e9d86 | 253 | assert(i == c); |
4d1cf1e2 LP |
254 | assert(idx == ms); |
255 | ||
256 | if (*pat) | |
257 | **pat = *r_tuple_first; | |
258 | else | |
259 | *pat = r_tuple_first; | |
260 | ||
261 | if (ttlp) | |
262 | *ttlp = 0; | |
263 | ||
06202b9e YW |
264 | /* Explicitly reset both *h_errnop and h_errno to work around |
265 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
e70df46b LP |
266 | *h_errnop = NETDB_SUCCESS; |
267 | h_errno = 0; | |
268 | ||
4d1cf1e2 LP |
269 | return NSS_STATUS_SUCCESS; |
270 | ||
271 | fail: | |
cdccd29f | 272 | UNPROTECT_ERRNO; |
0192cbdb | 273 | *errnop = -r; |
a464cf80 | 274 | *h_errnop = NO_RECOVERY; |
954cba66 | 275 | return NSS_STATUS_UNAVAIL; |
06202b9e YW |
276 | |
277 | not_found: | |
278 | *h_errnop = HOST_NOT_FOUND; | |
279 | return NSS_STATUS_NOTFOUND; | |
4d1cf1e2 LP |
280 | } |
281 | ||
282 | enum nss_status _nss_resolve_gethostbyname3_r( | |
283 | const char *name, | |
284 | int af, | |
285 | struct hostent *result, | |
286 | char *buffer, size_t buflen, | |
287 | int *errnop, int *h_errnop, | |
288 | int32_t *ttlp, | |
289 | char **canonp) { | |
290 | ||
4afd3348 LP |
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; | |
4d1cf1e2 | 293 | char *r_name, *r_aliases, *r_addr, *r_addr_list; |
4afd3348 | 294 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; |
4d1cf1e2 | 295 | size_t l, idx, ms, alen; |
309e9d86 | 296 | const char *canonical; |
78c6a153 | 297 | int c, r, i = 0; |
4d1cf1e2 | 298 | |
06202b9e | 299 | PROTECT_ERRNO; |
0c5eb056 LP |
300 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
301 | ||
4d1cf1e2 LP |
302 | assert(name); |
303 | assert(result); | |
304 | assert(buffer); | |
305 | assert(errnop); | |
306 | assert(h_errnop); | |
307 | ||
308 | if (af == AF_UNSPEC) | |
309 | af = AF_INET; | |
310 | ||
4c701096 | 311 | if (!IN_SET(af, AF_INET, AF_INET6)) { |
4d1cf1e2 LP |
312 | r = -EAFNOSUPPORT; |
313 | goto fail; | |
314 | } | |
315 | ||
2f28018c LP |
316 | if (avoid_deadlock()) { |
317 | r = -EDEADLK; | |
318 | goto fail; | |
319 | } | |
320 | ||
4d1cf1e2 LP |
321 | r = sd_bus_open_system(&bus); |
322 | if (r < 0) | |
5486a31d | 323 | goto fail; |
4d1cf1e2 LP |
324 | |
325 | r = sd_bus_message_new_method_call( | |
326 | bus, | |
327 | &req, | |
328 | "org.freedesktop.resolve1", | |
329 | "/org/freedesktop/resolve1", | |
330 | "org.freedesktop.resolve1.Manager", | |
331 | "ResolveHostname"); | |
332 | if (r < 0) | |
333 | goto fail; | |
334 | ||
335 | r = sd_bus_message_set_auto_start(req, false); | |
336 | if (r < 0) | |
337 | goto fail; | |
338 | ||
51323288 | 339 | r = sd_bus_message_append(req, "isit", 0, name, af, (uint64_t) 0); |
4d1cf1e2 LP |
340 | if (r < 0) |
341 | goto fail; | |
342 | ||
4cbfd62b | 343 | r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply); |
4d1cf1e2 | 344 | if (r < 0) { |
547fde47 | 345 | if (!bus_error_shall_fallback(&error)) |
06202b9e | 346 | goto not_found; |
7c2a5e26 | 347 | |
a464cf80 | 348 | goto fail; |
4d1cf1e2 LP |
349 | } |
350 | ||
309e9d86 LP |
351 | c = count_addresses(reply, af, &canonical); |
352 | if (c < 0) { | |
353 | r = c; | |
4d1cf1e2 | 354 | goto fail; |
309e9d86 | 355 | } |
06202b9e YW |
356 | if (c == 0) |
357 | goto not_found; | |
4d1cf1e2 | 358 | |
309e9d86 LP |
359 | if (isempty(canonical)) |
360 | canonical = name; | |
361 | ||
9d485985 | 362 | alen = FAMILY_ADDRESS_SIZE(af); |
309e9d86 | 363 | l = strlen(canonical); |
4d1cf1e2 | 364 | |
66a16e7e | 365 | ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); |
4d1cf1e2 LP |
366 | |
367 | if (buflen < ms) { | |
cdccd29f | 368 | UNPROTECT_ERRNO; |
0192cbdb | 369 | *errnop = ERANGE; |
e36c6e48 | 370 | *h_errnop = NETDB_INTERNAL; |
4d1cf1e2 LP |
371 | return NSS_STATUS_TRYAGAIN; |
372 | } | |
373 | ||
374 | /* First, append name */ | |
375 | r_name = buffer; | |
309e9d86 | 376 | memcpy(r_name, canonical, l+1); |
4d1cf1e2 LP |
377 | idx = ALIGN(l+1); |
378 | ||
309e9d86 | 379 | /* Second, create empty aliases array */ |
4d1cf1e2 LP |
380 | r_aliases = buffer + idx; |
381 | ((char**) r_aliases)[0] = NULL; | |
382 | idx += sizeof(char*); | |
383 | ||
384 | /* Third, append addresses */ | |
385 | r_addr = buffer + idx; | |
309e9d86 | 386 | |
78c6a153 | 387 | r = sd_bus_message_enter_container(reply, 'a', "(iiay)"); |
51323288 LP |
388 | if (r < 0) |
389 | goto fail; | |
390 | ||
78c6a153 LP |
391 | while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { |
392 | int ifindex, family; | |
4d1cf1e2 | 393 | const void *a; |
4d1cf1e2 LP |
394 | size_t sz; |
395 | ||
78c6a153 | 396 | r = sd_bus_message_read(reply, "ii", &ifindex, &family); |
4d1cf1e2 LP |
397 | if (r < 0) |
398 | goto fail; | |
399 | ||
78c6a153 LP |
400 | if (ifindex < 0) { |
401 | r = -EINVAL; | |
402 | goto fail; | |
403 | } | |
404 | ||
4d1cf1e2 LP |
405 | r = sd_bus_message_read_array(reply, 'y', &a, &sz); |
406 | if (r < 0) | |
407 | goto fail; | |
408 | ||
4d1cf1e2 LP |
409 | r = sd_bus_message_exit_container(reply); |
410 | if (r < 0) | |
411 | goto fail; | |
412 | ||
413 | if (family != af) | |
414 | continue; | |
415 | ||
416 | if (sz != alen) { | |
417 | r = -EINVAL; | |
418 | goto fail; | |
419 | } | |
420 | ||
4d1cf1e2 LP |
421 | memcpy(r_addr + i*ALIGN(alen), a, alen); |
422 | i++; | |
423 | } | |
309e9d86 LP |
424 | if (r < 0) |
425 | goto fail; | |
4d1cf1e2 LP |
426 | |
427 | assert(i == c); | |
428 | idx += c * ALIGN(alen); | |
429 | ||
309e9d86 | 430 | /* Fourth, append address pointer array */ |
4d1cf1e2 LP |
431 | r_addr_list = buffer + idx; |
432 | for (i = 0; i < c; i++) | |
433 | ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen); | |
434 | ||
435 | ((char**) r_addr_list)[i] = NULL; | |
436 | idx += (c+1) * sizeof(char*); | |
437 | ||
438 | assert(idx == ms); | |
439 | ||
440 | result->h_name = r_name; | |
441 | result->h_aliases = (char**) r_aliases; | |
442 | result->h_addrtype = af; | |
443 | result->h_length = alen; | |
444 | result->h_addr_list = (char**) r_addr_list; | |
445 | ||
446 | if (ttlp) | |
447 | *ttlp = 0; | |
448 | ||
449 | if (canonp) | |
450 | *canonp = r_name; | |
451 | ||
06202b9e YW |
452 | /* Explicitly reset both *h_errnop and h_errno to work around |
453 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
454 | *h_errnop = NETDB_SUCCESS; | |
455 | h_errno = 0; | |
456 | ||
4d1cf1e2 LP |
457 | return NSS_STATUS_SUCCESS; |
458 | ||
459 | fail: | |
cdccd29f | 460 | UNPROTECT_ERRNO; |
0192cbdb | 461 | *errnop = -r; |
a464cf80 | 462 | *h_errnop = NO_RECOVERY; |
954cba66 | 463 | return NSS_STATUS_UNAVAIL; |
06202b9e YW |
464 | |
465 | not_found: | |
466 | *h_errnop = HOST_NOT_FOUND; | |
467 | return NSS_STATUS_NOTFOUND; | |
4d1cf1e2 LP |
468 | } |
469 | ||
470 | enum nss_status _nss_resolve_gethostbyaddr2_r( | |
471 | const void* addr, socklen_t len, | |
472 | int af, | |
473 | struct hostent *result, | |
474 | char *buffer, size_t buflen, | |
475 | int *errnop, int *h_errnop, | |
476 | int32_t *ttlp) { | |
477 | ||
4afd3348 LP |
478 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; |
479 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
4d1cf1e2 | 480 | char *r_name, *r_aliases, *r_addr, *r_addr_list; |
4afd3348 | 481 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; |
4d1cf1e2 LP |
482 | unsigned c = 0, i = 0; |
483 | size_t ms = 0, idx; | |
484 | const char *n; | |
51323288 | 485 | int r, ifindex; |
4d1cf1e2 | 486 | |
06202b9e | 487 | PROTECT_ERRNO; |
0c5eb056 LP |
488 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
489 | ||
4d1cf1e2 LP |
490 | assert(addr); |
491 | assert(result); | |
492 | assert(buffer); | |
493 | assert(errnop); | |
494 | assert(h_errnop); | |
495 | ||
496 | if (!IN_SET(af, AF_INET, AF_INET6)) { | |
cdccd29f | 497 | UNPROTECT_ERRNO; |
0192cbdb | 498 | *errnop = EAFNOSUPPORT; |
4d1cf1e2 LP |
499 | *h_errnop = NO_DATA; |
500 | return NSS_STATUS_UNAVAIL; | |
501 | } | |
502 | ||
9d485985 | 503 | if (len != FAMILY_ADDRESS_SIZE(af)) { |
a62fc245 LP |
504 | r = -EINVAL; |
505 | goto fail; | |
4d1cf1e2 LP |
506 | } |
507 | ||
2f28018c LP |
508 | if (avoid_deadlock()) { |
509 | r = -EDEADLK; | |
510 | goto fail; | |
511 | } | |
512 | ||
4d1cf1e2 LP |
513 | r = sd_bus_open_system(&bus); |
514 | if (r < 0) | |
5486a31d | 515 | goto fail; |
4d1cf1e2 LP |
516 | |
517 | r = sd_bus_message_new_method_call( | |
518 | bus, | |
519 | &req, | |
520 | "org.freedesktop.resolve1", | |
521 | "/org/freedesktop/resolve1", | |
522 | "org.freedesktop.resolve1.Manager", | |
523 | "ResolveAddress"); | |
524 | if (r < 0) | |
525 | goto fail; | |
526 | ||
527 | r = sd_bus_message_set_auto_start(req, false); | |
528 | if (r < 0) | |
529 | goto fail; | |
530 | ||
51323288 | 531 | r = sd_bus_message_append(req, "ii", 0, af); |
4d1cf1e2 LP |
532 | if (r < 0) |
533 | goto fail; | |
534 | ||
535 | r = sd_bus_message_append_array(req, 'y', addr, len); | |
536 | if (r < 0) | |
537 | goto fail; | |
538 | ||
51323288 | 539 | r = sd_bus_message_append(req, "t", (uint64_t) 0); |
4d1cf1e2 LP |
540 | if (r < 0) |
541 | goto fail; | |
542 | ||
4cbfd62b | 543 | r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply); |
4d1cf1e2 | 544 | if (r < 0) { |
547fde47 | 545 | if (!bus_error_shall_fallback(&error)) |
06202b9e | 546 | goto not_found; |
7c2a5e26 | 547 | |
46c7a7ac | 548 | goto fail; |
4d1cf1e2 LP |
549 | } |
550 | ||
78c6a153 | 551 | r = sd_bus_message_enter_container(reply, 'a', "(is)"); |
51323288 LP |
552 | if (r < 0) |
553 | goto fail; | |
554 | ||
78c6a153 | 555 | while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) { |
51323288 | 556 | |
78c6a153 LP |
557 | if (ifindex < 0) { |
558 | r = -EINVAL; | |
559 | goto fail; | |
560 | } | |
4d1cf1e2 | 561 | |
4d1cf1e2 LP |
562 | c++; |
563 | ms += ALIGN(strlen(n) + 1); | |
564 | } | |
565 | if (r < 0) | |
566 | goto fail; | |
567 | ||
568 | r = sd_bus_message_rewind(reply, false); | |
569 | if (r < 0) | |
c7c468c9 | 570 | goto fail; |
4d1cf1e2 | 571 | |
06202b9e YW |
572 | if (c <= 0) |
573 | goto not_found; | |
4d1cf1e2 LP |
574 | |
575 | ms += ALIGN(len) + /* the address */ | |
576 | 2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */ | |
577 | c * sizeof(char*); /* pointers to aliases, plus trailing NULL */ | |
578 | ||
579 | if (buflen < ms) { | |
cdccd29f | 580 | UNPROTECT_ERRNO; |
0192cbdb | 581 | *errnop = ERANGE; |
e36c6e48 | 582 | *h_errnop = NETDB_INTERNAL; |
4d1cf1e2 LP |
583 | return NSS_STATUS_TRYAGAIN; |
584 | } | |
585 | ||
586 | /* First, place address */ | |
587 | r_addr = buffer; | |
588 | memcpy(r_addr, addr, len); | |
589 | idx = ALIGN(len); | |
590 | ||
591 | /* Second, place address list */ | |
592 | r_addr_list = buffer + idx; | |
593 | ((char**) r_addr_list)[0] = r_addr; | |
594 | ((char**) r_addr_list)[1] = NULL; | |
595 | idx += sizeof(char*) * 2; | |
596 | ||
597 | /* Third, reserve space for the aliases array */ | |
598 | r_aliases = buffer + idx; | |
599 | idx += sizeof(char*) * c; | |
600 | ||
601 | /* Fourth, place aliases */ | |
602 | i = 0; | |
603 | r_name = buffer + idx; | |
78c6a153 | 604 | while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) { |
4d1cf1e2 LP |
605 | char *p; |
606 | size_t l; | |
607 | ||
608 | l = strlen(n); | |
609 | p = buffer + idx; | |
610 | memcpy(p, n, l+1); | |
611 | ||
963783d7 | 612 | if (i > 0) |
4d1cf1e2 LP |
613 | ((char**) r_aliases)[i-1] = p; |
614 | i++; | |
615 | ||
616 | idx += ALIGN(l+1); | |
617 | } | |
309e9d86 LP |
618 | if (r < 0) |
619 | goto fail; | |
4d1cf1e2 LP |
620 | |
621 | ((char**) r_aliases)[c-1] = NULL; | |
622 | assert(idx == ms); | |
623 | ||
624 | result->h_name = r_name; | |
625 | result->h_aliases = (char**) r_aliases; | |
626 | result->h_addrtype = af; | |
627 | result->h_length = len; | |
628 | result->h_addr_list = (char**) r_addr_list; | |
629 | ||
630 | if (ttlp) | |
631 | *ttlp = 0; | |
632 | ||
06202b9e YW |
633 | /* Explicitly reset both *h_errnop and h_errno to work around |
634 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
e70df46b LP |
635 | *h_errnop = NETDB_SUCCESS; |
636 | h_errno = 0; | |
637 | ||
4d1cf1e2 LP |
638 | return NSS_STATUS_SUCCESS; |
639 | ||
640 | fail: | |
cdccd29f | 641 | UNPROTECT_ERRNO; |
0192cbdb | 642 | *errnop = -r; |
a464cf80 | 643 | *h_errnop = NO_RECOVERY; |
954cba66 | 644 | return NSS_STATUS_UNAVAIL; |
06202b9e YW |
645 | |
646 | not_found: | |
647 | *h_errnop = HOST_NOT_FOUND; | |
648 | return NSS_STATUS_NOTFOUND; | |
4d1cf1e2 LP |
649 | } |
650 | ||
651 | NSS_GETHOSTBYNAME_FALLBACKS(resolve); | |
652 | NSS_GETHOSTBYADDR_FALLBACKS(resolve); |