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