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/backend.h"
38 : #include "providers/be_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 : close(pipefd_to_child);
785 0 : return NULL;
786 : }
787 3 : state->pipefd_to_child = pipefd_to_child;
788 :
789 : /* Set up SIGCHLD handler */
790 3 : ret = child_handler_setup(ev, child_pid, nsupdate_child_handler, req,
791 3 : &state->child_ctx);
792 3 : if (ret != EOK) {
793 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
794 : ret, sss_strerror(ret));
795 0 : ret = ERR_DYNDNS_FAILED;
796 0 : goto done;
797 : }
798 :
799 : /* Set up timeout handler */
800 3 : tv = tevent_timeval_current_ofs(DYNDNS_TIMEOUT, 0);
801 3 : state->timeout_handler = tevent_add_timer(ev, req, tv,
802 : nsupdate_child_timeout, req);
803 3 : if(state->timeout_handler == NULL) {
804 0 : ret = ERR_DYNDNS_FAILED;
805 0 : goto done;
806 : }
807 :
808 : /* Write the update message to the nsupdate child */
809 6 : subreq = write_pipe_send(req, ev,
810 : (uint8_t *) child_stdin,
811 3 : strlen(child_stdin)+1,
812 3 : state->pipefd_to_child);
813 3 : if (subreq == NULL) {
814 0 : ret = ERR_DYNDNS_FAILED;
815 0 : goto done;
816 : }
817 3 : tevent_req_set_callback(subreq, nsupdate_child_stdin_done, req);
818 :
819 3 : ret = EOK;
820 : done:
821 3 : if (ret != EOK) {
822 0 : tevent_req_error(req, ret);
823 0 : tevent_req_post(req, ev);
824 : }
825 3 : return req;
826 : }
827 :
828 : static void
829 1 : nsupdate_child_timeout(struct tevent_context *ev,
830 : struct tevent_timer *te,
831 : struct timeval tv, void *pvt)
832 : {
833 1 : struct tevent_req *req =
834 : talloc_get_type(pvt, struct tevent_req);
835 1 : struct nsupdate_child_state *state =
836 1 : tevent_req_data(req, struct nsupdate_child_state);
837 :
838 1 : DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for dynamic DNS update\n");
839 1 : child_handler_destroy(state->child_ctx);
840 1 : state->child_ctx = NULL;
841 1 : state->child_status = ETIMEDOUT;
842 1 : tevent_req_error(req, ERR_DYNDNS_TIMEOUT);
843 1 : }
844 :
845 : static void
846 3 : nsupdate_child_stdin_done(struct tevent_req *subreq)
847 : {
848 : errno_t ret;
849 3 : struct tevent_req *req =
850 3 : tevent_req_callback_data(subreq, struct tevent_req);
851 3 : struct nsupdate_child_state *state =
852 3 : tevent_req_data(req, struct nsupdate_child_state);
853 :
854 : /* Verify that the buffer was sent, then return
855 : * and wait for the sigchld handler to finish.
856 : */
857 3 : DEBUG(SSSDBG_TRACE_LIBS, "Sending nsupdate data complete\n");
858 :
859 3 : ret = write_pipe_recv(subreq);
860 3 : talloc_zfree(subreq);
861 3 : if (ret != EOK) {
862 0 : DEBUG(SSSDBG_OP_FAILURE, "Sending nsupdate data failed [%d]: %s\n",
863 : ret, sss_strerror(ret));
864 0 : tevent_req_error(req, ERR_DYNDNS_FAILED);
865 3 : return;
866 : }
867 :
868 3 : PIPE_FD_CLOSE(state->pipefd_to_child);
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 3 : PIPE_FD_CLOSE(state->pipefd_to_child);
913 :
914 5 : TEVENT_REQ_RETURN_ON_ERROR(req);
915 :
916 1 : return ERR_OK;
917 : }
918 :
919 : /* Fork a nsupdate child, write the nsupdate_msg into stdin and wait for the child
920 : * to finish one way or another
921 : */
922 : struct be_nsupdate_state {
923 : int child_status;
924 : };
925 :
926 : static void be_nsupdate_done(struct tevent_req *subreq);
927 : static char **be_nsupdate_args(TALLOC_CTX *mem_ctx,
928 : enum be_nsupdate_auth auth_type,
929 : bool force_tcp);
930 :
931 3 : struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
932 : struct tevent_context *ev,
933 : enum be_nsupdate_auth auth_type,
934 : char *nsupdate_msg,
935 : bool force_tcp)
936 : {
937 3 : int pipefd_to_child[2] = PIPE_INIT;
938 : pid_t child_pid;
939 : errno_t ret;
940 3 : struct tevent_req *req = NULL;
941 3 : struct tevent_req *subreq = NULL;
942 : struct be_nsupdate_state *state;
943 : char **args;
944 : int debug_fd;
945 :
946 3 : req = tevent_req_create(mem_ctx, &state, struct be_nsupdate_state);
947 3 : if (req == NULL) {
948 0 : return NULL;
949 : }
950 3 : state->child_status = 0;
951 :
952 3 : ret = pipe(pipefd_to_child);
953 3 : if (ret == -1) {
954 0 : ret = errno;
955 0 : DEBUG(SSSDBG_CRIT_FAILURE,
956 : "pipe failed [%d][%s].\n", ret, strerror(ret));
957 0 : goto done;
958 : }
959 :
960 3 : child_pid = fork();
961 :
962 3 : if (child_pid == 0) { /* child */
963 0 : PIPE_FD_CLOSE(pipefd_to_child[1]);
964 0 : ret = dup2(pipefd_to_child[0], STDIN_FILENO);
965 0 : if (ret == -1) {
966 0 : ret = errno;
967 0 : DEBUG(SSSDBG_CRIT_FAILURE,
968 : "dup2 failed [%d][%s].\n", ret, strerror(ret));
969 0 : goto done;
970 : }
971 :
972 0 : if (debug_level >= SSSDBG_TRACE_LIBS) {
973 0 : debug_fd = get_fd_from_debug_file();
974 0 : ret = dup2(debug_fd, STDERR_FILENO);
975 0 : if (ret == -1) {
976 0 : ret = errno;
977 0 : DEBUG(SSSDBG_MINOR_FAILURE,
978 : "dup2 failed [%d][%s].\n", ret, strerror(ret));
979 : /* stderr is not fatal */
980 : }
981 : }
982 :
983 0 : args = be_nsupdate_args(state, auth_type, force_tcp);
984 0 : if (args == NULL) {
985 0 : ret = ENOMEM;
986 0 : goto done;
987 : }
988 :
989 0 : errno = 0;
990 0 : execv(NSUPDATE_PATH, args);
991 : /* The child should never end up here */
992 0 : ret = errno;
993 0 : DEBUG(SSSDBG_CRIT_FAILURE, "execv failed [%d][%s].\n", ret, strerror(ret));
994 0 : goto done;
995 3 : } else if (child_pid > 0) { /* parent */
996 3 : PIPE_FD_CLOSE(pipefd_to_child[0]);
997 :
998 : /* the nsupdate_child request now owns the pipefd and is responsible
999 : * for closing it
1000 : */
1001 3 : subreq = nsupdate_child_send(state, ev, pipefd_to_child[1],
1002 : child_pid, nsupdate_msg);
1003 3 : if (subreq == NULL) {
1004 0 : ret = ERR_DYNDNS_FAILED;
1005 0 : goto done;
1006 : }
1007 3 : tevent_req_set_callback(subreq, be_nsupdate_done, req);
1008 : } else { /* error */
1009 0 : ret = errno;
1010 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1011 : "fork failed [%d][%s].\n", ret, strerror(ret));
1012 0 : goto done;
1013 : }
1014 :
1015 3 : ret = EOK;
1016 : done:
1017 3 : if (ret != EOK) {
1018 0 : PIPE_CLOSE(pipefd_to_child);
1019 0 : tevent_req_error(req, ret);
1020 0 : tevent_req_post(req, ev);
1021 : }
1022 3 : return req;
1023 : }
1024 :
1025 : static char **
1026 0 : be_nsupdate_args(TALLOC_CTX *mem_ctx,
1027 : enum be_nsupdate_auth auth_type,
1028 : bool force_tcp)
1029 : {
1030 : char **argv;
1031 0 : int argc = 0;
1032 :
1033 0 : argv = talloc_zero_array(mem_ctx, char *, 6);
1034 0 : if (argv == NULL) {
1035 0 : return NULL;
1036 : }
1037 :
1038 0 : argv[argc] = talloc_strdup(argv, NSUPDATE_PATH);
1039 0 : if (argv[argc] == NULL) {
1040 0 : goto fail;
1041 : }
1042 0 : argc++;
1043 :
1044 0 : switch (auth_type) {
1045 : case BE_NSUPDATE_AUTH_NONE:
1046 0 : DEBUG(SSSDBG_FUNC_DATA, "nsupdate auth type: none\n");
1047 0 : break;
1048 : case BE_NSUPDATE_AUTH_GSS_TSIG:
1049 0 : DEBUG(SSSDBG_FUNC_DATA, "nsupdate auth type: GSS-TSIG\n");
1050 0 : argv[argc] = talloc_strdup(argv, "-g");
1051 0 : if (argv[argc] == NULL) {
1052 0 : goto fail;
1053 : }
1054 0 : argc++;
1055 0 : break;
1056 : default:
1057 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown nsupdate auth type\n");
1058 0 : goto fail;
1059 : }
1060 :
1061 0 : if (force_tcp) {
1062 0 : DEBUG(SSSDBG_FUNC_DATA, "TCP is set to on\n");
1063 0 : argv[argc] = talloc_strdup(argv, "-v");
1064 0 : if (argv[argc] == NULL) {
1065 0 : goto fail;
1066 : }
1067 0 : argc++;
1068 : }
1069 :
1070 0 : if (debug_level >= SSSDBG_TRACE_LIBS) {
1071 0 : argv[argc] = talloc_strdup(argv, "-d");
1072 0 : if (argv[argc] == NULL) {
1073 0 : goto fail;
1074 : }
1075 0 : argc++;
1076 : }
1077 :
1078 0 : if (debug_level >= SSSDBG_TRACE_INTERNAL) {
1079 0 : argv[argc] = talloc_strdup(argv, "-D");
1080 0 : if (argv[argc] == NULL) {
1081 0 : goto fail;
1082 : }
1083 0 : argc++;
1084 : }
1085 :
1086 0 : return argv;
1087 :
1088 : fail:
1089 0 : talloc_free(argv);
1090 0 : return NULL;
1091 : }
1092 :
1093 : static void
1094 3 : be_nsupdate_done(struct tevent_req *subreq)
1095 : {
1096 3 : struct tevent_req *req =
1097 3 : tevent_req_callback_data(subreq, struct tevent_req);
1098 3 : struct be_nsupdate_state *state =
1099 3 : tevent_req_data(req, struct be_nsupdate_state);
1100 : errno_t ret;
1101 :
1102 3 : ret = nsupdate_child_recv(subreq, &state->child_status);
1103 3 : talloc_zfree(subreq);
1104 3 : if (ret != EOK) {
1105 2 : DEBUG(SSSDBG_OP_FAILURE, "nsupdate child execution failed [%d]: %s\n",
1106 : ret, sss_strerror(ret));
1107 2 : tevent_req_error(req, ret);
1108 5 : return;
1109 : }
1110 :
1111 1 : DEBUG(SSSDBG_FUNC_DATA,
1112 : "nsupdate child status: %d\n", state->child_status);
1113 1 : tevent_req_done(req);
1114 : }
1115 :
1116 : errno_t
1117 3 : be_nsupdate_recv(struct tevent_req *req, int *child_status)
1118 : {
1119 3 : struct be_nsupdate_state *state =
1120 3 : tevent_req_data(req, struct be_nsupdate_state);
1121 :
1122 3 : *child_status = state->child_status;
1123 :
1124 5 : TEVENT_REQ_RETURN_ON_ERROR(req);
1125 :
1126 1 : return EOK;
1127 : }
1128 :
1129 2 : static void be_nsupdate_timer(struct tevent_context *ev,
1130 : struct tevent_timer *te,
1131 : struct timeval current_time,
1132 : void *pvt)
1133 : {
1134 2 : struct be_nsupdate_ctx *ctx = talloc_get_type(pvt, struct be_nsupdate_ctx);
1135 :
1136 2 : talloc_zfree(ctx->refresh_timer);
1137 2 : ctx->timer_callback(ctx->timer_pvt);
1138 :
1139 : /* timer_callback is responsible for calling be_nsupdate_timer_schedule
1140 : * again */
1141 2 : }
1142 :
1143 2 : void be_nsupdate_timer_schedule(struct tevent_context *ev,
1144 : struct be_nsupdate_ctx *ctx)
1145 : {
1146 : int refresh;
1147 : struct timeval tv;
1148 :
1149 2 : if (ctx->refresh_timer) {
1150 0 : DEBUG(SSSDBG_FUNC_DATA, "Timer already scheduled\n");
1151 0 : return;
1152 : }
1153 :
1154 2 : refresh = dp_opt_get_int(ctx->opts, DP_OPT_DYNDNS_REFRESH_INTERVAL);
1155 2 : if (refresh == 0) return;
1156 2 : DEBUG(SSSDBG_FUNC_DATA, "Scheduling timer in %d seconds\n", refresh);
1157 :
1158 2 : tv = tevent_timeval_current_ofs(refresh, 0);
1159 2 : ctx->refresh_timer = tevent_add_timer(ev, ctx, tv,
1160 : be_nsupdate_timer, ctx);
1161 :
1162 2 : if (!ctx->refresh_timer) {
1163 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1164 : "Failed to add dyndns refresh timer event\n");
1165 : }
1166 : }
1167 :
1168 : errno_t
1169 0 : be_nsupdate_check(void)
1170 : {
1171 : errno_t ret;
1172 : struct stat stat_buf;
1173 :
1174 : /* Ensure that nsupdate exists */
1175 0 : errno = 0;
1176 0 : ret = stat(NSUPDATE_PATH, &stat_buf);
1177 0 : if (ret == -1) {
1178 0 : ret = errno;
1179 0 : if (ret == ENOENT) {
1180 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1181 : "%s does not exist. Dynamic DNS updates disabled\n",
1182 : NSUPDATE_PATH);
1183 : } else {
1184 0 : DEBUG(SSSDBG_OP_FAILURE,
1185 : "Could not set up dynamic DNS updates: [%d][%s]\n",
1186 : ret, strerror(ret));
1187 : }
1188 : }
1189 :
1190 0 : return ret;
1191 : }
1192 :
1193 : static struct dp_option default_dyndns_opts[] = {
1194 : { "dyndns_update", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
1195 : { "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
1196 : { "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING },
1197 : { "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER },
1198 : { "dyndns_update_ptr", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE },
1199 : { "dyndns_force_tcp", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
1200 : { "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
1201 : { "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
1202 :
1203 : DP_OPTION_TERMINATOR
1204 : };
1205 :
1206 : errno_t
1207 1 : be_nsupdate_init(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
1208 : struct dp_option *defopts,
1209 : struct be_nsupdate_ctx **_ctx)
1210 : {
1211 : errno_t ret;
1212 : struct dp_option *src_opts;
1213 : struct be_nsupdate_ctx *ctx;
1214 : char *strauth;
1215 :
1216 1 : ctx = talloc_zero(mem_ctx, struct be_nsupdate_ctx);
1217 1 : if (ctx == NULL) return ENOMEM;
1218 :
1219 1 : src_opts = defopts ? defopts : default_dyndns_opts;
1220 :
1221 1 : ret = dp_get_options(ctx, be_ctx->cdb, be_ctx->conf_path,
1222 : src_opts, DP_OPT_DYNDNS, &ctx->opts);
1223 1 : if (ret != EOK) {
1224 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve dynamic DNS options\n");
1225 0 : return ret;
1226 : }
1227 :
1228 1 : strauth = dp_opt_get_string(ctx->opts, DP_OPT_DYNDNS_AUTH);
1229 1 : if (strcasecmp(strauth, "gss-tsig") == 0) {
1230 1 : ctx->auth_type = BE_NSUPDATE_AUTH_GSS_TSIG;
1231 0 : } else if (strcasecmp(strauth, "none") == 0) {
1232 0 : ctx->auth_type = BE_NSUPDATE_AUTH_NONE;
1233 : } else {
1234 0 : DEBUG(SSSDBG_OP_FAILURE, "Uknown dyndns auth type %s\n", strauth);
1235 0 : return EINVAL;
1236 : }
1237 :
1238 1 : *_ctx = ctx;
1239 1 : return ERR_OK;
1240 : }
1241 :
1242 1 : errno_t be_nsupdate_init_timer(struct be_nsupdate_ctx *ctx,
1243 : struct tevent_context *ev,
1244 : nsupdate_timer_fn_t timer_callback,
1245 : void *timer_pvt)
1246 : {
1247 1 : if (ctx == NULL) return EINVAL;
1248 :
1249 1 : ctx->timer_callback = timer_callback;
1250 1 : ctx->timer_pvt = timer_pvt;
1251 1 : be_nsupdate_timer_schedule(ev, ctx);
1252 :
1253 1 : return ERR_OK;
1254 : }
1255 :
1256 10 : static bool match_ip(const struct sockaddr *sa,
1257 : const struct sockaddr *sb)
1258 : {
1259 : size_t addrsize;
1260 : bool res;
1261 : const void *addr_a;
1262 : const void *addr_b;
1263 :
1264 10 : if (sa->sa_family == AF_INET) {
1265 9 : addrsize = sizeof(struct in_addr);
1266 9 : addr_a = (const void *) &((const struct sockaddr_in *) sa)->sin_addr;
1267 9 : addr_b = (const void *) &((const struct sockaddr_in *) sb)->sin_addr;
1268 1 : } else if (sa->sa_family == AF_INET6) {
1269 1 : addrsize = sizeof(struct in6_addr);
1270 1 : addr_a = (const void *) &((const struct sockaddr_in6 *) sa)->sin6_addr;
1271 1 : addr_b = (const void *) &((const struct sockaddr_in6 *) sb)->sin6_addr;
1272 : } else {
1273 0 : res = false;
1274 0 : goto done;
1275 : }
1276 :
1277 10 : if (sa->sa_family != sb->sa_family) {
1278 2 : res = false;
1279 2 : goto done;
1280 : }
1281 :
1282 8 : res = memcmp(addr_a, addr_b, addrsize) == 0;
1283 :
1284 : done:
1285 10 : return res;
1286 : }
1287 :
1288 7 : static errno_t find_iface_by_addr(TALLOC_CTX *mem_ctx,
1289 : const struct sockaddr *ss,
1290 : const char **_iface_name)
1291 : {
1292 7 : struct ifaddrs *ifaces = NULL;
1293 : struct ifaddrs *ifa;
1294 : errno_t ret;
1295 :
1296 7 : ret = getifaddrs(&ifaces);
1297 7 : if (ret == -1) {
1298 0 : ret = errno;
1299 0 : DEBUG(SSSDBG_OP_FAILURE,
1300 : "Could not read interfaces [%d][%s]\n", ret, sss_strerror(ret));
1301 0 : goto done;
1302 : }
1303 :
1304 11 : for (ifa = ifaces; ifa != NULL; ifa = ifa->ifa_next) {
1305 :
1306 : /* Some interfaces don't have an ifa_addr */
1307 10 : if (!ifa->ifa_addr) continue;
1308 :
1309 10 : if (match_ip(ss, ifa->ifa_addr)) {
1310 : const char *iface_name;
1311 6 : iface_name = talloc_strdup(mem_ctx, ifa->ifa_name);
1312 6 : if (iface_name == NULL) {
1313 0 : ret = ENOMEM;
1314 : } else {
1315 6 : *_iface_name = iface_name;
1316 6 : ret = EOK;
1317 : }
1318 6 : goto done;
1319 : }
1320 : }
1321 1 : ret = ENOENT;
1322 :
1323 : done:
1324 7 : freeifaddrs(ifaces);
1325 7 : return ret;
1326 : }
1327 :
1328 7 : errno_t sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
1329 : struct sockaddr *ss,
1330 : struct sss_iface_addr **_iface_addrs)
1331 : {
1332 : struct sss_iface_addr *iface_addrs;
1333 7 : const char *iface_name = NULL;
1334 : TALLOC_CTX *tmp_ctx;
1335 : errno_t ret;
1336 :
1337 7 : tmp_ctx = talloc_new(NULL);
1338 7 : if (tmp_ctx == NULL) {
1339 0 : ret = ENOMEM;
1340 0 : goto done;
1341 : }
1342 :
1343 7 : ret = find_iface_by_addr(tmp_ctx, ss, &iface_name);
1344 7 : if (ret != EOK) {
1345 1 : DEBUG(SSSDBG_MINOR_FAILURE, "find_iface_by_addr failed: %d:[%s]\n",
1346 : ret, sss_strerror(ret));
1347 1 : goto done;
1348 : }
1349 :
1350 6 : ret = sss_iface_addr_list_get(tmp_ctx, iface_name, &iface_addrs);
1351 6 : if (ret != EOK) {
1352 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1353 : "sss_iface_addr_list_get failed: %d:[%s]\n",
1354 : ret, sss_strerror(ret));
1355 0 : goto done;
1356 : }
1357 :
1358 6 : ret = EOK;
1359 6 : *_iface_addrs = talloc_steal(mem_ctx, iface_addrs);
1360 :
1361 : done:
1362 7 : talloc_free(tmp_ctx);
1363 7 : return ret;
1364 : }
|