Line data Source code
1 : /*
2 : SSSD
3 :
4 : sdap_dyndns.c: LDAP specific dynamic DNS update
5 :
6 : Authors:
7 : Jakub Hrozek <jhrozek@redhat.com>
8 :
9 : Copyright (C) 2013 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "util/util.h"
26 : #include "resolv/async_resolv.h"
27 : #include "providers/backend.h"
28 : #include "providers/be_dyndns.h"
29 : #include "providers/ldap/sdap_async_private.h"
30 : #include "providers/ldap/sdap_dyndns.h"
31 : #include "providers/ldap/sdap_id_op.h"
32 : #include "providers/ldap/ldap_common.h"
33 :
34 : static struct tevent_req *
35 : sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
36 : struct tevent_context *ev,
37 : struct sdap_id_ctx *sdap_ctx,
38 : const char *iface);
39 : static errno_t
40 : sdap_dyndns_get_addrs_recv(struct tevent_req *req,
41 : TALLOC_CTX *mem_ctx,
42 : struct sss_iface_addr **_addresses);
43 :
44 : struct sdap_dyndns_update_state {
45 : struct tevent_context *ev;
46 : struct be_resolv_ctx *be_res;
47 : struct dp_option *opts;
48 :
49 : const char *hostname;
50 : const char *realm;
51 : const char *servername;
52 : int ttl;
53 :
54 : struct sss_iface_addr *addresses;
55 : struct sss_iface_addr *dns_addrlist;
56 : uint8_t remove_af;
57 :
58 : bool update_ptr;
59 : bool check_diff;
60 : enum be_nsupdate_auth auth_type;
61 : bool fallback_mode;
62 : char *update_msg;
63 : struct sss_iface_addr *ptr_addr_iter;
64 : bool del_phase;
65 : };
66 :
67 : static void sdap_dyndns_update_addrs_done(struct tevent_req *subreq);
68 : static void sdap_dyndns_dns_addrs_done(struct tevent_req *subreq);
69 : static errno_t sdap_dyndns_addrs_diff(struct sdap_dyndns_update_state *state,
70 : bool *_do_update);
71 : static errno_t sdap_dyndns_update_step(struct tevent_req *req);
72 : static errno_t sdap_dyndns_update_ptr_step(struct tevent_req *req);
73 : static void sdap_dyndns_update_done(struct tevent_req *subreq);
74 : static void sdap_dyndns_update_ptr_done(struct tevent_req *subreq);
75 : static errno_t
76 : sdap_dyndns_next_ptr_record(struct sdap_dyndns_update_state *state,
77 : struct tevent_req *req);
78 : static struct sss_iface_addr*
79 : sdap_get_address_to_delete(struct sss_iface_addr *address_it,
80 : uint8_t remove_af);
81 :
82 : struct tevent_req *
83 0 : sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
84 : struct tevent_context *ev,
85 : struct be_ctx *be_ctx,
86 : struct dp_option *opts,
87 : struct sdap_id_ctx *sdap_ctx,
88 : enum be_nsupdate_auth auth_type,
89 : const char *ifname,
90 : const char *hostname,
91 : const char *realm,
92 : const int ttl,
93 : bool check_diff)
94 : {
95 : errno_t ret;
96 : struct tevent_req *req;
97 : struct tevent_req *subreq;
98 : struct sdap_dyndns_update_state *state;
99 : const char *conf_servername;
100 :
101 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_dyndns_update_state);
102 0 : if (req == NULL) {
103 0 : return NULL;
104 : }
105 0 : state->check_diff = check_diff;
106 0 : state->update_ptr = dp_opt_get_bool(opts, DP_OPT_DYNDNS_UPDATE_PTR);
107 0 : state->hostname = hostname;
108 0 : state->realm = realm;
109 0 : state->servername = NULL;
110 0 : state->fallback_mode = false;
111 0 : state->ttl = ttl;
112 0 : state->be_res = be_ctx->be_res;
113 0 : state->ev = ev;
114 0 : state->opts = opts;
115 0 : state->auth_type = auth_type;
116 0 : state->ptr_addr_iter = NULL;
117 0 : state->del_phase = true;
118 :
119 : /* fallback servername is overriden by user option */
120 0 : conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
121 0 : if (conf_servername != NULL) {
122 0 : state->servername = conf_servername;
123 : }
124 :
125 0 : if (ifname) {
126 : /* Unless one family is restricted, just replace all
127 : * address families during the update
128 : */
129 0 : switch (state->be_res->family_order) {
130 : case IPV4_ONLY:
131 0 : state->remove_af |= DYNDNS_REMOVE_A;
132 0 : break;
133 : case IPV6_ONLY:
134 0 : state->remove_af |= DYNDNS_REMOVE_AAAA;
135 0 : break;
136 : case IPV4_FIRST:
137 : case IPV6_FIRST:
138 0 : state->remove_af |= (DYNDNS_REMOVE_A |
139 : DYNDNS_REMOVE_AAAA);
140 0 : break;
141 : }
142 : } else {
143 : /* If the interface isn't specified, we ONLY want to have the address
144 : * that's connected to the LDAP server stored, so we need to check
145 : * (and later remove) both address families.
146 : */
147 0 : state->remove_af = (DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA);
148 : }
149 :
150 0 : subreq = sdap_dyndns_get_addrs_send(state, state->ev, sdap_ctx, ifname);
151 0 : if (!subreq) {
152 0 : ret = EIO;
153 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: [%d](%s)\n",
154 : ret, sss_strerror(ret));
155 0 : goto done;
156 : }
157 0 : tevent_req_set_callback(subreq, sdap_dyndns_update_addrs_done, req);
158 :
159 0 : ret = EOK;
160 : done:
161 0 : if (ret != EOK) {
162 0 : tevent_req_error(req, ret);
163 0 : tevent_req_post(req, ev);
164 : }
165 0 : return req;
166 : }
167 :
168 : static void
169 0 : sdap_dyndns_update_addrs_done(struct tevent_req *subreq)
170 : {
171 : errno_t ret;
172 : struct tevent_req *req;
173 : struct sdap_dyndns_update_state *state;
174 :
175 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
176 0 : state = tevent_req_data(req, struct sdap_dyndns_update_state);
177 :
178 0 : ret = sdap_dyndns_get_addrs_recv(subreq, state, &state->addresses);
179 0 : talloc_zfree(subreq);
180 0 : if (ret != EOK) {
181 0 : DEBUG(SSSDBG_OP_FAILURE, "Can't get addresses for DNS update\n");
182 0 : tevent_req_error(req, ret);
183 0 : return;
184 : }
185 :
186 0 : if (state->check_diff || state->update_ptr) {
187 : /* Check if we need the update at all. In case we are updating the PTR
188 : * records as well, we need to know the old addresses to be able to
189 : * reliably delete the PTR records */
190 0 : subreq = nsupdate_get_addrs_send(state, state->ev,
191 : state->be_res, state->hostname);
192 0 : if (subreq == NULL) {
193 0 : DEBUG(SSSDBG_OP_FAILURE, "Can't initiate address check\n");
194 0 : tevent_req_error(req, ret);
195 0 : return;
196 : }
197 0 : tevent_req_set_callback(subreq, sdap_dyndns_dns_addrs_done, req);
198 0 : return;
199 : }
200 :
201 : /* Perform update */
202 0 : ret = sdap_dyndns_update_step(req);
203 0 : if (ret != EOK) {
204 0 : tevent_req_error(req, ret);
205 0 : return;
206 : }
207 : /* Execution will resume in sdap_dyndns_update_done */
208 : }
209 :
210 : static void
211 0 : sdap_dyndns_dns_addrs_done(struct tevent_req *subreq)
212 : {
213 : struct tevent_req *req;
214 : struct sdap_dyndns_update_state *state;
215 : errno_t ret;
216 : bool do_update;
217 :
218 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
219 0 : state = tevent_req_data(req, struct sdap_dyndns_update_state);
220 :
221 0 : ret = nsupdate_get_addrs_recv(subreq, state, &state->dns_addrlist, NULL);
222 0 : talloc_zfree(subreq);
223 0 : if (ret != EOK) {
224 0 : DEBUG(SSSDBG_OP_FAILURE,
225 : "Could not receive list of current addresses [%d]: %s\n",
226 : ret, sss_strerror(ret));
227 0 : tevent_req_error(req, ret);
228 0 : return;
229 : }
230 :
231 0 : if (state->check_diff) {
232 0 : ret = sdap_dyndns_addrs_diff(state, &do_update);
233 0 : if (ret != EOK) {
234 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not check the diff between DNS "
235 : "and current addresses [%d]: %s\n", ret, strerror(ret));
236 0 : tevent_req_error(req, ret);
237 0 : return;
238 : }
239 :
240 0 : if (do_update == false) {
241 0 : DEBUG(SSSDBG_TRACE_FUNC,
242 : "No DNS update needed, addresses did not change\n");
243 0 : tevent_req_done(req);
244 0 : return;
245 : }
246 0 : DEBUG(SSSDBG_TRACE_FUNC,
247 : "Detected IP addresses change, will perform an update\n");
248 : }
249 :
250 : /* Either we needed the addresses for updating PTR records only or
251 : * the addresses have changed (or both) */
252 0 : ret = sdap_dyndns_update_step(req);
253 0 : if (ret != EOK) {
254 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not start the update [%d]: %s\n",
255 : ret, sss_strerror(ret));
256 0 : tevent_req_error(req, ret);
257 : }
258 0 : return;
259 : }
260 :
261 : static errno_t
262 0 : sdap_dyndns_addrs_diff(struct sdap_dyndns_update_state *state, bool *_do_update)
263 : {
264 : errno_t ret;
265 : int i;
266 0 : char **str_dnslist = NULL, **str_local_list = NULL;
267 0 : char **dns_only = NULL, **local_only = NULL;
268 0 : bool do_update = false;
269 :
270 0 : ret = sss_iface_addr_list_as_str_list(state,
271 : state->dns_addrlist, &str_dnslist);
272 0 : if (ret != EOK) {
273 0 : DEBUG(SSSDBG_OP_FAILURE,
274 : "Converting DNS IP addresses to strings failed: [%d]: %s\n",
275 : ret, sss_strerror(ret));
276 0 : return ret;
277 : }
278 :
279 0 : ret = sss_iface_addr_list_as_str_list(state,
280 : state->addresses, &str_local_list);
281 0 : if (ret != EOK) {
282 0 : DEBUG(SSSDBG_OP_FAILURE,
283 : "Converting local IP addresses to strings failed: [%d]: %s\n",
284 : ret, sss_strerror(ret));
285 0 : return ret;
286 : }
287 :
288 : /* Compare the lists */
289 0 : ret = diff_string_lists(state, str_dnslist, str_local_list,
290 : &dns_only, &local_only, NULL);
291 0 : if (ret != EOK) {
292 0 : DEBUG(SSSDBG_OP_FAILURE,
293 : "diff_string_lists failed: [%d]: %s\n", ret, sss_strerror(ret));
294 0 : return ret;
295 : }
296 :
297 0 : if (dns_only) {
298 0 : for (i=0; dns_only[i]; i++) {
299 0 : DEBUG(SSSDBG_TRACE_LIBS,
300 : "Address in DNS only: %s\n", dns_only[i]);
301 0 : do_update = true;
302 : }
303 : }
304 :
305 0 : if (local_only) {
306 0 : for (i=0; local_only[i]; i++) {
307 0 : DEBUG(SSSDBG_TRACE_LIBS,
308 : "Address on localhost only: %s\n", local_only[i]);
309 0 : do_update = true;
310 : }
311 : }
312 :
313 0 : *_do_update = do_update;
314 0 : return EOK;
315 : }
316 :
317 : static errno_t
318 0 : sdap_dyndns_update_step(struct tevent_req *req)
319 : {
320 : errno_t ret;
321 : struct sdap_dyndns_update_state *state;
322 : const char *servername;
323 : const char *realm;
324 : struct tevent_req *subreq;
325 :
326 0 : state = tevent_req_data(req, struct sdap_dyndns_update_state);
327 :
328 0 : servername = NULL;
329 0 : realm = NULL;
330 0 : if (state->fallback_mode) {
331 0 : servername = state->servername;
332 0 : realm = state->realm;
333 : }
334 :
335 0 : ret = be_nsupdate_create_fwd_msg(state, realm, servername,
336 : state->hostname,
337 0 : state->ttl, state->remove_af,
338 : state->addresses,
339 : &state->update_msg);
340 0 : if (ret != EOK) {
341 0 : DEBUG(SSSDBG_OP_FAILURE, "Can't get addresses for DNS update\n");
342 0 : return ret;
343 : }
344 :
345 : /* Fork a child process to perform the DNS update */
346 0 : subreq = be_nsupdate_send(state, state->ev, state->auth_type,
347 : state->update_msg,
348 0 : dp_opt_get_bool(state->opts,
349 : DP_OPT_DYNDNS_FORCE_TCP));
350 0 : if (subreq == NULL) {
351 0 : return EIO;
352 : }
353 :
354 0 : tevent_req_set_callback(subreq, sdap_dyndns_update_done, req);
355 0 : return EOK;
356 : }
357 :
358 : static void
359 0 : sdap_dyndns_update_done(struct tevent_req *subreq)
360 : {
361 : errno_t ret;
362 : int child_status;
363 : struct tevent_req *req;
364 : struct sdap_dyndns_update_state *state;
365 :
366 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
367 0 : state = tevent_req_data(req, struct sdap_dyndns_update_state);
368 :
369 0 : ret = be_nsupdate_recv(subreq, &child_status);
370 0 : talloc_zfree(subreq);
371 0 : if (ret != EOK) {
372 : /* If the update didn't succeed, we can retry using the server name */
373 0 : if (state->fallback_mode == false
374 0 : && WIFEXITED(child_status)
375 0 : && WEXITSTATUS(child_status) != 0) {
376 0 : state->fallback_mode = true;
377 0 : DEBUG(SSSDBG_MINOR_FAILURE,
378 : "nsupdate failed, retrying.\n");
379 0 : ret = sdap_dyndns_update_step(req);
380 0 : if (ret == EOK) {
381 0 : return;
382 : }
383 : }
384 :
385 0 : tevent_req_error(req, ret);
386 0 : return;
387 : }
388 :
389 0 : if (state->update_ptr == false) {
390 0 : DEBUG(SSSDBG_TRACE_FUNC, "No PTR update requested, done\n");
391 0 : tevent_req_done(req);
392 0 : return;
393 : }
394 :
395 0 : talloc_free(state->update_msg);
396 :
397 : /* init iterator for addresses to be deleted */
398 0 : state->ptr_addr_iter = sdap_get_address_to_delete(state->dns_addrlist,
399 0 : state->remove_af);
400 0 : if (state->ptr_addr_iter == NULL) {
401 : /* init iterator for addresses to be added */
402 0 : state->del_phase = false;
403 0 : state->ptr_addr_iter = state->addresses;
404 : }
405 :
406 0 : ret = sdap_dyndns_update_ptr_step(req);
407 0 : if (ret != EOK) {
408 0 : tevent_req_error(req, ret);
409 0 : return;
410 : }
411 : /* Execution will resume in sdap_dyndns_update_ptr_done */
412 : }
413 :
414 :
415 0 : static bool remove_addr(int address_family, uint8_t remove_af)
416 : {
417 0 : bool ret = false;
418 :
419 0 : switch(address_family) {
420 : case AF_INET:
421 0 : if (remove_af & DYNDNS_REMOVE_A) {
422 0 : ret = true;
423 : }
424 0 : break;
425 : case AF_INET6:
426 0 : if (remove_af & DYNDNS_REMOVE_AAAA) {
427 0 : ret = true;
428 : }
429 0 : break;
430 : default:
431 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
432 0 : ret = false;
433 : }
434 :
435 0 : return ret;
436 : }
437 :
438 : static struct sss_iface_addr*
439 0 : sdap_get_address_to_delete(struct sss_iface_addr *address_it,
440 : uint8_t remove_af)
441 : {
442 : struct sockaddr_storage* address;
443 :
444 0 : while (address_it != NULL) {
445 0 : address = sss_iface_addr_get_address(address_it);
446 :
447 : /* skip addresses that are not to be deleted */
448 0 : if (remove_addr(address->ss_family, remove_af)) {
449 0 : break;
450 : }
451 :
452 0 : address_it = sss_iface_addr_get_next(address_it);
453 : }
454 :
455 0 : return address_it;
456 : }
457 :
458 : static errno_t
459 0 : sdap_dyndns_update_ptr_step(struct tevent_req *req)
460 : {
461 : errno_t ret;
462 : struct sdap_dyndns_update_state *state;
463 : const char *servername;
464 : const char *realm;
465 : struct tevent_req *subreq;
466 : struct sockaddr_storage *address;
467 :
468 0 : state = tevent_req_data(req, struct sdap_dyndns_update_state);
469 :
470 0 : servername = NULL;
471 0 : realm = NULL;
472 0 : if (state->fallback_mode == true) {
473 0 : servername = state->servername;
474 0 : realm = state->realm;
475 : }
476 :
477 0 : address = sss_iface_addr_get_address(state->ptr_addr_iter);
478 0 : if (address == NULL) {
479 0 : return EIO;
480 : }
481 :
482 0 : ret = be_nsupdate_create_ptr_msg(state, realm, servername, state->hostname,
483 0 : state->ttl, address, state->del_phase,
484 : &state->update_msg);
485 :
486 0 : if (ret != EOK) {
487 0 : DEBUG(SSSDBG_OP_FAILURE, "Can't get addresses for DNS update\n");
488 0 : return ret;
489 : }
490 :
491 : /* Fork a child process to perform the DNS update */
492 0 : subreq = be_nsupdate_send(state, state->ev, state->auth_type,
493 : state->update_msg,
494 0 : dp_opt_get_bool(state->opts,
495 : DP_OPT_DYNDNS_FORCE_TCP));
496 0 : if (subreq == NULL) {
497 0 : return EIO;
498 : }
499 :
500 0 : tevent_req_set_callback(subreq, sdap_dyndns_update_ptr_done, req);
501 0 : return EOK;
502 : }
503 :
504 : static void
505 0 : sdap_dyndns_update_ptr_done(struct tevent_req *subreq)
506 : {
507 : errno_t ret;
508 : int child_status;
509 : struct tevent_req *req;
510 : struct sdap_dyndns_update_state *state;
511 :
512 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
513 0 : state = tevent_req_data(req, struct sdap_dyndns_update_state);
514 :
515 0 : ret = be_nsupdate_recv(subreq, &child_status);
516 0 : talloc_zfree(subreq);
517 0 : if (ret != EOK) {
518 : /* If the update didn't succeed, we can retry using the server name */
519 0 : if (state->fallback_mode == false
520 0 : && WIFEXITED(child_status)
521 0 : && WEXITSTATUS(child_status) != 0) {
522 0 : state->fallback_mode = true;
523 0 : DEBUG(SSSDBG_MINOR_FAILURE, "nsupdate failed, retrying\n");
524 0 : ret = sdap_dyndns_update_ptr_step(req);
525 0 : if (ret == EOK) {
526 0 : return;
527 : }
528 : }
529 :
530 0 : ret = sdap_dyndns_next_ptr_record(state, req);
531 0 : if (ret == EAGAIN) {
532 0 : return;
533 : }
534 :
535 0 : tevent_req_error(req, ret);
536 0 : return;
537 : }
538 :
539 0 : ret = sdap_dyndns_next_ptr_record(state, req);
540 0 : if (ret == EAGAIN) {
541 0 : return;
542 : }
543 :
544 0 : tevent_req_done(req);
545 : }
546 :
547 : static errno_t
548 0 : sdap_dyndns_next_ptr_record(struct sdap_dyndns_update_state *state,
549 : struct tevent_req *req)
550 : {
551 : errno_t ret;
552 :
553 0 : if (state->del_phase) {
554 : /* iterate to next address to delete */
555 0 : state->ptr_addr_iter = sdap_get_address_to_delete(
556 0 : sss_iface_addr_get_next(state->ptr_addr_iter), state->remove_af);
557 0 : if (state->ptr_addr_iter == NULL) {
558 : /* init iterator for addresses to be added */
559 0 : state->del_phase = false;
560 0 : state->ptr_addr_iter = state->addresses;
561 : }
562 : } else {
563 : /* iterate to next address to add */
564 0 : state->ptr_addr_iter = sss_iface_addr_get_next(state->ptr_addr_iter);
565 : }
566 :
567 0 : if (state->ptr_addr_iter != NULL) {
568 :
569 0 : state->fallback_mode = false;
570 0 : ret = sdap_dyndns_update_ptr_step(req);
571 0 : if (ret == EOK) {
572 0 : return EAGAIN;
573 : }
574 : }
575 :
576 0 : return EOK;
577 : }
578 :
579 : errno_t
580 0 : sdap_dyndns_update_recv(struct tevent_req *req)
581 : {
582 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
583 0 : return EOK;
584 : }
585 :
586 : /* A request to get addresses to update with */
587 : struct sdap_dyndns_get_addrs_state {
588 : struct sdap_id_op* sdap_op;
589 : struct sss_iface_addr *addresses;
590 : };
591 :
592 : static void sdap_dyndns_get_addrs_done(struct tevent_req *subreq);
593 : static errno_t sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
594 : struct sdap_handle *sh);
595 :
596 0 : static errno_t get_ifaces_addrs(TALLOC_CTX *mem_ctx,
597 : const char *iface,
598 : struct sss_iface_addr **_result)
599 : {
600 0 : struct sss_iface_addr *result_addrs = NULL;
601 : struct sss_iface_addr *intf_addrs;
602 : TALLOC_CTX *tmp_ctx;
603 : char **list_of_intfs;
604 : int num_of_intfs;
605 : errno_t ret;
606 : int i;
607 :
608 0 : tmp_ctx = talloc_new(NULL);
609 0 : if (tmp_ctx == NULL) {
610 0 : ret = ENOMEM;
611 0 : goto done;
612 : }
613 :
614 0 : ret = split_on_separator(tmp_ctx, iface, ',', true, true, &list_of_intfs,
615 : &num_of_intfs);
616 0 : if (ret != EOK) {
617 0 : DEBUG(SSSDBG_MINOR_FAILURE,
618 : "Parsing names of interfaces failed - %d:[%s].\n",
619 : ret, sss_strerror(ret));
620 0 : goto done;
621 : }
622 :
623 0 : for (i = 0; i < num_of_intfs; i++) {
624 0 : ret = sss_iface_addr_list_get(tmp_ctx, list_of_intfs[i], &intf_addrs);
625 0 : if (ret == EOK) {
626 0 : if (result_addrs != NULL) {
627 : /* If there is already an existing list, head of this existing
628 : * list will be considered as parent talloc context for the
629 : * new list.
630 : */
631 0 : talloc_steal(result_addrs, intf_addrs);
632 : }
633 0 : sss_iface_addr_concatenate(&result_addrs, intf_addrs);
634 0 : } else if (ret == ENOENT) {
635 : /* non-critical failure */
636 0 : DEBUG(SSSDBG_TRACE_FUNC,
637 : "Cannot get interface %s or there are no addresses "
638 : "bind to it.\n", list_of_intfs[i]);
639 : } else {
640 0 : DEBUG(SSSDBG_OP_FAILURE,
641 : "Cannot get list of addresses from interface %s - %d:[%s]\n",
642 : list_of_intfs[i], ret, sss_strerror(ret));
643 0 : goto done;
644 : }
645 : }
646 :
647 0 : ret = EOK;
648 0 : *_result = talloc_steal(mem_ctx, result_addrs);
649 :
650 : done:
651 0 : talloc_free(tmp_ctx);
652 0 : return ret;
653 : }
654 :
655 : static struct tevent_req *
656 0 : sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
657 : struct tevent_context *ev,
658 : struct sdap_id_ctx *sdap_ctx,
659 : const char *iface)
660 : {
661 : errno_t ret;
662 : struct tevent_req *req;
663 : struct tevent_req *subreq;
664 : struct sdap_dyndns_get_addrs_state *state;
665 :
666 0 : req = tevent_req_create(mem_ctx, &state,
667 : struct sdap_dyndns_get_addrs_state);
668 0 : if (req == NULL) {
669 0 : return NULL;
670 : }
671 :
672 0 : if (iface) {
673 0 : ret = get_ifaces_addrs(state, iface, &state->addresses);
674 0 : if (ret != EOK || state->addresses == NULL) {
675 0 : DEBUG(SSSDBG_MINOR_FAILURE,
676 : "get_ifaces_addrs() failed: %d:[%s]\n",
677 : ret, sss_strerror(ret));
678 : }
679 : /* We're done. Just fake an async request completion */
680 0 : goto done;
681 : }
682 :
683 : /* Detect DYNDNS address from LDAP connection */
684 0 : state->sdap_op = sdap_id_op_create(state, sdap_ctx->conn->conn_cache);
685 0 : if (!state->sdap_op) {
686 0 : ret = ENOMEM;
687 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
688 0 : goto done;
689 : }
690 :
691 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
692 0 : if (!subreq) {
693 0 : ret = EIO;
694 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: [%d](%s)\n",
695 : ret, sss_strerror(ret));
696 0 : goto done;
697 : }
698 0 : tevent_req_set_callback(subreq, sdap_dyndns_get_addrs_done, req);
699 :
700 0 : ret = EAGAIN;
701 : done:
702 0 : if (ret == EOK) {
703 0 : tevent_req_done(req);
704 0 : tevent_req_post(req, ev);
705 0 : } else if (ret != EAGAIN) {
706 0 : tevent_req_error(req, ret);
707 0 : tevent_req_post(req, ev);
708 : }
709 :
710 : /* EAGAIN - resolution in progress */
711 0 : return req;
712 : }
713 :
714 : static void
715 0 : sdap_dyndns_get_addrs_done(struct tevent_req *subreq)
716 : {
717 : errno_t ret;
718 : int dp_error;
719 : struct tevent_req *req;
720 : struct sdap_dyndns_get_addrs_state *state;
721 :
722 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
723 0 : state = tevent_req_data(req, struct sdap_dyndns_get_addrs_state);
724 :
725 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
726 0 : talloc_zfree(subreq);
727 0 : if (ret != EOK) {
728 0 : if (dp_error == DP_ERR_OFFLINE) {
729 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No LDAP server is available, "
730 : "dynamic DNS update is skipped in offline mode.\n");
731 0 : ret = ERR_DYNDNS_OFFLINE;
732 : } else {
733 0 : DEBUG(SSSDBG_OP_FAILURE,
734 : "Failed to connect to LDAP server: [%d](%s)\n",
735 : ret, sss_strerror(ret));
736 : }
737 0 : tevent_req_error(req, ret);
738 0 : return;
739 : }
740 :
741 0 : ret = sdap_dyndns_add_ldap_conn(state, sdap_id_op_handle(state->sdap_op));
742 0 : if (ret != EOK) {
743 0 : DEBUG(SSSDBG_OP_FAILURE, "Can't get addresses from LDAP connection\n");
744 0 : tevent_req_error(req, ret);
745 0 : return;
746 : }
747 :
748 : /* Got the address! Done! */
749 0 : tevent_req_done(req);
750 : }
751 :
752 : static errno_t
753 0 : sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
754 : struct sdap_handle *sh)
755 : {
756 : int ret;
757 : int fd;
758 : struct sockaddr_storage ss;
759 0 : socklen_t ss_len = sizeof(ss);
760 :
761 0 : if (sh == NULL) {
762 0 : return EINVAL;
763 : }
764 :
765 : /* Get the file descriptor for the primary LDAP connection */
766 0 : ret = get_fd_from_ldap(sh->ldap, &fd);
767 0 : if (ret != EOK) {
768 0 : return ret;
769 : }
770 :
771 0 : errno = 0;
772 0 : ret = getsockname(fd, (struct sockaddr *) &ss, &ss_len);
773 0 : if (ret == -1) {
774 0 : ret = errno;
775 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to get socket name\n");
776 0 : return ret;
777 : }
778 :
779 0 : if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6) {
780 0 : DEBUG(SSSDBG_CRIT_FAILURE,
781 : "Connection to LDAP is neither IPv4 nor IPv6\n");
782 0 : return EIO;
783 : }
784 :
785 0 : ret = sss_get_dualstack_addresses(state, (struct sockaddr *) &ss,
786 : &state->addresses);
787 0 : if (ret != EOK) {
788 0 : DEBUG(SSSDBG_MINOR_FAILURE,
789 : "sss_get_dualstack_addresses failed: %d:[%s]\n",
790 : ret, sss_strerror(ret));
791 0 : return ret;
792 : }
793 :
794 0 : return EOK;
795 : }
796 :
797 : static errno_t
798 0 : sdap_dyndns_get_addrs_recv(struct tevent_req *req,
799 : TALLOC_CTX *mem_ctx,
800 : struct sss_iface_addr **_addresses)
801 : {
802 : struct sdap_dyndns_get_addrs_state *state;
803 :
804 0 : state = tevent_req_data(req, struct sdap_dyndns_get_addrs_state);
805 :
806 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
807 :
808 0 : *_addresses = talloc_steal(mem_ctx, state->addresses);
809 0 : return EOK;
810 : }
811 :
812 : struct sdap_dyndns_timer_state {
813 : struct tevent_context *ev;
814 : struct sdap_id_ctx *sdap_ctx;
815 : struct be_nsupdate_ctx *dyndns_ctx;
816 :
817 : struct sdap_id_op *sdap_op;
818 : };
819 :
820 : static void sdap_dyndns_timer_conn_done(struct tevent_req *req);
821 :
822 : struct tevent_req *
823 0 : sdap_dyndns_timer_conn_send(TALLOC_CTX *mem_ctx,
824 : struct tevent_context *ev,
825 : struct sdap_id_ctx *sdap_ctx,
826 : struct be_nsupdate_ctx *dyndns_ctx)
827 : {
828 : struct sdap_dyndns_timer_state *state;
829 : struct tevent_req *req;
830 : struct tevent_req *subreq;
831 : errno_t ret;
832 :
833 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_dyndns_timer_state);
834 0 : if (req == NULL) {
835 0 : return NULL;
836 : }
837 0 : state->ev = ev;
838 0 : state->sdap_ctx = sdap_ctx;
839 0 : state->dyndns_ctx = dyndns_ctx;
840 :
841 : /* In order to prevent the connection triggering an
842 : * online callback which would in turn trigger a concurrent DNS
843 : * update
844 : */
845 0 : state->dyndns_ctx->timer_in_progress = true;
846 :
847 : /* Make sure to have a valid LDAP connection */
848 0 : state->sdap_op = sdap_id_op_create(state, state->sdap_ctx->conn->conn_cache);
849 0 : if (state->sdap_op == NULL) {
850 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
851 0 : ret = ENOMEM;
852 0 : goto fail;
853 : }
854 :
855 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
856 0 : if (subreq == NULL) {
857 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: [%d](%s)\n",
858 : ret, sss_strerror(ret));
859 0 : ret = ENOMEM;
860 0 : goto fail;
861 : }
862 0 : tevent_req_set_callback(subreq, sdap_dyndns_timer_conn_done, req);
863 0 : return req;
864 :
865 : fail:
866 0 : dyndns_ctx->timer_in_progress = false;
867 0 : be_nsupdate_timer_schedule(ev, dyndns_ctx);
868 0 : tevent_req_error(req, ret);
869 0 : tevent_req_post(req, ev);
870 0 : return req;
871 : }
872 :
873 : static void
874 0 : sdap_dyndns_timer_conn_done(struct tevent_req *subreq)
875 : {
876 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
877 : struct tevent_req);
878 0 : struct sdap_dyndns_timer_state *state = tevent_req_data(req,
879 : struct sdap_dyndns_timer_state);
880 : errno_t ret;
881 : int dp_error;
882 :
883 0 : state->dyndns_ctx->timer_in_progress = false;
884 :
885 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
886 0 : talloc_zfree(subreq);
887 0 : if (ret != EOK) {
888 0 : if (dp_error == DP_ERR_OFFLINE) {
889 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No server is available, "
890 : "dynamic DNS update is skipped in offline mode.\n");
891 : /* Another timer will be scheduled when provider goes online */
892 0 : tevent_req_error(req, ERR_DYNDNS_OFFLINE);
893 : } else {
894 0 : DEBUG(SSSDBG_OP_FAILURE,
895 : "Failed to connect to LDAP server: [%d](%s)\n",
896 : ret, sss_strerror(ret));
897 :
898 : /* Just schedule another dyndns retry */
899 0 : be_nsupdate_timer_schedule(state->ev, state->dyndns_ctx);
900 0 : tevent_req_error(req, ERR_NETWORK_IO);
901 : }
902 0 : return;
903 : }
904 :
905 : /* All OK, schedule another refresh and let the user call its
906 : * provider-specific update
907 : */
908 0 : be_nsupdate_timer_schedule(state->ev, state->dyndns_ctx);
909 0 : tevent_req_done(req);
910 : }
911 :
912 : errno_t
913 0 : sdap_dyndns_timer_conn_recv(struct tevent_req *req)
914 : {
915 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
916 0 : return EOK;
917 : }
|