Line data Source code
1 : /*
2 : Authors:
3 : Jan Cholasta <jcholast@redhat.com>
4 :
5 : Copyright (C) 2012 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "util/util.h"
22 : #include "util/crypto/sss_crypto.h"
23 : #include "db/sysdb_ssh.h"
24 : #include "providers/ldap/ldap_common.h"
25 : #include "providers/ipa/ipa_common.h"
26 : #include "providers/ipa/ipa_hostid.h"
27 : #include "providers/ipa/ipa_hosts.h"
28 :
29 : struct hosts_get_state {
30 : struct tevent_context *ev;
31 : struct ipa_hostid_ctx *ctx;
32 : struct sdap_id_op *op;
33 : struct sss_domain_info *domain;
34 : const char *name;
35 : const char *alias;
36 :
37 : size_t count;
38 : struct sysdb_attrs **hosts;
39 : int dp_error;
40 : };
41 :
42 : static errno_t
43 : hosts_get_retry(struct tevent_req *req);
44 : static void
45 : hosts_get_connect_done(struct tevent_req *subreq);
46 : static void
47 : hosts_get_done(struct tevent_req *subreq);
48 :
49 : struct tevent_req *
50 0 : hosts_get_send(TALLOC_CTX *memctx,
51 : struct tevent_context *ev,
52 : struct ipa_hostid_ctx *hostid_ctx,
53 : const char *name,
54 : const char *alias)
55 : {
56 : struct tevent_req *req;
57 : struct hosts_get_state *state;
58 : struct sdap_id_ctx *ctx;
59 : errno_t ret;
60 :
61 0 : ctx = hostid_ctx->sdap_id_ctx;
62 :
63 0 : req = tevent_req_create(memctx, &state, struct hosts_get_state);
64 0 : if (!req) return NULL;
65 :
66 0 : state->ev = ev;
67 0 : state->ctx = hostid_ctx;
68 0 : state->dp_error = DP_ERR_FATAL;
69 :
70 0 : state->op = sdap_id_op_create(state, ctx->conn->conn_cache);
71 0 : if (!state->op) {
72 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
73 0 : ret = ENOMEM;
74 0 : goto fail;
75 : }
76 :
77 0 : state->domain = ctx->be->domain;
78 0 : state->name = name;
79 0 : state->alias = alias;
80 :
81 0 : ret = hosts_get_retry(req);
82 0 : if (ret != EOK) {
83 0 : goto fail;
84 : }
85 :
86 0 : return req;
87 :
88 : fail:
89 0 : tevent_req_error(req, ret);
90 0 : tevent_req_post(req, ev);
91 0 : return req;
92 : }
93 :
94 : static errno_t
95 0 : hosts_get_retry(struct tevent_req *req)
96 : {
97 0 : struct hosts_get_state *state = tevent_req_data(req,
98 : struct hosts_get_state);
99 : struct tevent_req *subreq;
100 0 : errno_t ret = EOK;
101 :
102 0 : subreq = sdap_id_op_connect_send(state->op, state, &ret);
103 0 : if (!subreq) {
104 0 : return ret;
105 : }
106 :
107 0 : tevent_req_set_callback(subreq, hosts_get_connect_done, req);
108 0 : return EOK;
109 : }
110 :
111 : static void
112 0 : hosts_get_connect_done(struct tevent_req *subreq)
113 : {
114 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
115 : struct tevent_req);
116 0 : struct hosts_get_state *state = tevent_req_data(req,
117 : struct hosts_get_state);
118 0 : int dp_error = DP_ERR_FATAL;
119 : errno_t ret;
120 :
121 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
122 0 : talloc_zfree(subreq);
123 :
124 0 : if (ret != EOK) {
125 0 : state->dp_error = dp_error;
126 0 : tevent_req_error(req, ret);
127 0 : return;
128 : }
129 :
130 0 : subreq = ipa_host_info_send(state, state->ev,
131 : sdap_id_op_handle(state->op),
132 0 : state->ctx->sdap_id_ctx->opts, state->name,
133 0 : state->ctx->ipa_opts->host_map, NULL,
134 0 : state->ctx->host_search_bases);
135 0 : if (!subreq) {
136 0 : tevent_req_error(req, ENOMEM);
137 0 : return;
138 : }
139 0 : tevent_req_set_callback(subreq, hosts_get_done, req);
140 : }
141 :
142 : static void
143 0 : hosts_get_done(struct tevent_req *subreq)
144 : {
145 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
146 : struct tevent_req);
147 0 : struct hosts_get_state *state = tevent_req_data(req,
148 : struct hosts_get_state);
149 0 : int dp_error = DP_ERR_FATAL;
150 : errno_t ret;
151 : struct sysdb_attrs *attrs;
152 0 : time_t now = time(NULL);
153 :
154 0 : ret = ipa_host_info_recv(subreq, state,
155 : &state->count, &state->hosts,
156 : NULL, NULL);
157 0 : talloc_zfree(subreq);
158 :
159 0 : ret = sdap_id_op_done(state->op, ret, &dp_error);
160 0 : if (dp_error == DP_ERR_OK && ret != EOK) {
161 : /* retry */
162 0 : ret = hosts_get_retry(req);
163 0 : if (ret != EOK) {
164 0 : goto done;
165 : }
166 0 : return;
167 : }
168 :
169 0 : if (ret != EOK && ret != ENOENT) {
170 0 : goto done;
171 : }
172 :
173 0 : if (state->count == 0) {
174 0 : DEBUG(SSSDBG_OP_FAILURE,
175 : "No host with name [%s] found.\n", state->name);
176 :
177 0 : ret = sysdb_delete_ssh_host(state->domain, state->name);
178 0 : if (ret != EOK && ret != ENOENT) {
179 0 : goto done;
180 : }
181 :
182 0 : ret = EINVAL;
183 0 : goto done;
184 : }
185 :
186 0 : if (state->count > 1) {
187 0 : DEBUG(SSSDBG_CRIT_FAILURE,
188 : "Found more than one host with name [%s].\n", state->name);
189 0 : ret = EINVAL;
190 0 : goto done;
191 : }
192 :
193 0 : attrs = sysdb_new_attrs(state);
194 0 : if (!attrs) {
195 0 : ret = ENOMEM;
196 0 : goto done;
197 : }
198 :
199 : /* we are interested only in the host keys */
200 0 : ret = sysdb_attrs_copy_values(state->hosts[0], attrs, SYSDB_SSH_PUBKEY);
201 0 : if (ret != EOK) {
202 0 : goto done;
203 : }
204 :
205 0 : ret = sysdb_store_ssh_host(state->domain, state->name, state->alias,
206 0 : state->domain->ssh_host_timeout, now, attrs);
207 0 : if (ret != EOK) {
208 0 : goto done;
209 : }
210 :
211 0 : dp_error = DP_ERR_OK;
212 :
213 : done:
214 0 : state->dp_error = dp_error;
215 0 : if (ret == EOK) {
216 0 : tevent_req_done(req);
217 : } else {
218 0 : tevent_req_error(req, ret);
219 : }
220 : }
221 :
222 : static errno_t
223 0 : hosts_get_recv(struct tevent_req *req,
224 : int *dp_error_out)
225 : {
226 0 : struct hosts_get_state *state = tevent_req_data(req,
227 : struct hosts_get_state);
228 :
229 0 : if (dp_error_out) {
230 0 : *dp_error_out = state->dp_error;
231 : }
232 :
233 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
234 :
235 0 : return EOK;
236 : }
237 :
238 : struct ipa_hostid_handler_state {
239 : struct dp_reply_std reply;
240 : };
241 :
242 : static void ipa_hostid_handler_done(struct tevent_req *subreq);
243 :
244 : struct tevent_req *
245 0 : ipa_hostid_handler_send(TALLOC_CTX *mem_ctx,
246 : struct ipa_hostid_ctx *hostid_ctx,
247 : struct dp_hostid_data *data,
248 : struct dp_req_params *params)
249 : {
250 : struct ipa_hostid_handler_state *state;
251 : struct tevent_req *subreq;
252 : struct tevent_req *req;
253 : errno_t ret;
254 :
255 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_hostid_handler_state);
256 0 : if (req == NULL) {
257 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
258 0 : return NULL;
259 : }
260 :
261 0 : subreq = hosts_get_send(state, params->ev, hostid_ctx,
262 : data->name, data->alias);
263 0 : if (subreq == NULL) {
264 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request\n");
265 0 : ret = ENOMEM;
266 0 : goto immediately;
267 : }
268 :
269 0 : tevent_req_set_callback(subreq, ipa_hostid_handler_done, req);
270 :
271 0 : return req;
272 :
273 : immediately:
274 0 : dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
275 :
276 : /* TODO For backward compatibility we always return EOK to DP now. */
277 0 : tevent_req_done(req);
278 0 : tevent_req_post(req, params->ev);
279 :
280 0 : return req;
281 : }
282 :
283 0 : static void ipa_hostid_handler_done(struct tevent_req *subreq)
284 : {
285 : struct ipa_hostid_handler_state *state;
286 : struct tevent_req *req;
287 : int dp_error;
288 : errno_t ret;
289 :
290 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
291 0 : state = tevent_req_data(req, struct ipa_hostid_handler_state);
292 :
293 0 : ret = hosts_get_recv(subreq, &dp_error);
294 0 : talloc_zfree(subreq);
295 :
296 : /* TODO For backward compatibility we always return EOK to DP now. */
297 0 : dp_reply_std_set(&state->reply, dp_error, ret, NULL);
298 0 : tevent_req_done(req);
299 0 : }
300 :
301 : errno_t
302 0 : ipa_hostid_handler_recv(TALLOC_CTX *mem_ctx,
303 : struct tevent_req *req,
304 : struct dp_reply_std *data)
305 : {
306 0 : struct ipa_hostid_handler_state *state = NULL;
307 :
308 0 : state = tevent_req_data(req, struct ipa_hostid_handler_state);
309 :
310 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
311 :
312 0 : *data = state->reply;
313 :
314 0 : return EOK;
315 : }
|