chiark / gitweb /
systemctl: fail in the case that no unit files were found
[elogind.git] / src / nss-resolve / nss-resolve.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <limits.h>
23 #include <nss.h>
24 #include <sys/types.h>
25 #include <netdb.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <net/if.h>
30 #include <stdlib.h>
31 #include <arpa/inet.h>
32 #include <dlfcn.h>
33
34 #include "sd-bus.h"
35 #include "bus-util.h"
36 #include "bus-errors.h"
37 #include "macro.h"
38 #include "nss-util.h"
39 #include "util.h"
40 #include "in-addr-util.h"
41
42 NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
43 NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
44
45 #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
46
47 typedef void (*voidfunc_t)(void);
48
49 static voidfunc_t find_fallback(const char *module, const char *symbol) {
50         void *dl;
51
52         /* Try to find a fallback NSS module symbol */
53
54         dl = dlopen(module, RTLD_LAZY|RTLD_NODELETE);
55         if (!dl)
56                 return NULL;
57
58         return dlsym(dl, symbol);
59 }
60
61 static bool bus_error_shall_fallback(sd_bus_error *e) {
62         return sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) ||
63                sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER) ||
64                sd_bus_error_has_name(e, SD_BUS_ERROR_NO_REPLY) ||
65                sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED);
66 }
67
68 static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
69         int c = 0, r, ifindex;
70
71         assert(m);
72         assert(canonical);
73
74         r = sd_bus_message_read(m, "i", &ifindex);
75         if (r < 0)
76                 return r;
77
78         r = sd_bus_message_enter_container(m, 'a', "(iay)");
79         if (r < 0)
80                 return r;
81
82         while ((r = sd_bus_message_enter_container(m, 'r', "iay")) > 0) {
83                 int family;
84
85                 r = sd_bus_message_read(m, "i", &family);
86                 if (r < 0)
87                         return r;
88
89                 r = sd_bus_message_skip(m, "ay");
90                 if (r < 0)
91                         return r;
92
93                 r = sd_bus_message_exit_container(m);
94                 if (r < 0)
95                         return r;
96
97                 if (af != AF_UNSPEC && family != af)
98                         continue;
99
100                 c ++;
101         }
102         if (r < 0)
103                 return r;
104
105         r = sd_bus_message_exit_container(m);
106         if (r < 0)
107                 return r;
108
109         r = sd_bus_message_read(m, "s", canonical);
110         if (r < 0)
111                 return r;
112
113         r = sd_bus_message_rewind(m, true);
114         if (r < 0)
115                 return r;
116
117         return c;
118 }
119
120 enum nss_status _nss_resolve_gethostbyname4_r(
121                 const char *name,
122                 struct gaih_addrtuple **pat,
123                 char *buffer, size_t buflen,
124                 int *errnop, int *h_errnop,
125                 int32_t *ttlp) {
126
127         _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
128         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
129         struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
130         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
131         const char *canonical = NULL;
132         size_t l, ms, idx;
133         char *r_name;
134         int c, r, i = 0, ifindex;
135
136         assert(name);
137         assert(pat);
138         assert(buffer);
139         assert(errnop);
140         assert(h_errnop);
141
142         r = sd_bus_open_system(&bus);
143         if (r < 0)
144                 goto fail;
145
146         r = sd_bus_message_new_method_call(
147                         bus,
148                         &req,
149                         "org.freedesktop.resolve1",
150                         "/org/freedesktop/resolve1",
151                         "org.freedesktop.resolve1.Manager",
152                         "ResolveHostname");
153         if (r < 0)
154                 goto fail;
155
156         r = sd_bus_message_set_auto_start(req, false);
157         if (r < 0)
158                 goto fail;
159
160         r = sd_bus_message_append(req, "isit", 0, name, AF_UNSPEC, (uint64_t) 0);
161         if (r < 0)
162                 goto fail;
163
164         r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
165         if (r < 0) {
166                 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
167                         *errnop = ESRCH;
168                         *h_errnop = HOST_NOT_FOUND;
169                         return NSS_STATUS_NOTFOUND;
170                 }
171
172                 if (bus_error_shall_fallback(&error)) {
173
174                         enum nss_status (*fallback)(
175                                         const char *name,
176                                         struct gaih_addrtuple **pat,
177                                         char *buffer, size_t buflen,
178                                         int *errnop, int *h_errnop,
179                                         int32_t *ttlp);
180
181                         fallback = (enum nss_status (*)(const char *name,
182                                                         struct gaih_addrtuple **pat,
183                                                         char *buffer, size_t buflen,
184                                                         int *errnop, int *h_errnop,
185                                                         int32_t *ttlp))
186                                 find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r");
187                         if (fallback)
188                                 return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp);
189                 }
190
191                 *errnop = -r;
192                 *h_errnop = NO_RECOVERY;
193                 return NSS_STATUS_UNAVAIL;
194         }
195
196         c = count_addresses(reply, AF_UNSPEC, &canonical);
197         if (c < 0) {
198                 r = c;
199                 goto fail;
200         }
201         if (c == 0) {
202                 *errnop = ESRCH;
203                 *h_errnop = HOST_NOT_FOUND;
204                 return NSS_STATUS_NOTFOUND;
205         }
206
207         if (isempty(canonical))
208                 canonical = name;
209
210         l = strlen(canonical);
211         ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
212         if (buflen < ms) {
213                 *errnop = ENOMEM;
214                 *h_errnop = TRY_AGAIN;
215                 return NSS_STATUS_TRYAGAIN;
216         }
217
218         /* First, append name */
219         r_name = buffer;
220         memcpy(r_name, canonical, l+1);
221         idx = ALIGN(l+1);
222
223         /* Second, append addresses */
224         r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
225
226         r = sd_bus_message_read(reply, "i", &ifindex);
227         if (r < 0)
228                 goto fail;
229
230         if (ifindex < 0) {
231                 r = -EINVAL;
232                 goto fail;
233         }
234
235         r = sd_bus_message_enter_container(reply, 'a', "(iay)");
236         if (r < 0)
237                 goto fail;
238
239         while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
240                 int family;
241                 const void *a;
242                 size_t sz;
243
244                 r = sd_bus_message_read(reply, "i", &family);
245                 if (r < 0)
246                         goto fail;
247
248                 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
249                 if (r < 0)
250                         goto fail;
251
252                 r = sd_bus_message_exit_container(reply);
253                 if (r < 0)
254                         goto fail;
255
256                 if (!IN_SET(family, AF_INET, AF_INET6))
257                         continue;
258
259                 if (sz != FAMILY_ADDRESS_SIZE(family)) {
260                         r = -EINVAL;
261                         goto fail;
262                 }
263
264                 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
265                 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
266                 r_tuple->name = r_name;
267                 r_tuple->family = family;
268                 r_tuple->scopeid = ifindex;
269                 memcpy(r_tuple->addr, a, sz);
270
271                 idx += ALIGN(sizeof(struct gaih_addrtuple));
272                 i++;
273         }
274         if (r < 0)
275                 goto fail;
276
277         assert(i == c);
278         assert(idx == ms);
279
280         if (*pat)
281                 **pat = *r_tuple_first;
282         else
283                 *pat = r_tuple_first;
284
285         if (ttlp)
286                 *ttlp = 0;
287
288         /* Explicitly reset all error variables */
289         *errnop = 0;
290         *h_errnop = NETDB_SUCCESS;
291         h_errno = 0;
292
293         return NSS_STATUS_SUCCESS;
294
295 fail:
296         *errnop = -r;
297         *h_errnop = NO_DATA;
298         return NSS_STATUS_UNAVAIL;
299 }
300
301 enum nss_status _nss_resolve_gethostbyname3_r(
302                 const char *name,
303                 int af,
304                 struct hostent *result,
305                 char *buffer, size_t buflen,
306                 int *errnop, int *h_errnop,
307                 int32_t *ttlp,
308                 char **canonp) {
309
310         _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
311         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
312         char *r_name, *r_aliases, *r_addr, *r_addr_list;
313         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
314         size_t l, idx, ms, alen;
315         const char *canonical;
316         int c, r, i = 0, ifindex;
317
318         assert(name);
319         assert(result);
320         assert(buffer);
321         assert(errnop);
322         assert(h_errnop);
323
324         if (af == AF_UNSPEC)
325                 af = AF_INET;
326
327         if (af != AF_INET && af != AF_INET6) {
328                 r = -EAFNOSUPPORT;
329                 goto fail;
330         }
331
332         r = sd_bus_open_system(&bus);
333         if (r < 0)
334                 goto fail;
335
336         r = sd_bus_message_new_method_call(
337                         bus,
338                         &req,
339                         "org.freedesktop.resolve1",
340                         "/org/freedesktop/resolve1",
341                         "org.freedesktop.resolve1.Manager",
342                         "ResolveHostname");
343         if (r < 0)
344                 goto fail;
345
346         r = sd_bus_message_set_auto_start(req, false);
347         if (r < 0)
348                 goto fail;
349
350         r = sd_bus_message_append(req, "isit", 0, name, af, (uint64_t) 0);
351         if (r < 0)
352                 goto fail;
353
354         r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
355         if (r < 0) {
356                 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
357                         *errnop = ESRCH;
358                         *h_errnop = HOST_NOT_FOUND;
359                         return NSS_STATUS_NOTFOUND;
360                 }
361
362                 if (bus_error_shall_fallback(&error)) {
363
364                         enum nss_status (*fallback)(
365                                         const char *name,
366                                         int af,
367                                         struct hostent *result,
368                                         char *buffer, size_t buflen,
369                                         int *errnop, int *h_errnop,
370                                         int32_t *ttlp,
371                                         char **canonp);
372
373                         fallback =  (enum nss_status (*)(const char *name,
374                                                          int af,
375                                                          struct hostent *result,
376                                                          char *buffer, size_t buflen,
377                                                          int *errnop, int *h_errnop,
378                                                          int32_t *ttlp,
379                                                          char **canonp))
380                                 find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r");
381                         if (fallback)
382                                 return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
383                 }
384
385                 *errnop = -r;
386                 *h_errnop = NO_RECOVERY;
387                 return NSS_STATUS_UNAVAIL;
388         }
389
390         c = count_addresses(reply, af, &canonical);
391         if (c < 0) {
392                 r = c;
393                 goto fail;
394         }
395         if (c == 0) {
396                 *errnop = ESRCH;
397                 *h_errnop = HOST_NOT_FOUND;
398                 return NSS_STATUS_NOTFOUND;
399         }
400
401         if (isempty(canonical))
402                 canonical = name;
403
404         alen = FAMILY_ADDRESS_SIZE(af);
405         l = strlen(canonical);
406
407         ms = ALIGN(l+1) +
408                 sizeof(char*) +
409                 (c > 0 ? c : 1) * ALIGN(alen) +
410                 (c > 0 ? c+1 : 2) * sizeof(char*);
411
412         if (buflen < ms) {
413                 *errnop = ENOMEM;
414                 *h_errnop = TRY_AGAIN;
415                 return NSS_STATUS_TRYAGAIN;
416         }
417
418         /* First, append name */
419         r_name = buffer;
420         memcpy(r_name, canonical, l+1);
421         idx = ALIGN(l+1);
422
423         /* Second, create empty aliases array */
424         r_aliases = buffer + idx;
425         ((char**) r_aliases)[0] = NULL;
426         idx += sizeof(char*);
427
428         /* Third, append addresses */
429         r_addr = buffer + idx;
430
431         r = sd_bus_message_read(reply, "i", &ifindex);
432         if (r < 0)
433                 goto fail;
434
435         if (ifindex < 0) {
436                 r = -EINVAL;
437                 goto fail;
438         }
439
440         r = sd_bus_message_enter_container(reply, 'a', "(iay)");
441         if (r < 0)
442                 goto fail;
443
444         while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
445                 int family;
446                 const void *a;
447                 size_t sz;
448
449                 r = sd_bus_message_read(reply, "i", &family);
450                 if (r < 0)
451                         goto fail;
452
453                 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
454                 if (r < 0)
455                         goto fail;
456
457                 r = sd_bus_message_exit_container(reply);
458                 if (r < 0)
459                         goto fail;
460
461                 if (family != af)
462                         continue;
463
464                 if (sz != alen) {
465                         r = -EINVAL;
466                         goto fail;
467                 }
468
469                 if (ifindex < 0) {
470                         r = -EINVAL;
471                         goto fail;
472                 }
473
474                 memcpy(r_addr + i*ALIGN(alen), a, alen);
475                 i++;
476         }
477         if (r < 0)
478                 goto fail;
479
480         assert(i == c);
481         idx += c * ALIGN(alen);
482
483         /* Fourth, append address pointer array */
484         r_addr_list = buffer + idx;
485         for (i = 0; i < c; i++)
486                 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
487
488         ((char**) r_addr_list)[i] = NULL;
489         idx += (c+1) * sizeof(char*);
490
491         assert(idx == ms);
492
493         result->h_name = r_name;
494         result->h_aliases = (char**) r_aliases;
495         result->h_addrtype = af;
496         result->h_length = alen;
497         result->h_addr_list = (char**) r_addr_list;
498
499         /* Explicitly reset all error variables */
500         *errnop = 0;
501         *h_errnop = NETDB_SUCCESS;
502         h_errno = 0;
503
504         if (ttlp)
505                 *ttlp = 0;
506
507         if (canonp)
508                 *canonp = r_name;
509
510         return NSS_STATUS_SUCCESS;
511
512 fail:
513         *errnop = -r;
514         *h_errnop = NO_DATA;
515         return NSS_STATUS_UNAVAIL;
516 }
517
518 enum nss_status _nss_resolve_gethostbyaddr2_r(
519                 const void* addr, socklen_t len,
520                 int af,
521                 struct hostent *result,
522                 char *buffer, size_t buflen,
523                 int *errnop, int *h_errnop,
524                 int32_t *ttlp) {
525
526         _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
527         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
528         char *r_name, *r_aliases, *r_addr, *r_addr_list;
529         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
530         unsigned c = 0, i = 0;
531         size_t ms = 0, idx;
532         const char *n;
533         int r, ifindex;
534
535         assert(addr);
536         assert(result);
537         assert(buffer);
538         assert(errnop);
539         assert(h_errnop);
540
541         if (!IN_SET(af, AF_INET, AF_INET6)) {
542                 *errnop = EAFNOSUPPORT;
543                 *h_errnop = NO_DATA;
544                 return NSS_STATUS_UNAVAIL;
545         }
546
547         if (len != FAMILY_ADDRESS_SIZE(af)) {
548                 *errnop = EINVAL;
549                 *h_errnop = NO_RECOVERY;
550                 return NSS_STATUS_UNAVAIL;
551         }
552
553         r = sd_bus_open_system(&bus);
554         if (r < 0)
555                 goto fail;
556
557         r = sd_bus_message_new_method_call(
558                         bus,
559                         &req,
560                         "org.freedesktop.resolve1",
561                         "/org/freedesktop/resolve1",
562                         "org.freedesktop.resolve1.Manager",
563                         "ResolveAddress");
564         if (r < 0)
565                 goto fail;
566
567         r = sd_bus_message_set_auto_start(req, false);
568         if (r < 0)
569                 goto fail;
570
571         r = sd_bus_message_append(req, "ii", 0, af);
572         if (r < 0)
573                 goto fail;
574
575         r = sd_bus_message_append_array(req, 'y', addr, len);
576         if (r < 0)
577                 goto fail;
578
579         r = sd_bus_message_append(req, "t", (uint64_t) 0);
580         if (r < 0)
581                 goto fail;
582
583         r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
584         if (r < 0) {
585                 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
586                         *errnop = ESRCH;
587                         *h_errnop = HOST_NOT_FOUND;
588                         return NSS_STATUS_NOTFOUND;
589                 }
590
591                 if (bus_error_shall_fallback(&error)) {
592
593                         enum nss_status (*fallback)(
594                                         const void* addr, socklen_t len,
595                                         int af,
596                                         struct hostent *result,
597                                         char *buffer, size_t buflen,
598                                         int *errnop, int *h_errnop,
599                                         int32_t *ttlp);
600
601                         fallback = (enum nss_status (*)(
602                                         const void* addr, socklen_t len,
603                                         int af,
604                                         struct hostent *result,
605                                         char *buffer, size_t buflen,
606                                         int *errnop, int *h_errnop,
607                                         int32_t *ttlp))
608                                 find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r");
609
610                         if (fallback)
611                                 return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp);
612                 }
613
614                 *errnop = -r;
615                 *h_errnop = NO_RECOVERY;
616                 return NSS_STATUS_UNAVAIL;
617         }
618
619         r = sd_bus_message_read(reply, "i", &ifindex);
620         if (r < 0)
621                 goto fail;
622
623         if (ifindex < 0) {
624                 r = -EINVAL;
625                 goto fail;
626         }
627
628         r = sd_bus_message_enter_container(reply, 'a', "s");
629         if (r < 0)
630                 goto fail;
631
632         while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
633                 c++;
634                 ms += ALIGN(strlen(n) + 1);
635         }
636         if (r < 0)
637                 goto fail;
638
639         r = sd_bus_message_rewind(reply, false);
640         if (r < 0)
641                 return r;
642
643         if (c <= 0) {
644                 *errnop = ESRCH;
645                 *h_errnop = HOST_NOT_FOUND;
646                 return NSS_STATUS_NOTFOUND;
647         }
648
649         ms += ALIGN(len) +              /* the address */
650               2 * sizeof(char*) +       /* pointers to the address, plus trailing NULL */
651               c * sizeof(char*);        /* pointers to aliases, plus trailing NULL */
652
653         if (buflen < ms) {
654                 *errnop = ENOMEM;
655                 *h_errnop = TRY_AGAIN;
656                 return NSS_STATUS_TRYAGAIN;
657         }
658
659         /* First, place address */
660         r_addr = buffer;
661         memcpy(r_addr, addr, len);
662         idx = ALIGN(len);
663
664         /* Second, place address list */
665         r_addr_list = buffer + idx;
666         ((char**) r_addr_list)[0] = r_addr;
667         ((char**) r_addr_list)[1] = NULL;
668         idx += sizeof(char*) * 2;
669
670         /* Third, reserve space for the aliases array */
671         r_aliases = buffer + idx;
672         idx += sizeof(char*) * c;
673
674         /* Fourth, place aliases */
675         i = 0;
676         r_name = buffer + idx;
677         while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
678                 char *p;
679                 size_t l;
680
681                 l = strlen(n);
682                 p = buffer + idx;
683                 memcpy(p, n, l+1);
684
685                 if (i > 1)
686                         ((char**) r_aliases)[i-1] = p;
687                 i++;
688
689                 idx += ALIGN(l+1);
690         }
691         if (r < 0)
692                 goto fail;
693
694         ((char**) r_aliases)[c-1] = NULL;
695         assert(idx == ms);
696
697         result->h_name = r_name;
698         result->h_aliases = (char**) r_aliases;
699         result->h_addrtype = af;
700         result->h_length = len;
701         result->h_addr_list = (char**) r_addr_list;
702
703         if (ttlp)
704                 *ttlp = 0;
705
706         /* Explicitly reset all error variables */
707         *errnop = 0;
708         *h_errnop = NETDB_SUCCESS;
709         h_errno = 0;
710
711         return NSS_STATUS_SUCCESS;
712
713 fail:
714         *errnop = -r;
715         *h_errnop = NO_DATA;
716         return NSS_STATUS_UNAVAIL;
717 }
718
719 NSS_GETHOSTBYNAME_FALLBACKS(resolve);
720 NSS_GETHOSTBYADDR_FALLBACKS(resolve);