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 : struct tevent_req *
43 : hosts_get_send(TALLOC_CTX *memctx,
44 : struct tevent_context *ev,
45 : struct ipa_hostid_ctx *hostid_ctx,
46 : const char *name,
47 : const char *alias);
48 : static errno_t
49 : hosts_get_recv(struct tevent_req *req,
50 : int *dp_error_out);
51 :
52 : static void
53 : ipa_host_info_hosts_done(struct tevent_req *req);
54 :
55 : void
56 0 : ipa_host_info_handler(struct be_req *breq)
57 : {
58 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
59 : struct ipa_hostid_ctx *hostid_ctx;
60 : struct sdap_id_ctx *ctx;
61 : struct be_host_req *hr;
62 : struct tevent_req *req;
63 0 : int dp_error = DP_ERR_FATAL;
64 0 : errno_t ret = EOK;
65 0 : const char *err = "Unknown Error";
66 :
67 0 : hostid_ctx = talloc_get_type(be_ctx->bet_info[BET_HOSTID].pvt_bet_data,
68 : struct ipa_hostid_ctx);
69 0 : ctx = hostid_ctx->sdap_id_ctx;
70 :
71 0 : if (be_is_offline(ctx->be)) {
72 0 : dp_error = DP_ERR_OFFLINE;
73 0 : ret = EAGAIN;
74 0 : err = "Offline";
75 0 : goto done;
76 : }
77 :
78 0 : hr = talloc_get_type(be_req_get_data(breq), struct be_host_req);
79 :
80 0 : if (hr->filter_type != BE_FILTER_NAME) {
81 0 : ret = EINVAL;
82 0 : err = "Invalid filter type";
83 0 : goto done;
84 : }
85 :
86 0 : req = hosts_get_send(breq, be_ctx->ev, hostid_ctx,
87 0 : hr->name, hr->alias);
88 0 : if (!req) {
89 0 : ret = ENOMEM;
90 0 : err = "Out of memory";
91 0 : goto done;
92 : }
93 :
94 0 : tevent_req_set_callback(req, ipa_host_info_hosts_done, breq);
95 :
96 0 : ret = EOK;
97 :
98 : done:
99 0 : if (ret != EOK) return sdap_handler_done(breq, dp_error, ret, err);
100 : }
101 :
102 : static void
103 0 : ipa_host_info_complete(struct be_req *breq, int dp_error,
104 : errno_t ret, const char *default_error_text)
105 : {
106 : const char* error_text;
107 :
108 0 : if (dp_error == DP_ERR_OK) {
109 0 : if (ret == EOK) {
110 0 : error_text = NULL;
111 : } else {
112 0 : DEBUG(SSSDBG_CRIT_FAILURE,
113 : "Bug: dp_error is OK on failed request\n");
114 0 : dp_error = DP_ERR_FATAL;
115 0 : error_text = default_error_text;
116 : }
117 0 : } else if (dp_error == DP_ERR_OFFLINE) {
118 0 : error_text = "Offline";
119 0 : } else if (dp_error == DP_ERR_FATAL && ret == ENOMEM) {
120 0 : error_text = "Out of memory";
121 : } else {
122 0 : error_text = default_error_text;
123 : }
124 :
125 0 : sdap_handler_done(breq, dp_error, ret, error_text);
126 0 : }
127 :
128 : static void
129 0 : ipa_host_info_hosts_done(struct tevent_req *req)
130 : {
131 0 : struct be_req *breq = tevent_req_callback_data(req, struct be_req);
132 : int ret, dp_error;
133 :
134 0 : ret = hosts_get_recv(req, &dp_error);
135 0 : talloc_zfree(req);
136 :
137 0 : ipa_host_info_complete(breq, dp_error, ret, "Host lookup failed");
138 0 : }
139 :
140 : static errno_t
141 : hosts_get_retry(struct tevent_req *req);
142 : static void
143 : hosts_get_connect_done(struct tevent_req *subreq);
144 : static void
145 : hosts_get_done(struct tevent_req *subreq);
146 :
147 : struct tevent_req *
148 0 : hosts_get_send(TALLOC_CTX *memctx,
149 : struct tevent_context *ev,
150 : struct ipa_hostid_ctx *hostid_ctx,
151 : const char *name,
152 : const char *alias)
153 : {
154 : struct tevent_req *req;
155 : struct hosts_get_state *state;
156 : struct sdap_id_ctx *ctx;
157 : errno_t ret;
158 :
159 0 : ctx = hostid_ctx->sdap_id_ctx;
160 :
161 0 : req = tevent_req_create(memctx, &state, struct hosts_get_state);
162 0 : if (!req) return NULL;
163 :
164 0 : state->ev = ev;
165 0 : state->ctx = hostid_ctx;
166 0 : state->dp_error = DP_ERR_FATAL;
167 :
168 0 : state->op = sdap_id_op_create(state, ctx->conn->conn_cache);
169 0 : if (!state->op) {
170 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
171 0 : ret = ENOMEM;
172 0 : goto fail;
173 : }
174 :
175 0 : state->domain = ctx->be->domain;
176 0 : state->name = name;
177 0 : state->alias = alias;
178 :
179 0 : ret = hosts_get_retry(req);
180 0 : if (ret != EOK) {
181 0 : goto fail;
182 : }
183 :
184 0 : return req;
185 :
186 : fail:
187 0 : tevent_req_error(req, ret);
188 0 : tevent_req_post(req, ev);
189 0 : return req;
190 : }
191 :
192 : static errno_t
193 0 : hosts_get_retry(struct tevent_req *req)
194 : {
195 0 : struct hosts_get_state *state = tevent_req_data(req,
196 : struct hosts_get_state);
197 : struct tevent_req *subreq;
198 0 : errno_t ret = EOK;
199 :
200 0 : subreq = sdap_id_op_connect_send(state->op, state, &ret);
201 0 : if (!subreq) {
202 0 : return ret;
203 : }
204 :
205 0 : tevent_req_set_callback(subreq, hosts_get_connect_done, req);
206 0 : return EOK;
207 : }
208 :
209 : static void
210 0 : hosts_get_connect_done(struct tevent_req *subreq)
211 : {
212 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
213 : struct tevent_req);
214 0 : struct hosts_get_state *state = tevent_req_data(req,
215 : struct hosts_get_state);
216 0 : int dp_error = DP_ERR_FATAL;
217 : errno_t ret;
218 :
219 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
220 0 : talloc_zfree(subreq);
221 :
222 0 : if (ret != EOK) {
223 0 : state->dp_error = dp_error;
224 0 : tevent_req_error(req, ret);
225 0 : return;
226 : }
227 :
228 0 : subreq = ipa_host_info_send(state, state->ev,
229 : sdap_id_op_handle(state->op),
230 0 : state->ctx->sdap_id_ctx->opts, state->name,
231 0 : state->ctx->ipa_opts->host_map, NULL,
232 0 : state->ctx->host_search_bases);
233 0 : if (!subreq) {
234 0 : tevent_req_error(req, ENOMEM);
235 0 : return;
236 : }
237 0 : tevent_req_set_callback(subreq, hosts_get_done, req);
238 : }
239 :
240 : static void
241 0 : hosts_get_done(struct tevent_req *subreq)
242 : {
243 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
244 : struct tevent_req);
245 0 : struct hosts_get_state *state = tevent_req_data(req,
246 : struct hosts_get_state);
247 0 : int dp_error = DP_ERR_FATAL;
248 : errno_t ret;
249 : struct sysdb_attrs *attrs;
250 0 : time_t now = time(NULL);
251 :
252 0 : ret = ipa_host_info_recv(subreq, state,
253 : &state->count, &state->hosts,
254 : NULL, NULL);
255 0 : talloc_zfree(subreq);
256 :
257 0 : ret = sdap_id_op_done(state->op, ret, &dp_error);
258 0 : if (dp_error == DP_ERR_OK && ret != EOK) {
259 : /* retry */
260 0 : ret = hosts_get_retry(req);
261 0 : if (ret != EOK) {
262 0 : goto done;
263 : }
264 0 : return;
265 : }
266 :
267 0 : if (ret != EOK && ret != ENOENT) {
268 0 : goto done;
269 : }
270 :
271 0 : if (state->count == 0) {
272 0 : DEBUG(SSSDBG_OP_FAILURE,
273 : "No host with name [%s] found.\n", state->name);
274 :
275 0 : ret = sysdb_delete_ssh_host(state->domain, state->name);
276 0 : if (ret != EOK && ret != ENOENT) {
277 0 : goto done;
278 : }
279 :
280 0 : ret = EINVAL;
281 0 : goto done;
282 : }
283 :
284 0 : if (state->count > 1) {
285 0 : DEBUG(SSSDBG_CRIT_FAILURE,
286 : "Found more than one host with name [%s].\n", state->name);
287 0 : ret = EINVAL;
288 0 : goto done;
289 : }
290 :
291 0 : attrs = sysdb_new_attrs(state);
292 0 : if (!attrs) {
293 0 : ret = ENOMEM;
294 0 : goto done;
295 : }
296 :
297 : /* we are interested only in the host keys */
298 0 : ret = sysdb_attrs_copy_values(state->hosts[0], attrs, SYSDB_SSH_PUBKEY);
299 0 : if (ret != EOK) {
300 0 : goto done;
301 : }
302 :
303 0 : ret = sysdb_store_ssh_host(state->domain, state->name, state->alias,
304 0 : state->domain->ssh_host_timeout, now, attrs);
305 0 : if (ret != EOK) {
306 0 : goto done;
307 : }
308 :
309 0 : dp_error = DP_ERR_OK;
310 :
311 : done:
312 0 : state->dp_error = dp_error;
313 0 : if (ret == EOK) {
314 0 : tevent_req_done(req);
315 : } else {
316 0 : tevent_req_error(req, ret);
317 : }
318 : }
319 :
320 : static errno_t
321 0 : hosts_get_recv(struct tevent_req *req,
322 : int *dp_error_out)
323 : {
324 0 : struct hosts_get_state *state = tevent_req_data(req,
325 : struct hosts_get_state);
326 :
327 0 : if (dp_error_out) {
328 0 : *dp_error_out = state->dp_error;
329 : }
330 :
331 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
332 :
333 0 : return EOK;
334 : }
|