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