Line data Source code
1 : /*
2 : SSSD
3 :
4 : dp_dyndns.c
5 :
6 : Authors:
7 : Stephen Gallagher <sgallagh@redhat.com>
8 : Jakub Hrozek <jhrozek@redhat.com>
9 :
10 : Copyright (C) 2013 Red Hat
11 :
12 : This program is free software; you can redistribute it and/or modify
13 : it under the terms of the GNU General Public License as published by
14 : the Free Software Foundation; either version 3 of the License, or
15 : (at your option) any later version.
16 :
17 : This program is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : GNU General Public License for more details.
21 :
22 : You should have received a copy of the GNU General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include <sys/types.h>
27 : #include <sys/socket.h>
28 : #include <sys/ioctl.h>
29 : #include <arpa/inet.h>
30 : #include <net/if.h>
31 : #include <ifaddrs.h>
32 : #include <ctype.h>
33 : #include "util/util.h"
34 : #include "confdb/confdb.h"
35 : #include "util/child_common.h"
36 : #include "providers/data_provider.h"
37 : #include "providers/dp_backend.h"
38 : #include "providers/dp_dyndns.h"
39 : #include "resolv/async_resolv.h"
40 :
41 : #ifndef DYNDNS_TIMEOUT
42 : #define DYNDNS_TIMEOUT 15
43 : #endif /* DYNDNS_TIMEOUT */
44 :
45 : /* MASK represents special value for matching all interfaces */
46 : #define MASK "*"
47 :
48 : struct sss_iface_addr {
49 : struct sss_iface_addr *next;
50 : struct sss_iface_addr *prev;
51 :
52 : struct sockaddr_storage *addr;
53 : };
54 :
55 : struct sockaddr_storage*
56 4 : sss_iface_addr_get_address(struct sss_iface_addr *address)
57 : {
58 4 : if (address == NULL) {
59 1 : return NULL;
60 : }
61 :
62 3 : return address->addr;
63 : }
64 :
65 4 : struct sss_iface_addr *sss_iface_addr_get_next(struct sss_iface_addr *address)
66 : {
67 4 : if (address) {
68 3 : return address->next;
69 : }
70 :
71 1 : return NULL;
72 : }
73 :
74 0 : void sss_iface_addr_concatenate(struct sss_iface_addr **list,
75 : struct sss_iface_addr *list2)
76 : {
77 0 : DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
78 0 : }
79 :
80 24 : static errno_t addr_to_str(struct sockaddr_storage *addr,
81 : char *dst, size_t size)
82 : {
83 : const void *src;
84 : const char *res;
85 : errno_t ret;
86 :
87 24 : switch(addr->ss_family) {
88 : case AF_INET:
89 12 : src = &(((struct sockaddr_in *)addr)->sin_addr);
90 12 : break;
91 : case AF_INET6:
92 12 : src = &(((struct sockaddr_in6 *)addr)->sin6_addr);
93 12 : break;
94 : default:
95 0 : ret = ERR_ADDR_FAMILY_NOT_SUPPORTED;
96 0 : goto done;
97 : }
98 :
99 24 : res = inet_ntop(addr->ss_family, src, dst, size);
100 24 : if (res == NULL) {
101 0 : ret = errno;
102 0 : DEBUG(SSSDBG_OP_FAILURE, "inet_ntop failed [%d]: %s\n",
103 : ret, sss_strerror(ret));
104 0 : goto done;
105 : }
106 :
107 24 : ret = EOK;
108 :
109 : done:
110 24 : return ret;
111 : }
112 :
113 : errno_t
114 1 : sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
115 : struct sss_iface_addr *ifaddr_list,
116 : char ***_straddrs)
117 : {
118 : struct sss_iface_addr *ifaddr;
119 : size_t count;
120 : int ai;
121 : char **straddrs;
122 : char ip_addr[INET6_ADDRSTRLEN];
123 : errno_t ret;
124 :
125 1 : count = 0;
126 5 : DLIST_FOR_EACH(ifaddr, ifaddr_list) {
127 4 : count++;
128 : }
129 :
130 1 : straddrs = talloc_array(mem_ctx, char *, count+1);
131 1 : if (straddrs == NULL) {
132 0 : return ENOMEM;
133 : }
134 :
135 1 : ai = 0;
136 5 : DLIST_FOR_EACH(ifaddr, ifaddr_list) {
137 :
138 4 : ret = addr_to_str(ifaddr->addr, ip_addr, INET6_ADDRSTRLEN);
139 4 : if (ret == ERR_ADDR_FAMILY_NOT_SUPPORTED) {
140 0 : continue;
141 4 : } else if (ret != EOK) {
142 0 : DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
143 : ret, sss_strerror(ret));
144 0 : goto fail;
145 : }
146 :
147 4 : straddrs[ai] = talloc_strdup(straddrs, ip_addr);
148 4 : if (straddrs[ai] == NULL) {
149 0 : ret = ENOMEM;
150 0 : goto fail;
151 : }
152 4 : ai++;
153 : }
154 :
155 1 : straddrs[count] = NULL;
156 1 : *_straddrs = straddrs;
157 1 : return EOK;
158 :
159 : fail:
160 0 : talloc_free(straddrs);
161 0 : return ret;
162 : }
163 :
164 : static bool
165 25 : ok_for_dns(struct sockaddr *sa)
166 : {
167 : struct sockaddr_in sa4;
168 : struct sockaddr_in6 sa6;
169 :
170 25 : switch (sa->sa_family) {
171 : case AF_INET6:
172 12 : memcpy(&sa6, sa, sizeof(struct sockaddr_in6));
173 12 : return check_ipv6_addr(&sa6.sin6_addr, SSS_NO_SPECIAL);
174 : case AF_INET:
175 13 : memcpy(&sa4, sa, sizeof(struct sockaddr_in));
176 13 : return check_ipv4_addr(&sa4.sin_addr, SSS_NO_SPECIAL);
177 : default:
178 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
179 0 : return false;
180 : }
181 :
182 : return true;
183 : }
184 :
185 32 : static bool supported_address_family(sa_family_t sa_family)
186 : {
187 32 : return sa_family == AF_INET || sa_family == AF_INET6;
188 : }
189 :
190 32 : static bool matching_name(const char *ifname, const char *ifname2)
191 : {
192 32 : return (strcmp(MASK, ifname) == 0) || (strcasecmp(ifname, ifname2) == 0);
193 : }
194 :
195 : /* Collect IP addresses associated with an interface */
196 : errno_t
197 10 : sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
198 : struct sss_iface_addr **_addrlist)
199 : {
200 10 : struct ifaddrs *ifaces = NULL;
201 : struct ifaddrs *ifa;
202 : errno_t ret;
203 : size_t addrsize;
204 : struct sss_iface_addr *address;
205 10 : struct sss_iface_addr *addrlist = NULL;
206 :
207 : /* Get the IP addresses associated with the
208 : * specified interface
209 : */
210 10 : errno = 0;
211 10 : ret = getifaddrs(&ifaces);
212 10 : if (ret == -1) {
213 0 : ret = errno;
214 0 : DEBUG(SSSDBG_OP_FAILURE,
215 : "Could not read interfaces [%d][%s]\n", ret, strerror(ret));
216 0 : goto done;
217 : }
218 :
219 42 : for (ifa = ifaces; ifa != NULL; ifa = ifa->ifa_next) {
220 : /* Some interfaces don't have an ifa_addr */
221 32 : if (!ifa->ifa_addr) continue;
222 :
223 : /* Add IP addresses to the list */
224 32 : if (supported_address_family(ifa->ifa_addr->sa_family)
225 32 : && matching_name(ifname, ifa->ifa_name)
226 25 : && ok_for_dns(ifa->ifa_addr)) {
227 :
228 : /* Add this address to the IP address list */
229 23 : address = talloc_zero(mem_ctx, struct sss_iface_addr);
230 23 : if (!address) {
231 0 : ret = ENOMEM;
232 0 : goto done;
233 : }
234 :
235 46 : addrsize = ifa->ifa_addr->sa_family == AF_INET ? \
236 23 : sizeof(struct sockaddr_in) : \
237 : sizeof(struct sockaddr_in6);
238 :
239 23 : address->addr = talloc_memdup(address, ifa->ifa_addr,
240 : addrsize);
241 23 : if (address->addr == NULL) {
242 0 : ret = ENOMEM;
243 0 : goto done;
244 : }
245 :
246 : /* steal old dlist to the new head */
247 23 : talloc_steal(address, addrlist);
248 23 : DLIST_ADD(addrlist, address);
249 : }
250 : }
251 :
252 10 : if (addrlist != NULL) {
253 : /* OK, some result was found */
254 9 : ret = EOK;
255 9 : *_addrlist = addrlist;
256 : } else {
257 : /* No result was found */
258 1 : DEBUG(SSSDBG_TRACE_FUNC,
259 : "No IPs usable for DNS was found for interface: %s.\n", ifname);
260 1 : ret = ENOENT;
261 : }
262 :
263 : done:
264 10 : freeifaddrs(ifaces);
265 10 : return ret;
266 : }
267 :
268 : static char *
269 9 : nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
270 : const char *hostname, int ttl, uint8_t remove_af)
271 : {
272 : struct sss_iface_addr *new_record;
273 : char ip_addr[INET6_ADDRSTRLEN];
274 : errno_t ret;
275 :
276 : /* A addresses first */
277 : /* Remove existing entries as needed */
278 9 : if (remove_af & DYNDNS_REMOVE_A) {
279 8 : update_msg = talloc_asprintf_append(update_msg,
280 : "update delete %s. in A\n",
281 : hostname);
282 8 : if (update_msg == NULL) {
283 0 : return NULL;
284 : }
285 : }
286 29 : DLIST_FOR_EACH(new_record, addresses) {
287 20 : if (new_record->addr->ss_family == AF_INET) {
288 10 : ret = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
289 10 : if (ret != EOK) {
290 0 : DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
291 : ret, sss_strerror(ret));
292 0 : return NULL;
293 : }
294 :
295 : /* Format the record update */
296 10 : update_msg = talloc_asprintf_append(update_msg,
297 : "update add %s. %d in %s %s\n",
298 : hostname, ttl, "A", ip_addr);
299 10 : if (update_msg == NULL) {
300 0 : return NULL;
301 : }
302 : }
303 : }
304 9 : update_msg = talloc_asprintf_append(update_msg, "send\n");
305 :
306 : /* AAAA addresses next */
307 : /* Remove existing entries as needed */
308 9 : if (remove_af & DYNDNS_REMOVE_AAAA) {
309 8 : update_msg = talloc_asprintf_append(update_msg,
310 : "update delete %s. in AAAA\n",
311 : hostname);
312 8 : if (update_msg == NULL) {
313 0 : return NULL;
314 : }
315 : }
316 29 : DLIST_FOR_EACH(new_record, addresses) {
317 20 : if (new_record->addr->ss_family == AF_INET6) {
318 10 : ret = addr_to_str(new_record->addr, ip_addr, INET6_ADDRSTRLEN);
319 10 : if (ret != EOK) {
320 0 : DEBUG(SSSDBG_MINOR_FAILURE, "addr_to_str failed: %d:[%s],\n",
321 : ret, sss_strerror(ret));
322 0 : return NULL;
323 : }
324 :
325 : /* Format the record update */
326 10 : update_msg = talloc_asprintf_append(update_msg,
327 : "update add %s. %d in %s %s\n",
328 : hostname, ttl, "AAAA", ip_addr);
329 10 : if (update_msg == NULL) {
330 0 : return NULL;
331 : }
332 : }
333 : }
334 :
335 9 : return talloc_asprintf_append(update_msg, "send\n");
336 : }
337 :
338 0 : static uint8_t *nsupdate_convert_address(struct sockaddr_storage *add_address)
339 : {
340 : uint8_t *addr;
341 :
342 0 : switch(add_address->ss_family) {
343 : case AF_INET:
344 0 : addr = (uint8_t *) &((struct sockaddr_in *) add_address)->sin_addr;
345 0 : break;
346 : case AF_INET6:
347 0 : addr = (uint8_t *) &((struct sockaddr_in6 *) add_address)->sin6_addr;
348 0 : break;
349 : default:
350 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
351 0 : addr = NULL;
352 0 : break;
353 : }
354 :
355 0 : return addr;
356 : }
357 :
358 0 : static char *nsupdate_msg_add_ptr(char *update_msg,
359 : struct sockaddr_storage *address,
360 : const char *hostname,
361 : int ttl,
362 : bool delete)
363 : {
364 : char *strptr;
365 : uint8_t *addr;
366 :
367 0 : addr = nsupdate_convert_address(address);
368 0 : if (addr == NULL) {
369 0 : return NULL;
370 : }
371 :
372 0 : strptr = resolv_get_string_ptr_address(update_msg, address->ss_family,
373 : addr);
374 0 : if (strptr == NULL) {
375 0 : return NULL;
376 : }
377 :
378 0 : if (delete) {
379 : /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
380 0 : update_msg = talloc_asprintf_append(update_msg,
381 : "update delete %s in PTR\n"
382 : "send\n",
383 : strptr);
384 : } else {
385 : /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
386 0 : update_msg = talloc_asprintf_append(update_msg,
387 : "update add %s %d in PTR %s.\n"
388 : "send\n",
389 : strptr, ttl, hostname);
390 : }
391 :
392 0 : talloc_free(strptr);
393 0 : if (update_msg == NULL) {
394 0 : return NULL;
395 : }
396 :
397 0 : return update_msg;
398 : }
399 :
400 : static char *
401 9 : nsupdate_msg_add_realm_cmd(TALLOC_CTX *mem_ctx, const char *realm)
402 : {
403 : #ifdef HAVE_NSUPDATE_REALM
404 9 : if (realm != NULL) {
405 2 : return talloc_asprintf(mem_ctx, "realm %s\n", realm);
406 : }
407 : #endif
408 7 : return talloc_asprintf(mem_ctx, "\n");
409 : }
410 :
411 : static char *
412 9 : nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm,
413 : const char *servername)
414 : {
415 : char *realm_directive;
416 : char *update_msg;
417 : TALLOC_CTX *tmp_ctx;
418 :
419 9 : tmp_ctx = talloc_new(NULL);
420 9 : if (tmp_ctx == NULL) return NULL;
421 :
422 9 : realm_directive = nsupdate_msg_add_realm_cmd(tmp_ctx, realm);
423 9 : if (!realm_directive) {
424 0 : goto fail;
425 : }
426 :
427 : /* The realm_directive would now either contain an empty string or be
428 : * completely empty so we don't need to add another newline here
429 : */
430 9 : if (servername) {
431 2 : DEBUG(SSSDBG_FUNC_DATA,
432 : "Creating update message for server [%s] and realm [%s].\n",
433 : servername, realm);
434 :
435 : /* Add the server, realm and headers */
436 2 : update_msg = talloc_asprintf(tmp_ctx, "server %s\n%s",
437 : servername, realm_directive);
438 : } else {
439 7 : DEBUG(SSSDBG_FUNC_DATA,
440 : "Creating update message for realm [%s].\n", realm);
441 : /* Add the realm headers */
442 7 : update_msg = talloc_asprintf(tmp_ctx, "%s", realm_directive);
443 : }
444 9 : talloc_free(realm_directive);
445 9 : if (update_msg == NULL) {
446 0 : goto fail;
447 : }
448 :
449 9 : update_msg = talloc_steal(mem_ctx, update_msg);
450 9 : talloc_free(tmp_ctx);
451 9 : return update_msg;
452 :
453 : fail:
454 0 : talloc_free(tmp_ctx);
455 0 : return NULL;
456 : }
457 :
458 : errno_t
459 9 : be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
460 : const char *servername,
461 : const char *hostname, const unsigned int ttl,
462 : uint8_t remove_af, struct sss_iface_addr *addresses,
463 : char **_update_msg)
464 : {
465 : int ret;
466 : char *update_msg;
467 : TALLOC_CTX *tmp_ctx;
468 :
469 : /* in some cases realm could have been NULL if we weren't using TSIG */
470 9 : if (hostname == NULL) {
471 0 : return EINVAL;
472 : }
473 :
474 9 : tmp_ctx = talloc_new(NULL);
475 9 : if (tmp_ctx == NULL) return ENOMEM;
476 :
477 9 : update_msg = nsupdate_msg_create_common(tmp_ctx, realm, servername);
478 9 : if (update_msg == NULL) {
479 0 : ret = ENOMEM;
480 0 : goto done;
481 : }
482 :
483 9 : update_msg = nsupdate_msg_add_fwd(update_msg, addresses, hostname,
484 : ttl, remove_af);
485 9 : if (update_msg == NULL) {
486 0 : ret = ENOMEM;
487 0 : goto done;
488 : }
489 :
490 9 : DEBUG(SSSDBG_TRACE_FUNC,
491 : " -- Begin nsupdate message -- \n"
492 : "%s"
493 : " -- End nsupdate message -- \n",
494 : update_msg);
495 :
496 9 : ret = ERR_OK;
497 9 : *_update_msg = talloc_steal(mem_ctx, update_msg);
498 : done:
499 9 : talloc_free(tmp_ctx);
500 9 : return ret;
501 : }
502 :
503 : errno_t
504 0 : be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
505 : const char *servername, const char *hostname,
506 : const unsigned int ttl,
507 : struct sockaddr_storage *address,
508 : bool delete,
509 : char **_update_msg)
510 : {
511 : errno_t ret;
512 : char *update_msg;
513 :
514 : /* in some cases realm could have been NULL if we weren't using TSIG */
515 0 : if (hostname == NULL) {
516 0 : return EINVAL;
517 : }
518 :
519 0 : update_msg = nsupdate_msg_create_common(mem_ctx, realm, servername);
520 0 : if (update_msg == NULL) {
521 0 : ret = ENOMEM;
522 0 : goto done;
523 : }
524 :
525 0 : update_msg = nsupdate_msg_add_ptr(update_msg, address, hostname, ttl,
526 : delete);
527 0 : if (update_msg == NULL) {
528 0 : ret = ENOMEM;
529 0 : goto done;
530 : }
531 :
532 0 : DEBUG(SSSDBG_TRACE_FUNC,
533 : " -- Begin nsupdate message -- \n"
534 : "%s"
535 : " -- End nsupdate message -- \n",
536 : update_msg);
537 :
538 0 : ret = ERR_OK;
539 0 : *_update_msg = update_msg;
540 :
541 : done:
542 0 : return ret;
543 : }
544 :
545 : struct nsupdate_get_addrs_state {
546 : struct tevent_context *ev;
547 : struct be_resolv_ctx *be_res;
548 : enum host_database *db;
549 : const char *hostname;
550 :
551 : /* Use sss_addr in this request */
552 : struct sss_iface_addr *addrlist;
553 : size_t count;
554 : };
555 :
556 : static void nsupdate_get_addrs_done(struct tevent_req *subreq);
557 :
558 : struct tevent_req *
559 0 : nsupdate_get_addrs_send(TALLOC_CTX *mem_ctx,
560 : struct tevent_context *ev,
561 : struct be_resolv_ctx *be_res,
562 : const char *hostname)
563 : {
564 : errno_t ret;
565 : struct tevent_req *req;
566 : struct tevent_req *subreq;
567 : struct nsupdate_get_addrs_state *state;
568 :
569 0 : req = tevent_req_create(mem_ctx, &state, struct nsupdate_get_addrs_state);
570 0 : if (req == NULL) {
571 0 : return NULL;
572 : }
573 0 : state->be_res = be_res;
574 0 : state->ev = ev;
575 0 : state->hostname = talloc_strdup(state, hostname);
576 0 : if (state->hostname == NULL) {
577 0 : ret = ENOMEM;
578 0 : goto done;
579 : }
580 :
581 0 : state->db = talloc_array(state, enum host_database, 2);
582 0 : if (state->db == NULL) {
583 0 : ret = ENOMEM;
584 0 : goto done;
585 : }
586 0 : state->db[0] = DB_DNS;
587 0 : state->db[1] = DB_SENTINEL;
588 :
589 0 : subreq = resolv_gethostbyname_send(state, ev, be_res->resolv, hostname,
590 0 : state->be_res->family_order,
591 0 : state->db);
592 0 : if (subreq == NULL) {
593 0 : ret = ENOMEM;
594 0 : goto done;
595 : }
596 0 : tevent_req_set_callback(subreq, nsupdate_get_addrs_done, req);
597 :
598 0 : ret = ERR_OK;
599 : done:
600 0 : if (ret != ERR_OK) {
601 0 : tevent_req_error(req, ret);
602 0 : tevent_req_post(req, ev);
603 : }
604 0 : return req;
605 : }
606 :
607 : static void
608 0 : nsupdate_get_addrs_done(struct tevent_req *subreq)
609 : {
610 : errno_t ret;
611 : size_t count;
612 0 : struct tevent_req *req =
613 0 : tevent_req_callback_data(subreq, struct tevent_req);
614 0 : struct nsupdate_get_addrs_state *state = tevent_req_data(req,
615 : struct nsupdate_get_addrs_state);
616 : struct resolv_hostent *rhostent;
617 : struct sss_iface_addr *addr;
618 : int i;
619 : int resolv_status;
620 : enum restrict_family retry_family_order;
621 :
622 0 : ret = resolv_gethostbyname_recv(subreq, state, &resolv_status, NULL,
623 : &rhostent);
624 0 : talloc_zfree(subreq);
625 :
626 : /* If the retry did not match, simply quit */
627 0 : if (ret == ENOENT) {
628 : /* If the resolver is set to honor both address families
629 : * it automatically retries the other one internally, so ENOENT
630 : * means neither matched and we can simply quit.
631 : */
632 0 : ret = EOK;
633 0 : goto done;
634 0 : } else if (ret != EOK) {
635 0 : DEBUG(SSSDBG_OP_FAILURE,
636 : "Could not resolve address for this machine, error [%d]: %s, "
637 : "resolver returned: [%d]: %s\n", ret, sss_strerror(ret),
638 : resolv_status, resolv_strerror(resolv_status));
639 0 : goto done;
640 : }
641 :
642 : /* EOK */
643 :
644 0 : if (rhostent->addr_list) {
645 0 : for (count=0; rhostent->addr_list[count]; count++);
646 : } else {
647 : /* The address list is NULL. This is probably a bug in
648 : * c-ares, but we need to handle it gracefully.
649 : */
650 0 : DEBUG(SSSDBG_MINOR_FAILURE,
651 : "Lookup of [%s] returned no addresses. Skipping.\n",
652 : rhostent->name);
653 0 : count = 0;
654 : }
655 :
656 0 : for (i=0; i < count; i++) {
657 0 : addr = talloc(state, struct sss_iface_addr);
658 0 : if (addr == NULL) {
659 0 : ret = ENOMEM;
660 0 : goto done;
661 : }
662 :
663 0 : addr->addr = resolv_get_sockaddr_address_index(addr, rhostent, 0, i);
664 0 : if (addr->addr == NULL) {
665 0 : ret = ENOMEM;
666 0 : goto done;
667 : }
668 :
669 0 : if (state->addrlist) {
670 0 : talloc_steal(state->addrlist, addr);
671 : }
672 :
673 : /* steal old dlist to the new head */
674 0 : talloc_steal(addr, state->addrlist);
675 0 : DLIST_ADD(state->addrlist, addr);
676 : }
677 0 : state->count += count;
678 :
679 : /* If the resolver is set to honor both address families
680 : * and the first one matched, retry the second one to
681 : * get the complete list.
682 : */
683 0 : if (((state->be_res->family_order == IPV4_FIRST &&
684 0 : rhostent->family == AF_INET) ||
685 0 : (state->be_res->family_order == IPV6_FIRST &&
686 0 : rhostent->family == AF_INET6))) {
687 :
688 0 : retry_family_order = (state->be_res->family_order == IPV4_FIRST) ? \
689 : IPV6_ONLY : \
690 : IPV4_ONLY;
691 :
692 0 : subreq = resolv_gethostbyname_send(state, state->ev,
693 0 : state->be_res->resolv,
694 : state->hostname,
695 : retry_family_order,
696 : state->db);
697 0 : if (!subreq) {
698 0 : ret = ENOMEM;
699 0 : goto done;
700 : }
701 0 : tevent_req_set_callback(subreq, nsupdate_get_addrs_done, req);
702 0 : return;
703 : }
704 :
705 : /* The second address matched either immediatelly or after a retry.
706 : * No need to retry again. */
707 0 : ret = EOK;
708 :
709 : done:
710 0 : if (ret == EOK) {
711 : /* All done */
712 0 : tevent_req_done(req);
713 0 : } else if (ret != EAGAIN) {
714 0 : DEBUG(SSSDBG_OP_FAILURE,
715 : "nsupdate_get_addrs_done failed: [%d]: [%s]\n",
716 : ret, sss_strerror(ret));
717 0 : tevent_req_error(req, ret);
718 : }
719 : /* EAGAIN - another lookup in progress */
720 : }
721 :
722 : errno_t
723 0 : nsupdate_get_addrs_recv(struct tevent_req *req,
724 : TALLOC_CTX *mem_ctx,
725 : struct sss_iface_addr **_addrlist,
726 : size_t *_count)
727 : {
728 0 : struct nsupdate_get_addrs_state *state = tevent_req_data(req,
729 : struct nsupdate_get_addrs_state);
730 :
731 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
732 :
733 0 : if (_addrlist) {
734 0 : *_addrlist = talloc_steal(mem_ctx, state->addrlist);
735 : }
736 :
737 0 : if (_count) {
738 0 : *_count = state->count;
739 : }
740 :
741 0 : return EOK;
742 : }
743 :
744 : /* Write the nsupdate_msg into the already forked child, wait until
745 : * the child finishes
746 : *
747 : * This is not a typical tevent_req styled request as it ends either after
748 : * a timeout or when the child finishes operation.
749 : */
750 : struct nsupdate_child_state {
751 : int pipefd_to_child;
752 : struct tevent_timer *timeout_handler;
753 : struct sss_child_ctx_old *child_ctx;
754 :
755 : int child_status;
756 : };
757 :
758 : static void
759 : nsupdate_child_timeout(struct tevent_context *ev,
760 : struct tevent_timer *te,
761 : struct timeval tv, void *pvt);
762 : static void
763 : nsupdate_child_handler(int child_status,
764 : struct tevent_signal *sige,
765 : void *pvt);
766 :
767 : static void nsupdate_child_stdin_done(struct tevent_req *subreq);
768 :
769 : static struct tevent_req *
770 3 : nsupdate_child_send(TALLOC_CTX *mem_ctx,
771 : struct tevent_context *ev,
772 : int pipefd_to_child,
773 : pid_t child_pid,
774 : char *child_stdin)
775 : {
776 : errno_t ret;
777 : struct tevent_req *req;
778 : struct tevent_req *subreq;
779 : struct nsupdate_child_state *state;
780 : struct timeval tv;
781 :
782 3 : req = tevent_req_create(mem_ctx, &state, struct nsupdate_child_state);
783 3 : if (req == NULL) {
784 0 : return NULL;
785 : }
786 3 : state->pipefd_to_child = pipefd_to_child;
787 :
788 : /* Set up SIGCHLD handler */
789 3 : ret = child_handler_setup(ev, child_pid, nsupdate_child_handler, req,
790 3 : &state->child_ctx);
791 3 : if (ret != EOK) {
792 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
793 : ret, sss_strerror(ret));
794 0 : ret = ERR_DYNDNS_FAILED;
795 0 : goto done;
796 : }
797 :
798 : /* Set up timeout handler */
799 3 : tv = tevent_timeval_current_ofs(DYNDNS_TIMEOUT, 0);
800 3 : state->timeout_handler = tevent_add_timer(ev, req, tv,
801 : nsupdate_child_timeout, req);
802 3 : if(state->timeout_handler == NULL) {
803 0 : ret = ERR_DYNDNS_FAILED;
804 0 : goto done;
805 : }
806 :
807 : /* Write the update message to the nsupdate child */
808 6 : subreq = write_pipe_send(req, ev,
809 : (uint8_t *) child_stdin,
810 3 : strlen(child_stdin)+1,
811 3 : state->pipefd_to_child);
812 3 : if (subreq == NULL) {
813 0 : ret = ERR_DYNDNS_FAILED;
814 0 : goto done;
815 : }
816 3 : tevent_req_set_callback(subreq, nsupdate_child_stdin_done, req);
817 :
818 3 : ret = EOK;
819 : done:
820 3 : if (ret != EOK) {
821 0 : tevent_req_error(req, ret);
822 0 : tevent_req_post(req, ev);
823 : }
824 3 : return req;
825 : }
826 :
827 : static void
828 1 : nsupdate_child_timeout(struct tevent_context *ev,
829 : struct tevent_timer *te,
830 : struct timeval tv, void *pvt)
831 : {
832 1 : struct tevent_req *req =
833 : talloc_get_type(pvt, struct tevent_req);
834 1 : struct nsupdate_child_state *state =
835 1 : tevent_req_data(req, struct nsupdate_child_state);
836 :
837 1 : DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for dynamic DNS update\n");
838 1 : child_handler_destroy(state->child_ctx);
839 1 : state->child_ctx = NULL;
840 1 : state->child_status = ETIMEDOUT;
841 1 : tevent_req_error(req, ERR_DYNDNS_TIMEOUT);
842 1 : }
843 :
844 : static void
845 3 : nsupdate_child_stdin_done(struct tevent_req *subreq)
846 : {
847 : errno_t ret;
848 3 : struct tevent_req *req =
849 3 : tevent_req_callback_data(subreq, struct tevent_req);
850 3 : struct nsupdate_child_state *state =
851 3 : tevent_req_data(req, struct nsupdate_child_state);
852 :
853 : /* Verify that the buffer was sent, then return
854 : * and wait for the sigchld handler to finish.
855 : */
856 3 : DEBUG(SSSDBG_TRACE_LIBS, "Sending nsupdate data complete\n");
857 :
858 3 : ret = write_pipe_recv(subreq);
859 3 : talloc_zfree(subreq);
860 3 : if (ret != EOK) {
861 0 : DEBUG(SSSDBG_OP_FAILURE, "Sending nsupdate data failed [%d]: %s\n",
862 : ret, sss_strerror(ret));
863 0 : tevent_req_error(req, ERR_DYNDNS_FAILED);
864 0 : return;
865 : }
866 :
867 3 : close(state->pipefd_to_child);
868 3 : state->pipefd_to_child = -1;
869 :
870 : /* Now either wait for the timeout to fire or the child
871 : * to finish
872 : */
873 : }
874 :
875 : static void
876 2 : nsupdate_child_handler(int child_status,
877 : struct tevent_signal *sige,
878 : void *pvt)
879 : {
880 2 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
881 2 : struct nsupdate_child_state *state =
882 2 : tevent_req_data(req, struct nsupdate_child_state);
883 :
884 2 : state->child_status = child_status;
885 :
886 2 : if (WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
887 1 : DEBUG(SSSDBG_OP_FAILURE,
888 : "Dynamic DNS child failed with status [%d]\n", child_status);
889 1 : tevent_req_error(req, ERR_DYNDNS_FAILED);
890 1 : return;
891 : }
892 :
893 1 : if (WIFSIGNALED(child_status)) {
894 0 : DEBUG(SSSDBG_OP_FAILURE,
895 : "Dynamic DNS child was terminated by signal [%d]\n",
896 : WTERMSIG(child_status));
897 0 : tevent_req_error(req, ERR_DYNDNS_FAILED);
898 0 : return;
899 : }
900 :
901 1 : tevent_req_done(req);
902 : }
903 :
904 : static errno_t
905 3 : nsupdate_child_recv(struct tevent_req *req, int *child_status)
906 : {
907 3 : struct nsupdate_child_state *state =
908 3 : tevent_req_data(req, struct nsupdate_child_state);
909 :
910 3 : *child_status = state->child_status;
911 :
912 5 : TEVENT_REQ_RETURN_ON_ERROR(req);
913 :
914 1 : return ERR_OK;
915 : }
916 :
917 : /* Fork a nsupdate child, write the nsupdate_msg into stdin and wait for the child
918 : * to finish one way or another
919 : */
920 : struct be_nsupdate_state {
921 : int child_status;
922 : };
923 :
924 : static void be_nsupdate_done(struct tevent_req *subreq);
925 : static char **be_nsupdate_args(TALLOC_CTX *mem_ctx,
926 : enum be_nsupdate_auth auth_type,
927 : bool force_tcp);
928 :
929 3 : struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
930 : struct tevent_context *ev,
931 : enum be_nsupdate_auth auth_type,
932 : char *nsupdate_msg,
933 : bool force_tcp)
934 : {
935 : int pipefd_to_child[2];
936 : pid_t child_pid;
937 : errno_t ret;
938 3 : struct tevent_req *req = NULL;
939 3 : struct tevent_req *subreq = NULL;
940 : struct be_nsupdate_state *state;
941 : char **args;
942 : int debug_fd;
943 :
944 3 : req = tevent_req_create(mem_ctx, &state, struct be_nsupdate_state);
945 3 : if (req == NULL) {
946 0 : return NULL;
947 : }
948 3 : state->child_status = 0;
949 :
950 3 : ret = pipe(pipefd_to_child);
951 3 : if (ret == -1) {
952 0 : ret = errno;
953 0 : DEBUG(SSSDBG_CRIT_FAILURE,
954 : "pipe failed [%d][%s].\n", ret, strerror(ret));
955 0 : goto done;
956 : }
957 :
958 3 : child_pid = fork();
959 :
960 6 : if (child_pid == 0) { /* child */
961 3 : close(pipefd_to_child[1]);
962 3 : ret = dup2(pipefd_to_child[0], STDIN_FILENO);
963 3 : if (ret == -1) {
964 0 : ret = errno;
965 0 : DEBUG(SSSDBG_CRIT_FAILURE,
966 : "dup2 failed [%d][%s].\n", ret, strerror(ret));
967 0 : goto done;
968 : }
969 :
970 3 : if (debug_level >= SSSDBG_TRACE_LIBS) {
971 0 : debug_fd = get_fd_from_debug_file();
972 0 : ret = dup2(debug_fd, STDERR_FILENO);
973 0 : if (ret == -1) {
974 0 : ret = errno;
975 0 : DEBUG(SSSDBG_MINOR_FAILURE,
976 : "dup2 failed [%d][%s].\n", ret, strerror(ret));
977 : /* stderr is not fatal */
978 : }
979 : }
980 :
981 3 : args = be_nsupdate_args(state, auth_type, force_tcp);
982 3 : if (args == NULL) {
983 0 : ret = ENOMEM;
984 0 : goto done;
985 : }
986 :
987 3 : errno = 0;
988 3 : execv(NSUPDATE_PATH, args);
989 : /* The child should never end up here */
990 3 : ret = errno;
991 0 : DEBUG(SSSDBG_CRIT_FAILURE, "execv failed [%d][%s].\n", ret, strerror(ret));
992 0 : goto done;
993 3 : } else if (child_pid > 0) { /* parent */
994 3 : close(pipefd_to_child[0]);
995 :
996 3 : subreq = nsupdate_child_send(state, ev, pipefd_to_child[1],
997 : child_pid, nsupdate_msg);
998 3 : if (subreq == NULL) {
999 0 : ret = ERR_DYNDNS_FAILED;
1000 0 : goto done;
1001 : }
1002 3 : tevent_req_set_callback(subreq, be_nsupdate_done, req);
1003 : } else { /* error */
1004 0 : ret = errno;
1005 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1006 : "fork failed [%d][%s].\n", ret, strerror(ret));
1007 0 : goto done;
1008 : }
1009 :
1010 3 : ret = EOK;
1011 : done:
1012 3 : if (ret != EOK) {
1013 0 : tevent_req_error(req, ret);
1014 0 : tevent_req_post(req, ev);
1015 : }
1016 3 : return req;
1017 : }
1018 :
1019 : static char **
1020 3 : be_nsupdate_args(TALLOC_CTX *mem_ctx,
1021 : enum be_nsupdate_auth auth_type,
1022 : bool force_tcp)
1023 : {
1024 : char **argv;
1025 3 : int argc = 0;
1026 :
1027 3 : argv = talloc_zero_array(mem_ctx, char *, 6);
1028 3 : if (argv == NULL) {
1029 0 : return NULL;
1030 : }
1031 :
1032 3 : argv[argc] = talloc_strdup(argv, NSUPDATE_PATH);
1033 3 : if (argv[argc] == NULL) {
1034 0 : goto fail;
1035 : }
1036 3 : argc++;
1037 :
1038 3 : switch (auth_type) {
1039 : case BE_NSUPDATE_AUTH_NONE:
1040 0 : DEBUG(SSSDBG_FUNC_DATA, "nsupdate auth type: none\n");
1041 0 : break;
1042 : case BE_NSUPDATE_AUTH_GSS_TSIG:
1043 3 : DEBUG(SSSDBG_FUNC_DATA, "nsupdate auth type: GSS-TSIG\n");
1044 3 : argv[argc] = talloc_strdup(argv, "-g");
1045 3 : if (argv[argc] == NULL) {
1046 0 : goto fail;
1047 : }
1048 3 : argc++;
1049 3 : break;
1050 : default:
1051 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown nsupdate auth type\n");
1052 0 : goto fail;
1053 : }
1054 :
1055 3 : if (force_tcp) {
1056 0 : DEBUG(SSSDBG_FUNC_DATA, "TCP is set to on\n");
1057 0 : argv[argc] = talloc_strdup(argv, "-v");
1058 0 : if (argv[argc] == NULL) {
1059 0 : goto fail;
1060 : }
1061 0 : argc++;
1062 : }
1063 :
1064 3 : if (debug_level >= SSSDBG_TRACE_LIBS) {
1065 0 : argv[argc] = talloc_strdup(argv, "-d");
1066 0 : if (argv[argc] == NULL) {
1067 0 : goto fail;
1068 : }
1069 0 : argc++;
1070 : }
1071 :
1072 3 : if (debug_level >= SSSDBG_TRACE_INTERNAL) {
1073 0 : argv[argc] = talloc_strdup(argv, "-D");
1074 0 : if (argv[argc] == NULL) {
1075 0 : goto fail;
1076 : }
1077 0 : argc++;
1078 : }
1079 :
1080 3 : return argv;
1081 :
1082 : fail:
1083 0 : talloc_free(argv);
1084 0 : return NULL;
1085 : }
1086 :
1087 : static void
1088 3 : be_nsupdate_done(struct tevent_req *subreq)
1089 : {
1090 3 : struct tevent_req *req =
1091 3 : tevent_req_callback_data(subreq, struct tevent_req);
1092 3 : struct be_nsupdate_state *state =
1093 3 : tevent_req_data(req, struct be_nsupdate_state);
1094 : errno_t ret;
1095 :
1096 3 : ret = nsupdate_child_recv(subreq, &state->child_status);
1097 3 : talloc_zfree(subreq);
1098 3 : if (ret != EOK) {
1099 2 : DEBUG(SSSDBG_OP_FAILURE, "nsupdate child execution failed [%d]: %s\n",
1100 : ret, sss_strerror(ret));
1101 2 : tevent_req_error(req, ret);
1102 2 : return;
1103 : }
1104 :
1105 1 : DEBUG(SSSDBG_FUNC_DATA,
1106 : "nsupdate child status: %d\n", state->child_status);
1107 1 : tevent_req_done(req);
1108 : }
1109 :
1110 : errno_t
1111 3 : be_nsupdate_recv(struct tevent_req *req, int *child_status)
1112 : {
1113 3 : struct be_nsupdate_state *state =
1114 3 : tevent_req_data(req, struct be_nsupdate_state);
1115 :
1116 3 : *child_status = state->child_status;
1117 :
1118 5 : TEVENT_REQ_RETURN_ON_ERROR(req);
1119 :
1120 1 : return EOK;
1121 : }
1122 :
1123 2 : static void be_nsupdate_timer(struct tevent_context *ev,
1124 : struct tevent_timer *te,
1125 : struct timeval current_time,
1126 : void *pvt)
1127 : {
1128 2 : struct be_nsupdate_ctx *ctx = talloc_get_type(pvt, struct be_nsupdate_ctx);
1129 :
1130 2 : talloc_zfree(ctx->refresh_timer);
1131 2 : ctx->timer_callback(ctx->timer_pvt);
1132 :
1133 : /* timer_callback is responsible for calling be_nsupdate_timer_schedule
1134 : * again */
1135 2 : }
1136 :
1137 2 : void be_nsupdate_timer_schedule(struct tevent_context *ev,
1138 : struct be_nsupdate_ctx *ctx)
1139 : {
1140 : int refresh;
1141 : struct timeval tv;
1142 :
1143 2 : if (ctx->refresh_timer) {
1144 0 : DEBUG(SSSDBG_FUNC_DATA, "Timer already scheduled\n");
1145 0 : return;
1146 : }
1147 :
1148 2 : refresh = dp_opt_get_int(ctx->opts, DP_OPT_DYNDNS_REFRESH_INTERVAL);
1149 2 : if (refresh == 0) return;
1150 2 : DEBUG(SSSDBG_FUNC_DATA, "Scheduling timer in %d seconds\n", refresh);
1151 :
1152 2 : tv = tevent_timeval_current_ofs(refresh, 0);
1153 2 : ctx->refresh_timer = tevent_add_timer(ev, ctx, tv,
1154 : be_nsupdate_timer, ctx);
1155 :
1156 2 : if (!ctx->refresh_timer) {
1157 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1158 : "Failed to add dyndns refresh timer event\n");
1159 : }
1160 : }
1161 :
1162 : errno_t
1163 0 : be_nsupdate_check(void)
1164 : {
1165 : errno_t ret;
1166 : struct stat stat_buf;
1167 :
1168 : /* Ensure that nsupdate exists */
1169 0 : errno = 0;
1170 0 : ret = stat(NSUPDATE_PATH, &stat_buf);
1171 0 : if (ret == -1) {
1172 0 : ret = errno;
1173 0 : if (ret == ENOENT) {
1174 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1175 : "%s does not exist. Dynamic DNS updates disabled\n",
1176 : NSUPDATE_PATH);
1177 : } else {
1178 0 : DEBUG(SSSDBG_OP_FAILURE,
1179 : "Could not set up dynamic DNS updates: [%d][%s]\n",
1180 : ret, strerror(ret));
1181 : }
1182 : }
1183 :
1184 0 : return ret;
1185 : }
1186 :
1187 : static struct dp_option default_dyndns_opts[] = {
1188 : { "dyndns_update", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
1189 : { "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
1190 : { "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING },
1191 : { "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER },
1192 : { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE },
1193 : { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
1194 : { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
1195 : { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
1196 :
1197 : DP_OPTION_TERMINATOR
1198 : };
1199 :
1200 : errno_t
1201 1 : be_nsupdate_init(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
1202 : struct dp_option *defopts,
1203 : struct be_nsupdate_ctx **_ctx)
1204 : {
1205 : errno_t ret;
1206 : struct dp_option *src_opts;
1207 : struct be_nsupdate_ctx *ctx;
1208 : char *strauth;
1209 :
1210 1 : ctx = talloc_zero(mem_ctx, struct be_nsupdate_ctx);
1211 1 : if (ctx == NULL) return ENOMEM;
1212 :
1213 1 : src_opts = defopts ? defopts : default_dyndns_opts;
1214 :
1215 1 : ret = dp_get_options(ctx, be_ctx->cdb, be_ctx->conf_path,
1216 : src_opts, DP_OPT_DYNDNS, &ctx->opts);
1217 1 : if (ret != EOK) {
1218 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve dynamic DNS options\n");
1219 0 : return ret;
1220 : }
1221 :
1222 1 : strauth = dp_opt_get_string(ctx->opts, DP_OPT_DYNDNS_AUTH);
1223 1 : if (strcasecmp(strauth, "gss-tsig") == 0) {
1224 1 : ctx->auth_type = BE_NSUPDATE_AUTH_GSS_TSIG;
1225 0 : } else if (strcasecmp(strauth, "none") == 0) {
1226 0 : ctx->auth_type = BE_NSUPDATE_AUTH_NONE;
1227 : } else {
1228 0 : DEBUG(SSSDBG_OP_FAILURE, "Uknown dyndns auth type %s\n", strauth);
1229 0 : return EINVAL;
1230 : }
1231 :
1232 1 : *_ctx = ctx;
1233 1 : return ERR_OK;
1234 : }
1235 :
1236 1 : errno_t be_nsupdate_init_timer(struct be_nsupdate_ctx *ctx,
1237 : struct tevent_context *ev,
1238 : nsupdate_timer_fn_t timer_callback,
1239 : void *timer_pvt)
1240 : {
1241 1 : if (ctx == NULL) return EINVAL;
1242 :
1243 1 : ctx->timer_callback = timer_callback;
1244 1 : ctx->timer_pvt = timer_pvt;
1245 1 : be_nsupdate_timer_schedule(ev, ctx);
1246 :
1247 1 : return ERR_OK;
1248 : }
1249 :
1250 10 : static bool match_ip(const struct sockaddr *sa,
1251 : const struct sockaddr *sb)
1252 : {
1253 : size_t addrsize;
1254 : bool res;
1255 : const void *addr_a;
1256 : const void *addr_b;
1257 :
1258 10 : if (sa->sa_family == AF_INET) {
1259 9 : addrsize = sizeof(struct in_addr);
1260 9 : addr_a = (const void *) &((const struct sockaddr_in *) sa)->sin_addr;
1261 9 : addr_b = (const void *) &((const struct sockaddr_in *) sb)->sin_addr;
1262 1 : } else if (sa->sa_family == AF_INET6) {
1263 1 : addrsize = sizeof(struct in6_addr);
1264 1 : addr_a = (const void *) &((const struct sockaddr_in6 *) sa)->sin6_addr;
1265 1 : addr_b = (const void *) &((const struct sockaddr_in6 *) sb)->sin6_addr;
1266 : } else {
1267 0 : res = false;
1268 0 : goto done;
1269 : }
1270 :
1271 10 : if (sa->sa_family != sb->sa_family) {
1272 2 : res = false;
1273 2 : goto done;
1274 : }
1275 :
1276 8 : res = memcmp(addr_a, addr_b, addrsize) == 0;
1277 :
1278 : done:
1279 10 : return res;
1280 : }
1281 :
1282 7 : static errno_t find_iface_by_addr(TALLOC_CTX *mem_ctx,
1283 : const struct sockaddr *ss,
1284 : const char **_iface_name)
1285 : {
1286 7 : struct ifaddrs *ifaces = NULL;
1287 : struct ifaddrs *ifa;
1288 : errno_t ret;
1289 :
1290 7 : ret = getifaddrs(&ifaces);
1291 7 : if (ret == -1) {
1292 0 : ret = errno;
1293 0 : DEBUG(SSSDBG_OP_FAILURE,
1294 : "Could not read interfaces [%d][%s]\n", ret, sss_strerror(ret));
1295 0 : goto done;
1296 : }
1297 :
1298 11 : for (ifa = ifaces; ifa != NULL; ifa = ifa->ifa_next) {
1299 :
1300 : /* Some interfaces don't have an ifa_addr */
1301 10 : if (!ifa->ifa_addr) continue;
1302 :
1303 10 : if (match_ip(ss, ifa->ifa_addr)) {
1304 : const char *iface_name;
1305 6 : iface_name = talloc_strdup(mem_ctx, ifa->ifa_name);
1306 6 : if (iface_name == NULL) {
1307 0 : ret = ENOMEM;
1308 : } else {
1309 6 : *_iface_name = iface_name;
1310 6 : ret = EOK;
1311 : }
1312 6 : goto done;
1313 : }
1314 : }
1315 1 : ret = ENOENT;
1316 :
1317 : done:
1318 7 : freeifaddrs(ifaces);
1319 7 : return ret;
1320 : }
1321 :
1322 7 : errno_t sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
1323 : struct sockaddr *ss,
1324 : struct sss_iface_addr **_iface_addrs)
1325 : {
1326 : struct sss_iface_addr *iface_addrs;
1327 7 : const char *iface_name = NULL;
1328 : TALLOC_CTX *tmp_ctx;
1329 : errno_t ret;
1330 :
1331 7 : tmp_ctx = talloc_new(NULL);
1332 7 : if (tmp_ctx == NULL) {
1333 0 : ret = ENOMEM;
1334 0 : goto done;
1335 : }
1336 :
1337 7 : ret = find_iface_by_addr(tmp_ctx, ss, &iface_name);
1338 7 : if (ret != EOK) {
1339 1 : DEBUG(SSSDBG_MINOR_FAILURE, "find_iface_by_addr failed: %d:[%s]\n",
1340 : ret, sss_strerror(ret));
1341 1 : goto done;
1342 : }
1343 :
1344 6 : ret = sss_iface_addr_list_get(tmp_ctx, iface_name, &iface_addrs);
1345 6 : if (ret != EOK) {
1346 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1347 : "sss_iface_addr_list_get failed: %d:[%s]\n",
1348 : ret, sss_strerror(ret));
1349 0 : goto done;
1350 : }
1351 :
1352 6 : ret = EOK;
1353 6 : *_iface_addrs = talloc_steal(mem_ctx, iface_addrs);
1354 :
1355 : done:
1356 7 : talloc_free(tmp_ctx);
1357 7 : return ret;
1358 : }
|