]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nss-resolve/nss-resolve.c
Remove systemd-firstboot --force entry from TODO
[thirdparty/systemd.git] / src / nss-resolve / nss-resolve.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <netdb.h>
5 #include <nss.h>
6 #include <stdlib.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9
10 #include "sd-bus.h"
11
12 #include "bus-common-errors.h"
13 #include "bus-util.h"
14 #include "errno-util.h"
15 #include "in-addr-util.h"
16 #include "macro.h"
17 #include "nss-util.h"
18 #include "resolved-def.h"
19 #include "signal-util.h"
20 #include "string-util.h"
21
22 NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
23 NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
24
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);
32 }
33
34 static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
35 int c = 0, r;
36
37 assert(m);
38 assert(canonical);
39
40 r = sd_bus_message_enter_container(m, 'a', "(iiay)");
41 if (r < 0)
42 return r;
43
44 while ((r = sd_bus_message_enter_container(m, 'r', "iiay")) > 0) {
45 int family, ifindex;
46
47 assert_cc(sizeof(int32_t) == sizeof(int));
48
49 r = sd_bus_message_read(m, "ii", &ifindex, &family);
50 if (r < 0)
51 return r;
52
53 r = sd_bus_message_skip(m, "ay");
54 if (r < 0)
55 return r;
56
57 r = sd_bus_message_exit_container(m);
58 if (r < 0)
59 return r;
60
61 if (af != AF_UNSPEC && family != af)
62 continue;
63
64 c++;
65 }
66 if (r < 0)
67 return r;
68
69 r = sd_bus_message_exit_container(m);
70 if (r < 0)
71 return r;
72
73 r = sd_bus_message_read(m, "s", canonical);
74 if (r < 0)
75 return r;
76
77 r = sd_bus_message_rewind(m, true);
78 if (r < 0)
79 return r;
80
81 return c;
82 }
83
84 static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
85 struct in6_addr in6;
86
87 if (family != AF_INET6)
88 return 0;
89
90 /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
91
92 assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET6));
93 memcpy(&in6, a, sizeof(struct in6_addr));
94
95 return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0;
96 }
97
98 static bool avoid_deadlock(void) {
99
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. */
104
105 if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
106 return false;
107
108 return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-resolved.service") &&
109 streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
110 }
111
112 enum nss_status _nss_resolve_gethostbyname4_r(
113 const char *name,
114 struct gaih_addrtuple **pat,
115 char *buffer, size_t buflen,
116 int *errnop, int *h_errnop,
117 int32_t *ttlp) {
118
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;
124 size_t l, ms, idx;
125 char *r_name;
126 int c, r, i = 0;
127
128 PROTECT_ERRNO;
129 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
130
131 assert(name);
132 assert(pat);
133 assert(buffer);
134 assert(errnop);
135 assert(h_errnop);
136
137 if (avoid_deadlock()) {
138 r = -EDEADLK;
139 goto fail;
140 }
141
142 r = sd_bus_open_system(&bus);
143 if (r < 0)
144 goto fail;
145
146 r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
147 if (r < 0)
148 goto fail;
149
150 r = sd_bus_message_set_auto_start(req, false);
151 if (r < 0)
152 goto fail;
153
154 r = sd_bus_message_append(req, "isit", 0, name, AF_UNSPEC, (uint64_t) 0);
155 if (r < 0)
156 goto fail;
157
158 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
159 if (r < 0) {
160 if (!bus_error_shall_fallback(&error))
161 goto not_found;
162
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). */
168 goto fail;
169 }
170
171 c = count_addresses(reply, AF_UNSPEC, &canonical);
172 if (c < 0) {
173 r = c;
174 goto fail;
175 }
176 if (c == 0)
177 goto not_found;
178
179 if (isempty(canonical))
180 canonical = name;
181
182 l = strlen(canonical);
183 ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
184 if (buflen < ms) {
185 UNPROTECT_ERRNO;
186 *errnop = ERANGE;
187 *h_errnop = NETDB_INTERNAL;
188 return NSS_STATUS_TRYAGAIN;
189 }
190
191 /* First, append name */
192 r_name = buffer;
193 memcpy(r_name, canonical, l+1);
194 idx = ALIGN(l+1);
195
196 /* Second, append addresses */
197 r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
198
199 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
200 if (r < 0)
201 goto fail;
202
203 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
204 int family, ifindex;
205 const void *a;
206 size_t sz;
207
208 assert_cc(sizeof(int32_t) == sizeof(int));
209
210 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
211 if (r < 0)
212 goto fail;
213
214 if (ifindex < 0) {
215 r = -EINVAL;
216 goto fail;
217 }
218
219 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
220 if (r < 0)
221 goto fail;
222
223 r = sd_bus_message_exit_container(reply);
224 if (r < 0)
225 goto fail;
226
227 if (!IN_SET(family, AF_INET, AF_INET6))
228 continue;
229
230 if (sz != FAMILY_ADDRESS_SIZE(family)) {
231 r = -EINVAL;
232 goto fail;
233 }
234
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);
241
242 idx += ALIGN(sizeof(struct gaih_addrtuple));
243 i++;
244 }
245 if (r < 0)
246 goto fail;
247
248 assert(i == c);
249 assert(idx == ms);
250
251 if (*pat)
252 **pat = *r_tuple_first;
253 else
254 *pat = r_tuple_first;
255
256 if (ttlp)
257 *ttlp = 0;
258
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;
262 h_errno = 0;
263
264 return NSS_STATUS_SUCCESS;
265
266 fail:
267 UNPROTECT_ERRNO;
268 *errnop = -r;
269 *h_errnop = NO_RECOVERY;
270 return NSS_STATUS_UNAVAIL;
271
272 not_found:
273 *h_errnop = HOST_NOT_FOUND;
274 return NSS_STATUS_NOTFOUND;
275 }
276
277 enum nss_status _nss_resolve_gethostbyname3_r(
278 const char *name,
279 int af,
280 struct hostent *result,
281 char *buffer, size_t buflen,
282 int *errnop, int *h_errnop,
283 int32_t *ttlp,
284 char **canonp) {
285
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;
292 int c, r, i = 0;
293
294 PROTECT_ERRNO;
295 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
296
297 assert(name);
298 assert(result);
299 assert(buffer);
300 assert(errnop);
301 assert(h_errnop);
302
303 if (af == AF_UNSPEC)
304 af = AF_INET;
305
306 if (!IN_SET(af, AF_INET, AF_INET6)) {
307 r = -EAFNOSUPPORT;
308 goto fail;
309 }
310
311 if (avoid_deadlock()) {
312 r = -EDEADLK;
313 goto fail;
314 }
315
316 r = sd_bus_open_system(&bus);
317 if (r < 0)
318 goto fail;
319
320 r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
321 if (r < 0)
322 goto fail;
323
324 r = sd_bus_message_set_auto_start(req, false);
325 if (r < 0)
326 goto fail;
327
328 r = sd_bus_message_append(req, "isit", 0, name, af, (uint64_t) 0);
329 if (r < 0)
330 goto fail;
331
332 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
333 if (r < 0) {
334 if (!bus_error_shall_fallback(&error))
335 goto not_found;
336
337 goto fail;
338 }
339
340 c = count_addresses(reply, af, &canonical);
341 if (c < 0) {
342 r = c;
343 goto fail;
344 }
345 if (c == 0)
346 goto not_found;
347
348 if (isempty(canonical))
349 canonical = name;
350
351 alen = FAMILY_ADDRESS_SIZE(af);
352 l = strlen(canonical);
353
354 ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
355
356 if (buflen < ms) {
357 UNPROTECT_ERRNO;
358 *errnop = ERANGE;
359 *h_errnop = NETDB_INTERNAL;
360 return NSS_STATUS_TRYAGAIN;
361 }
362
363 /* First, append name */
364 r_name = buffer;
365 memcpy(r_name, canonical, l+1);
366 idx = ALIGN(l+1);
367
368 /* Second, create empty aliases array */
369 r_aliases = buffer + idx;
370 ((char**) r_aliases)[0] = NULL;
371 idx += sizeof(char*);
372
373 /* Third, append addresses */
374 r_addr = buffer + idx;
375
376 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
377 if (r < 0)
378 goto fail;
379
380 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
381 int ifindex, family;
382 const void *a;
383 size_t sz;
384
385 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
386 if (r < 0)
387 goto fail;
388
389 if (ifindex < 0) {
390 r = -EINVAL;
391 goto fail;
392 }
393
394 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
395 if (r < 0)
396 goto fail;
397
398 r = sd_bus_message_exit_container(reply);
399 if (r < 0)
400 goto fail;
401
402 if (family != af)
403 continue;
404
405 if (sz != alen) {
406 r = -EINVAL;
407 goto fail;
408 }
409
410 memcpy(r_addr + i*ALIGN(alen), a, alen);
411 i++;
412 }
413 if (r < 0)
414 goto fail;
415
416 assert(i == c);
417 idx += c * ALIGN(alen);
418
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);
423
424 ((char**) r_addr_list)[i] = NULL;
425 idx += (c+1) * sizeof(char*);
426
427 assert(idx == ms);
428
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;
434
435 if (ttlp)
436 *ttlp = 0;
437
438 if (canonp)
439 *canonp = r_name;
440
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;
444 h_errno = 0;
445
446 return NSS_STATUS_SUCCESS;
447
448 fail:
449 UNPROTECT_ERRNO;
450 *errnop = -r;
451 *h_errnop = NO_RECOVERY;
452 return NSS_STATUS_UNAVAIL;
453
454 not_found:
455 *h_errnop = HOST_NOT_FOUND;
456 return NSS_STATUS_NOTFOUND;
457 }
458
459 enum nss_status _nss_resolve_gethostbyaddr2_r(
460 const void* addr, socklen_t len,
461 int af,
462 struct hostent *result,
463 char *buffer, size_t buflen,
464 int *errnop, int *h_errnop,
465 int32_t *ttlp) {
466
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;
472 size_t ms = 0, idx;
473 const char *n;
474 int r, ifindex;
475
476 PROTECT_ERRNO;
477 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
478
479 assert(addr);
480 assert(result);
481 assert(buffer);
482 assert(errnop);
483 assert(h_errnop);
484
485 if (!IN_SET(af, AF_INET, AF_INET6)) {
486 UNPROTECT_ERRNO;
487 *errnop = EAFNOSUPPORT;
488 *h_errnop = NO_DATA;
489 return NSS_STATUS_UNAVAIL;
490 }
491
492 if (len != FAMILY_ADDRESS_SIZE(af)) {
493 r = -EINVAL;
494 goto fail;
495 }
496
497 if (avoid_deadlock()) {
498 r = -EDEADLK;
499 goto fail;
500 }
501
502 r = sd_bus_open_system(&bus);
503 if (r < 0)
504 goto fail;
505
506 r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
507 if (r < 0)
508 goto fail;
509
510 r = sd_bus_message_set_auto_start(req, false);
511 if (r < 0)
512 goto fail;
513
514 r = sd_bus_message_append(req, "ii", 0, af);
515 if (r < 0)
516 goto fail;
517
518 r = sd_bus_message_append_array(req, 'y', addr, len);
519 if (r < 0)
520 goto fail;
521
522 r = sd_bus_message_append(req, "t", (uint64_t) 0);
523 if (r < 0)
524 goto fail;
525
526 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
527 if (r < 0) {
528 if (!bus_error_shall_fallback(&error))
529 goto not_found;
530
531 goto fail;
532 }
533
534 r = sd_bus_message_enter_container(reply, 'a', "(is)");
535 if (r < 0)
536 goto fail;
537
538 while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) {
539
540 if (ifindex < 0) {
541 r = -EINVAL;
542 goto fail;
543 }
544
545 c++;
546 ms += ALIGN(strlen(n) + 1);
547 }
548 if (r < 0)
549 goto fail;
550
551 r = sd_bus_message_rewind(reply, false);
552 if (r < 0)
553 goto fail;
554
555 if (c <= 0)
556 goto not_found;
557
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 */
561
562 if (buflen < ms) {
563 UNPROTECT_ERRNO;
564 *errnop = ERANGE;
565 *h_errnop = NETDB_INTERNAL;
566 return NSS_STATUS_TRYAGAIN;
567 }
568
569 /* First, place address */
570 r_addr = buffer;
571 memcpy(r_addr, addr, len);
572 idx = ALIGN(len);
573
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;
579
580 /* Third, reserve space for the aliases array */
581 r_aliases = buffer + idx;
582 idx += sizeof(char*) * c;
583
584 /* Fourth, place aliases */
585 i = 0;
586 r_name = buffer + idx;
587 while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) {
588 char *p;
589 size_t l;
590
591 l = strlen(n);
592 p = buffer + idx;
593 memcpy(p, n, l+1);
594
595 if (i > 0)
596 ((char**) r_aliases)[i-1] = p;
597 i++;
598
599 idx += ALIGN(l+1);
600 }
601 if (r < 0)
602 goto fail;
603
604 ((char**) r_aliases)[c-1] = NULL;
605 assert(idx == ms);
606
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;
612
613 if (ttlp)
614 *ttlp = 0;
615
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;
619 h_errno = 0;
620
621 return NSS_STATUS_SUCCESS;
622
623 fail:
624 UNPROTECT_ERRNO;
625 *errnop = -r;
626 *h_errnop = NO_RECOVERY;
627 return NSS_STATUS_UNAVAIL;
628
629 not_found:
630 *h_errnop = HOST_NOT_FOUND;
631 return NSS_STATUS_NOTFOUND;
632 }
633
634 NSS_GETHOSTBYNAME_FALLBACKS(resolve);
635 NSS_GETHOSTBYADDR_FALLBACKS(resolve);