Line data Source code
1 : /*
2 : SSSD
3 :
4 : ad_dyndns.c
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 <ctype.h>
26 : #include "util/util.h"
27 : #include "providers/ldap/sdap_dyndns.h"
28 : #include "providers/data_provider.h"
29 : #include "providers/dp_dyndns.h"
30 : #include "providers/ad/ad_common.h"
31 :
32 : void ad_dyndns_update(void *pvt);
33 :
34 0 : errno_t ad_dyndns_init(struct be_ctx *be_ctx,
35 : struct ad_options *ad_opts)
36 : {
37 : errno_t ret;
38 :
39 : /* nsupdate is available. Dynamic updates
40 : * are supported
41 : */
42 0 : ret = ad_get_dyndns_options(be_ctx, ad_opts);
43 0 : if (ret != EOK) {
44 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set AD options\n");
45 0 : return ret;
46 : }
47 :
48 0 : if (dp_opt_get_bool(ad_opts->dyndns_ctx->opts,
49 0 : DP_OPT_DYNDNS_UPDATE) == false) {
50 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Dynamic DNS updates not set\n");
51 0 : return EOK;
52 : }
53 :
54 0 : DEBUG(SSSDBG_CONF_SETTINGS,
55 : "Dynamic DNS updates are on. Checking for nsupdate..\n");
56 0 : ret = be_nsupdate_check();
57 0 : if (ret == ENOENT) {
58 0 : DEBUG(SSSDBG_MINOR_FAILURE,
59 : "DNS updates requested but nsupdate not available\n");
60 0 : return EOK;
61 0 : } else if (ret != EOK) {
62 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not check for nsupdate\n");
63 0 : return ret;
64 : }
65 :
66 0 : ad_opts->be_res = be_ctx->be_res;
67 0 : if (ad_opts->be_res == NULL) {
68 0 : DEBUG(SSSDBG_OP_FAILURE, "Resolver must be initialized in order "
69 : "to use the AD dynamic DNS updates\n");
70 0 : return EINVAL;
71 : }
72 :
73 0 : ret = be_nsupdate_init_timer(ad_opts->dyndns_ctx, be_ctx->ev,
74 : ad_dyndns_timer, ad_opts);
75 0 : if (ret != EOK) {
76 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up periodic update\n");
77 0 : return ret;
78 : }
79 :
80 0 : ret = be_add_online_cb(be_ctx, be_ctx,
81 : ad_dyndns_update,
82 : ad_opts, NULL);
83 0 : if (ret != EOK) {
84 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up online callback\n");
85 0 : return ret;
86 : }
87 :
88 0 : return EOK;
89 : }
90 :
91 : static void ad_dyndns_timer_connected(struct tevent_req *req);
92 :
93 0 : void ad_dyndns_timer(void *pvt)
94 : {
95 0 : struct ad_options *ctx = talloc_get_type(pvt, struct ad_options);
96 0 : struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
97 : struct tevent_req *req;
98 :
99 0 : req = sdap_dyndns_timer_conn_send(ctx, sdap_ctx->be->ev, sdap_ctx,
100 : ctx->dyndns_ctx);
101 0 : if (req == NULL) {
102 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
103 : /* Not much we can do. Just attempt to reschedule */
104 0 : be_nsupdate_timer_schedule(sdap_ctx->be->ev, ctx->dyndns_ctx);
105 0 : return;
106 : }
107 0 : tevent_req_set_callback(req, ad_dyndns_timer_connected, ctx);
108 : }
109 :
110 0 : static void ad_dyndns_timer_connected(struct tevent_req *req)
111 : {
112 : errno_t ret;
113 0 : struct ad_options *ctx = tevent_req_callback_data(req, struct ad_options);
114 :
115 0 : ret = sdap_dyndns_timer_conn_recv(req);
116 0 : talloc_zfree(req);
117 0 : if (ret != EOK) {
118 0 : DEBUG(SSSDBG_OP_FAILURE,
119 : "Failed to connect to AD: [%d](%s)\n", ret, sss_strerror(ret));
120 0 : return;
121 : }
122 :
123 0 : return ad_dyndns_update(ctx);
124 : }
125 :
126 : static struct tevent_req *ad_dyndns_update_send(struct ad_options *ctx);
127 : static errno_t ad_dyndns_update_recv(struct tevent_req *req);
128 : static void ad_dyndns_nsupdate_done(struct tevent_req *req);
129 :
130 0 : void ad_dyndns_update(void *pvt)
131 : {
132 0 : struct ad_options *ctx = talloc_get_type(pvt, struct ad_options);
133 0 : struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
134 : struct tevent_req *req;
135 :
136 : /* Schedule timer after provider went offline */
137 0 : be_nsupdate_timer_schedule(sdap_ctx->be->ev, ctx->dyndns_ctx);
138 :
139 0 : req = ad_dyndns_update_send(ctx);
140 0 : if (req == NULL) {
141 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not update DNS\n");
142 0 : return;
143 : }
144 0 : tevent_req_set_callback(req, ad_dyndns_nsupdate_done, NULL);
145 : }
146 :
147 0 : static void ad_dyndns_nsupdate_done(struct tevent_req *req)
148 : {
149 0 : int ret = ad_dyndns_update_recv(req);
150 0 : talloc_free(req);
151 0 : if (ret != EOK) {
152 0 : DEBUG(SSSDBG_OP_FAILURE, "Updating DNS entry failed [%d]: %s\n",
153 : ret, sss_strerror(ret));
154 0 : return;
155 : }
156 :
157 0 : DEBUG(SSSDBG_TRACE_FUNC, "DNS update finished\n");
158 : }
159 :
160 : struct ad_dyndns_update_state {
161 : struct ad_options *ad_ctx;
162 : };
163 :
164 : static void ad_dyndns_sdap_update_done(struct tevent_req *subreq);
165 :
166 : static struct tevent_req *
167 0 : ad_dyndns_update_send(struct ad_options *ctx)
168 : {
169 : int ret;
170 : struct ad_dyndns_update_state *state;
171 : struct tevent_req *req, *subreq;
172 0 : struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
173 : LDAPURLDesc *lud;
174 :
175 0 : DEBUG(SSSDBG_TRACE_FUNC, "Performing update\n");
176 :
177 0 : req = tevent_req_create(ctx, &state, struct ad_dyndns_update_state);
178 0 : if (req == NULL) {
179 0 : return NULL;
180 : }
181 0 : state->ad_ctx = ctx;
182 :
183 0 : if (ctx->dyndns_ctx->last_refresh + 60 > time(NULL) ||
184 0 : ctx->dyndns_ctx->timer_in_progress) {
185 0 : DEBUG(SSSDBG_FUNC_DATA, "Last periodic update ran recently or timer "
186 : "in progress, not scheduling another update\n");
187 0 : tevent_req_done(req);
188 0 : tevent_req_post(req, sdap_ctx->be->ev);
189 0 : return req;
190 : }
191 0 : state->ad_ctx->dyndns_ctx->last_refresh = time(NULL);
192 :
193 0 : ret = ldap_url_parse(ctx->service->sdap->uri, &lud);
194 0 : if (ret != LDAP_SUCCESS) {
195 0 : DEBUG(SSSDBG_CRIT_FAILURE,
196 : "Failed to parse ldap URI (%s)!\n", ctx->service->sdap->uri);
197 0 : ret = EINVAL;
198 0 : goto done;
199 : }
200 :
201 0 : if (lud->lud_scheme != NULL &&
202 0 : strcasecmp(lud->lud_scheme, "ldapi") == 0) {
203 0 : DEBUG(SSSDBG_CRIT_FAILURE,
204 : "The LDAP scheme is ldapi://, cannot proceed with update\n");
205 0 : ldap_free_urldesc(lud);
206 0 : ret = EINVAL;
207 0 : goto done;
208 : }
209 :
210 0 : if (lud->lud_host == NULL) {
211 0 : DEBUG(SSSDBG_CRIT_FAILURE,
212 : "The LDAP URI (%s) did not contain a host name\n",
213 : ctx->service->sdap->uri);
214 0 : ldap_free_urldesc(lud);
215 0 : ret = EINVAL;
216 0 : goto done;
217 : }
218 :
219 0 : subreq = sdap_dyndns_update_send(state, sdap_ctx->be->ev,
220 : sdap_ctx->be,
221 0 : ctx->dyndns_ctx->opts,
222 : sdap_ctx,
223 0 : ctx->dyndns_ctx->auth_type,
224 0 : dp_opt_get_string(ctx->dyndns_ctx->opts,
225 : DP_OPT_DYNDNS_IFACE),
226 0 : dp_opt_get_string(ctx->basic,
227 : AD_HOSTNAME),
228 0 : dp_opt_get_string(ctx->basic,
229 : AD_KRB5_REALM),
230 0 : dp_opt_get_int(ctx->dyndns_ctx->opts,
231 : DP_OPT_DYNDNS_TTL),
232 : false);
233 0 : if (!subreq) {
234 0 : ret = EIO;
235 0 : DEBUG(SSSDBG_OP_FAILURE,
236 : "sdap_id_op_connect_send failed: [%d](%s)\n",
237 : ret, sss_strerror(ret));
238 0 : goto done;
239 : }
240 0 : tevent_req_set_callback(subreq, ad_dyndns_sdap_update_done, req);
241 :
242 0 : ret = EOK;
243 : done:
244 0 : if (ret != EOK) {
245 0 : tevent_req_error(req, ret);
246 0 : tevent_req_post(req, sdap_ctx->be->ev);
247 : }
248 0 : return req;
249 : }
250 :
251 0 : static void ad_dyndns_sdap_update_done(struct tevent_req *subreq)
252 : {
253 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
254 : struct tevent_req);
255 : errno_t ret;
256 :
257 0 : ret = sdap_dyndns_update_recv(subreq);
258 0 : talloc_zfree(subreq);
259 0 : if (ret != EOK) {
260 0 : DEBUG(SSSDBG_OP_FAILURE,
261 : "Dynamic DNS update failed [%d]: %s\n",
262 : ret, sss_strerror(ret));
263 0 : tevent_req_error(req, ret);
264 0 : return;
265 : }
266 :
267 0 : tevent_req_done(req);
268 : }
269 :
270 0 : static errno_t ad_dyndns_update_recv(struct tevent_req *req)
271 : {
272 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
273 :
274 0 : return EOK;
275 : }
|