Line data Source code
1 : /*
2 : SSSD
3 :
4 : ipa_dyndns.c
5 :
6 : Authors:
7 : Stephen Gallagher <sgallagh@redhat.com>
8 :
9 : Copyright (C) 2010 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 <ctype.h>
26 : #include "util/util.h"
27 : #include "providers/ldap/sdap_dyndns.h"
28 : #include "providers/ipa/ipa_common.h"
29 : #include "providers/ipa/ipa_dyndns.h"
30 : #include "providers/data_provider.h"
31 : #include "providers/be_dyndns.h"
32 :
33 : void ipa_dyndns_update(void *pvt);
34 :
35 0 : errno_t ipa_dyndns_init(struct be_ctx *be_ctx,
36 : struct ipa_options *ctx)
37 : {
38 : errno_t ret;
39 :
40 0 : ctx->be_res = be_ctx->be_res;
41 0 : if (ctx->be_res == NULL) {
42 0 : DEBUG(SSSDBG_OP_FAILURE, "Resolver must be initialized in order "
43 : "to use the IPA dynamic DNS updates\n");
44 0 : return EINVAL;
45 : }
46 :
47 0 : ret = be_nsupdate_init_timer(ctx->dyndns_ctx, be_ctx->ev,
48 : ipa_dyndns_timer, ctx);
49 0 : if (ret != EOK) {
50 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up periodic update\n");
51 0 : return ret;
52 : }
53 :
54 0 : ret = be_add_online_cb(be_ctx, be_ctx,
55 : ipa_dyndns_update,
56 : ctx, NULL);
57 0 : if (ret != EOK) {
58 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up online callback\n");
59 0 : return ret;
60 : }
61 :
62 0 : return EOK;
63 : }
64 :
65 : struct ipa_dyndns_timer_ctx {
66 : struct sdap_id_op *sdap_op;
67 : struct tevent_context *ev;
68 :
69 : struct ipa_options *ctx;
70 : };
71 :
72 : static void ipa_dyndns_timer_connected(struct tevent_req *req);
73 :
74 0 : void ipa_dyndns_timer(void *pvt)
75 : {
76 0 : struct ipa_options *ctx = talloc_get_type(pvt, struct ipa_options);
77 0 : struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
78 : struct tevent_req *req;
79 :
80 0 : req = sdap_dyndns_timer_conn_send(ctx, sdap_ctx->be->ev, sdap_ctx,
81 : ctx->dyndns_ctx);
82 0 : if (req == NULL) {
83 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
84 : /* Not much we can do. Just attempt to reschedule */
85 0 : be_nsupdate_timer_schedule(sdap_ctx->be->ev, ctx->dyndns_ctx);
86 0 : return;
87 : }
88 0 : tevent_req_set_callback(req, ipa_dyndns_timer_connected, ctx);
89 : }
90 :
91 0 : static void ipa_dyndns_timer_connected(struct tevent_req *req)
92 : {
93 : errno_t ret;
94 0 : struct ipa_options *ctx = tevent_req_callback_data(req,
95 : struct ipa_options);
96 :
97 0 : ret = sdap_dyndns_timer_conn_recv(req);
98 0 : talloc_zfree(req);
99 0 : if (ret != EOK) {
100 0 : DEBUG(SSSDBG_OP_FAILURE,
101 : "Failed to connect to IPA: [%d](%s)\n",
102 : ret, sss_strerror(ret));
103 0 : return;
104 : }
105 :
106 0 : return ipa_dyndns_update(ctx);
107 : }
108 :
109 : static struct tevent_req *ipa_dyndns_update_send(struct ipa_options *ctx);
110 : static errno_t ipa_dyndns_update_recv(struct tevent_req *req);
111 :
112 : static void ipa_dyndns_nsupdate_done(struct tevent_req *subreq);
113 :
114 0 : void ipa_dyndns_update(void *pvt)
115 : {
116 0 : struct ipa_options *ctx = talloc_get_type(pvt, struct ipa_options);
117 0 : struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
118 :
119 : /* Schedule timer after provider went offline */
120 0 : be_nsupdate_timer_schedule(sdap_ctx->be->ev, ctx->dyndns_ctx);
121 :
122 0 : struct tevent_req *req = ipa_dyndns_update_send(ctx);
123 0 : if (req == NULL) {
124 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not update DNS\n");
125 0 : return;
126 : }
127 0 : tevent_req_set_callback(req, ipa_dyndns_nsupdate_done, NULL);
128 : }
129 :
130 0 : static void ipa_dyndns_nsupdate_done(struct tevent_req *req)
131 : {
132 0 : int ret = ipa_dyndns_update_recv(req);
133 0 : talloc_free(req);
134 0 : if (ret != EOK) {
135 0 : DEBUG(SSSDBG_OP_FAILURE, "Updating DNS entry failed [%d]: %s\n",
136 : ret, sss_strerror(ret));
137 0 : return;
138 : }
139 :
140 0 : DEBUG(SSSDBG_OP_FAILURE, "DNS update finished\n");
141 : }
142 :
143 : struct ipa_dyndns_update_state {
144 : struct ipa_options *ipa_ctx;
145 : };
146 :
147 : static void ipa_dyndns_sdap_update_done(struct tevent_req *subreq);
148 :
149 : static struct tevent_req *
150 0 : ipa_dyndns_update_send(struct ipa_options *ctx)
151 : {
152 : int ret;
153 : struct ipa_dyndns_update_state *state;
154 : struct tevent_req *req, *subreq;
155 0 : struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
156 :
157 0 : DEBUG(SSSDBG_TRACE_FUNC, "Performing update\n");
158 :
159 0 : req = tevent_req_create(ctx, &state, struct ipa_dyndns_update_state);
160 0 : if (req == NULL) {
161 0 : return NULL;
162 : }
163 0 : state->ipa_ctx = ctx;
164 :
165 0 : if (ctx->dyndns_ctx->last_refresh + 60 > time(NULL) ||
166 0 : ctx->dyndns_ctx->timer_in_progress) {
167 0 : DEBUG(SSSDBG_FUNC_DATA, "Last periodic update ran recently or timer "
168 : "in progress, not scheduling another update\n");
169 0 : tevent_req_done(req);
170 0 : tevent_req_post(req, sdap_ctx->be->ev);
171 0 : return req;
172 : }
173 0 : state->ipa_ctx->dyndns_ctx->last_refresh = time(NULL);
174 :
175 0 : if (strncmp(ctx->service->sdap->uri,
176 : "ldap://", 7) != 0) {
177 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected format of LDAP URI.\n");
178 0 : ret = EIO;
179 0 : goto done;
180 : }
181 :
182 0 : subreq = sdap_dyndns_update_send(state, sdap_ctx->be->ev,
183 : sdap_ctx->be,
184 0 : ctx->dyndns_ctx->opts,
185 : sdap_ctx,
186 0 : ctx->dyndns_ctx->auth_type,
187 0 : dp_opt_get_string(ctx->dyndns_ctx->opts,
188 : DP_OPT_DYNDNS_IFACE),
189 0 : dp_opt_get_string(ctx->basic,
190 : IPA_HOSTNAME),
191 0 : dp_opt_get_string(ctx->basic,
192 : IPA_KRB5_REALM),
193 0 : dp_opt_get_int(ctx->dyndns_ctx->opts,
194 : DP_OPT_DYNDNS_TTL),
195 : true);
196 0 : if (!subreq) {
197 0 : ret = EIO;
198 0 : DEBUG(SSSDBG_OP_FAILURE,
199 : "sdap_id_op_connect_send failed: [%d](%s)\n",
200 : ret, sss_strerror(ret));
201 0 : goto done;
202 : }
203 0 : tevent_req_set_callback(subreq, ipa_dyndns_sdap_update_done, req);
204 :
205 0 : ret = EOK;
206 : done:
207 0 : if (ret != EOK) {
208 0 : tevent_req_error(req, ret);
209 0 : tevent_req_post(req, sdap_ctx->be->ev);
210 : }
211 0 : return req;
212 : }
213 :
214 0 : static void ipa_dyndns_sdap_update_done(struct tevent_req *subreq)
215 : {
216 0 : struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
217 : errno_t ret;
218 :
219 0 : ret = sdap_dyndns_update_recv(subreq);
220 0 : talloc_zfree(subreq);
221 0 : if (ret != EOK) {
222 0 : DEBUG(SSSDBG_OP_FAILURE,
223 : "Dynamic DNS update failed [%d]: %s\n", ret, sss_strerror(ret));
224 0 : tevent_req_error(req, ret);
225 0 : return;
226 : }
227 :
228 0 : tevent_req_done(req);
229 : }
230 :
231 0 : static errno_t ipa_dyndns_update_recv(struct tevent_req *req)
232 : {
233 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
234 :
235 0 : return EOK;
236 : }
|