Line data Source code
1 : /*
2 : SSSD
3 :
4 : Authors:
5 : Jan Zeleny <jzeleny@redhat.com>
6 :
7 : Copyright (C) 2012 Red Hat
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "util/util.h"
24 : #include "db/sysdb.h"
25 : #include "providers/ldap/sdap_async.h"
26 : #include "providers/ipa/ipa_hosts.h"
27 : #include "providers/ipa/ipa_common.h"
28 :
29 : struct ipa_host_state {
30 : struct tevent_context *ev;
31 : struct sysdb_ctx *sysdb;
32 : struct sdap_handle *sh;
33 : struct sdap_options *opts;
34 : const char **attrs;
35 : struct sdap_attr_map *host_map;
36 : struct sdap_attr_map *hostgroup_map;
37 :
38 : struct sdap_search_base **search_bases;
39 : int search_base_iter;
40 :
41 : char *cur_filter;
42 : char *host_filter;
43 :
44 : const char *hostname;
45 :
46 : /* Return values */
47 : size_t host_count;
48 : struct sysdb_attrs **hosts;
49 :
50 : size_t hostgroup_count;
51 : struct sysdb_attrs **hostgroups;
52 : struct sdap_attr_map_info *ipa_hostgroup_map;
53 : };
54 :
55 : static void
56 : ipa_host_info_done(struct tevent_req *subreq);
57 :
58 : static void
59 : ipa_hostgroup_info_done(struct tevent_req *subreq);
60 :
61 : static errno_t
62 : ipa_host_info_next(struct tevent_req *req,
63 : struct ipa_host_state *state);
64 : static errno_t
65 : ipa_hostgroup_info_next(struct tevent_req *req,
66 : struct ipa_host_state *state);
67 :
68 : /**
69 : * hostname == NULL -> look up all hosts / host groups
70 : * hostname != NULL -> look up only given host and groups
71 : * it's member of
72 : * hostgroup_map == NULL -> skip looking up hostgroups
73 : */
74 : struct tevent_req *
75 0 : ipa_host_info_send(TALLOC_CTX *mem_ctx,
76 : struct tevent_context *ev,
77 : struct sdap_handle *sh,
78 : struct sdap_options *opts,
79 : const char *hostname,
80 : struct sdap_attr_map *host_map,
81 : struct sdap_attr_map *hostgroup_map,
82 : struct sdap_search_base **search_bases)
83 : {
84 : errno_t ret;
85 : struct ipa_host_state *state;
86 : struct tevent_req *req;
87 :
88 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_host_state);
89 0 : if (req == NULL) {
90 0 : return NULL;
91 : }
92 :
93 0 : state->ev = ev;
94 0 : state->sh = sh;
95 0 : state->opts = opts;
96 0 : state->hostname = hostname;
97 0 : state->search_bases = search_bases;
98 0 : state->search_base_iter = 0;
99 0 : state->cur_filter = NULL;
100 0 : state->host_map = host_map;
101 0 : state->hostgroup_map = hostgroup_map;
102 :
103 0 : ret = build_attrs_from_map(state, host_map, IPA_OPTS_HOST,
104 0 : NULL, &state->attrs, NULL);
105 0 : if (ret != EOK) {
106 0 : goto immediate;
107 : }
108 :
109 0 : if (hostname == NULL) {
110 0 : state->host_filter = talloc_asprintf(state, "(objectClass=%s)",
111 : host_map[IPA_OC_HOST].name);
112 : } else {
113 0 : state->host_filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=%s))",
114 : host_map[IPA_OC_HOST].name,
115 0 : host_map[IPA_AT_HOST_FQDN].name,
116 : hostname);
117 : }
118 0 : if (state->host_filter == NULL) {
119 0 : ret = ENOMEM;
120 0 : goto immediate;
121 : }
122 :
123 0 : ret = ipa_host_info_next(req, state);
124 0 : if (ret == EOK) {
125 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No host search base configured?\n");
126 0 : ret = EINVAL;
127 : }
128 :
129 0 : if (ret != EAGAIN) {
130 0 : goto immediate;
131 : }
132 :
133 0 : return req;
134 :
135 : immediate:
136 0 : if (ret == EOK) {
137 0 : tevent_req_done(req);
138 : } else {
139 0 : tevent_req_error(req, ret);
140 : }
141 0 : tevent_req_post(req, ev);
142 0 : return req;
143 : }
144 :
145 0 : static errno_t ipa_host_info_next(struct tevent_req *req,
146 : struct ipa_host_state *state)
147 : {
148 : struct sdap_search_base *base;
149 : struct tevent_req *subreq;
150 :
151 0 : base = state->search_bases[state->search_base_iter];
152 0 : if (base == NULL) {
153 0 : return EOK;
154 : }
155 :
156 0 : talloc_zfree(state->cur_filter);
157 0 : state->cur_filter = sdap_combine_filters(state, state->host_filter,
158 : base->filter);
159 0 : if (state->cur_filter == NULL) {
160 0 : return ENOMEM;
161 : }
162 :
163 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts,
164 : state->sh, base->basedn,
165 0 : base->scope, state->cur_filter,
166 : state->attrs, state->host_map,
167 : IPA_OPTS_HOST,
168 0 : dp_opt_get_int(state->opts->basic,
169 : SDAP_ENUM_SEARCH_TIMEOUT),
170 : true);
171 0 : if (subreq == NULL) {
172 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error requesting host info\n");
173 0 : talloc_zfree(state->cur_filter);
174 0 : return EIO;
175 : }
176 0 : tevent_req_set_callback(subreq, ipa_host_info_done, req);
177 :
178 0 : return EAGAIN;
179 : }
180 :
181 : static void
182 0 : ipa_host_info_done(struct tevent_req *subreq)
183 : {
184 : errno_t ret;
185 0 : struct tevent_req *req =
186 0 : tevent_req_callback_data(subreq, struct tevent_req);
187 0 : struct ipa_host_state *state =
188 0 : tevent_req_data(req, struct ipa_host_state);
189 : const char *host_dn;
190 :
191 0 : ret = sdap_get_generic_recv(subreq, state,
192 : &state->host_count,
193 : &state->hosts);
194 0 : talloc_zfree(subreq);
195 0 : if (ret != EOK) {
196 0 : tevent_req_error(req, ret);
197 0 : return;
198 : }
199 :
200 0 : if (state->host_count == 0) {
201 0 : state->search_base_iter++;
202 0 : ret = ipa_host_info_next(req, state);
203 0 : if (ret == EOK) {
204 : /* No more search bases to try */
205 0 : tevent_req_error(req, ENOENT);
206 0 : } else if (ret != EAGAIN) {
207 0 : tevent_req_error(req, ret);
208 : }
209 0 : return;
210 : }
211 :
212 0 : if (state->hostgroup_map) {
213 0 : talloc_free(state->attrs);
214 0 : ret = build_attrs_from_map(state, state->hostgroup_map,
215 : IPA_OPTS_HOSTGROUP, NULL,
216 : &state->attrs, NULL);
217 0 : if (ret != EOK) {
218 0 : tevent_req_error(req, ret);
219 0 : return;
220 : }
221 :
222 : /* Look up host groups */
223 0 : if (state->hostname == NULL) {
224 0 : talloc_zfree(state->host_filter);
225 0 : state->host_filter = talloc_asprintf(state, "(objectClass=%s)",
226 0 : state->hostgroup_map[IPA_OC_HOSTGROUP].name);
227 0 : if (state->host_filter == NULL) {
228 0 : tevent_req_error(req, ENOMEM);
229 0 : return;
230 : }
231 0 : state->search_base_iter = 0;
232 :
233 0 : ret = ipa_hostgroup_info_next(req, state);
234 0 : if (ret == EOK) {
235 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No host search base configured?\n");
236 0 : tevent_req_error(req, EINVAL);
237 0 : return;
238 0 : } else if (ret != EAGAIN) {
239 0 : tevent_req_error(req, ret);
240 0 : return;
241 : }
242 : } else {
243 0 : state->ipa_hostgroup_map = talloc_zero(state, struct sdap_attr_map_info);
244 0 : if (state->ipa_hostgroup_map == NULL) {
245 0 : tevent_req_error(req, ENOMEM);
246 0 : return;
247 : }
248 0 : state->ipa_hostgroup_map->map = state->hostgroup_map;
249 0 : state->ipa_hostgroup_map->num_attrs = IPA_OPTS_HOSTGROUP;
250 :
251 0 : ret = sysdb_attrs_get_string(state->hosts[0], SYSDB_ORIG_DN, &host_dn);
252 0 : if (ret != EOK) {
253 0 : tevent_req_error(req, ret);
254 0 : return;
255 : }
256 :
257 0 : if (!sdap_has_deref_support(state->sh, state->opts)) {
258 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Server does not support deref\n");
259 0 : tevent_req_error(req, EIO);
260 0 : return;
261 : }
262 :
263 0 : subreq = sdap_deref_search_send(state, state->ev, state->opts, state->sh,
264 : host_dn,
265 0 : state->hostgroup_map[IPA_AT_HOSTGROUP_MEMBER_OF].name,
266 : state->attrs,
267 : 1, state->ipa_hostgroup_map,
268 0 : dp_opt_get_int(state->opts->basic,
269 : SDAP_ENUM_SEARCH_TIMEOUT));
270 0 : if (subreq == NULL) {
271 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error requesting host info\n");
272 0 : tevent_req_error(req, EIO);
273 0 : return;
274 : }
275 0 : tevent_req_set_callback(subreq, ipa_hostgroup_info_done, req);
276 : }
277 : } else {
278 : /* Nothing else to do, just complete the req */
279 0 : tevent_req_done(req);
280 : }
281 : }
282 :
283 0 : static errno_t ipa_hostgroup_info_next(struct tevent_req *req,
284 : struct ipa_host_state *state)
285 : {
286 : struct sdap_search_base *base;
287 : struct tevent_req *subreq;
288 :
289 0 : base = state->search_bases[state->search_base_iter];
290 0 : if (base == NULL) {
291 0 : return EOK;
292 : }
293 :
294 0 : talloc_zfree(state->cur_filter);
295 0 : state->cur_filter = sdap_combine_filters(state, state->host_filter,
296 : base->filter);
297 0 : if (state->cur_filter == NULL) {
298 0 : return ENOMEM;
299 : }
300 :
301 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
302 : base->basedn, base->scope,
303 0 : state->cur_filter, state->attrs,
304 : state->hostgroup_map,
305 : IPA_OPTS_HOSTGROUP,
306 0 : dp_opt_get_int(state->opts->basic,
307 : SDAP_ENUM_SEARCH_TIMEOUT),
308 : true);
309 0 : if (subreq == NULL) {
310 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error requesting hostgroup info\n");
311 0 : talloc_zfree(state->cur_filter);
312 0 : return EIO;
313 : }
314 0 : tevent_req_set_callback(subreq, ipa_hostgroup_info_done, req);
315 :
316 0 : return EAGAIN;
317 : }
318 :
319 : static void
320 0 : ipa_hostgroup_info_done(struct tevent_req *subreq)
321 : {
322 : errno_t ret;
323 0 : struct tevent_req *req =
324 0 : tevent_req_callback_data(subreq, struct tevent_req);
325 0 : struct ipa_host_state *state =
326 0 : tevent_req_data(req, struct ipa_host_state);
327 :
328 : size_t hostgroups_total;
329 : size_t hostgroup_count;
330 : struct sysdb_attrs **hostgroups;
331 : struct sdap_deref_attrs **deref_result;
332 : const char *hostgroup_name;
333 : const char *hostgroup_dn;
334 : int i, j;
335 :
336 0 : if (state->hostname == NULL) {
337 0 : ret = sdap_get_generic_recv(subreq, state,
338 : &hostgroup_count,
339 : &hostgroups);
340 0 : talloc_zfree(subreq);
341 0 : if (ret != EOK) {
342 0 : DEBUG(SSSDBG_OP_FAILURE,
343 : "sdap_get_generic_recv failed: [%d]\n", ret);
344 0 : tevent_req_error(req, ret);
345 0 : return;
346 : }
347 :
348 : /* Merge the two arrays */
349 0 : if (hostgroup_count > 0) {
350 0 : hostgroups_total = hostgroup_count + state->hostgroup_count;
351 0 : state->hostgroups = talloc_realloc(state, state->hostgroups,
352 : struct sysdb_attrs *,
353 : hostgroups_total);
354 0 : if (state->hostgroups == NULL) {
355 0 : tevent_req_error(req, ENOMEM);
356 0 : return;
357 : }
358 :
359 0 : i = 0;
360 0 : while(state->hostgroup_count < hostgroups_total) {
361 0 : state->hostgroups[state->hostgroup_count] =
362 0 : talloc_steal(state->hostgroups, hostgroups[i]);
363 0 : state->hostgroup_count++;
364 0 : i++;
365 : }
366 : }
367 :
368 : /* Now look in the next base */
369 0 : state->search_base_iter++;
370 0 : ret = ipa_hostgroup_info_next(req, state);
371 0 : if (ret != EOK && ret != EAGAIN) {
372 0 : tevent_req_error(req, ret);
373 : }
374 :
375 0 : if (ret != EOK) {
376 : /* Only continue if no error occurred
377 : * and no req was created */
378 0 : return;
379 : }
380 : } else {
381 0 : ret = sdap_deref_search_recv(subreq, state,
382 : &state->hostgroup_count,
383 : &deref_result);
384 0 : talloc_zfree(subreq);
385 0 : if (ret != EOK) goto done;
386 :
387 0 : if (state->hostgroup_count == 0) {
388 0 : DEBUG(SSSDBG_FUNC_DATA, "No host groups were dereferenced\n");
389 : } else {
390 0 : state->hostgroups = talloc_zero_array(state, struct sysdb_attrs *,
391 : state->hostgroup_count);
392 0 : if (state->hostgroups == NULL) {
393 0 : ret = ENOMEM;
394 0 : goto done;
395 : }
396 :
397 0 : j = 0;
398 0 : for (i = 0; i < state->hostgroup_count; i++) {
399 0 : ret = sysdb_attrs_get_string(deref_result[i]->attrs,
400 : SYSDB_ORIG_DN, &hostgroup_dn);
401 0 : if (ret != EOK) goto done;
402 :
403 0 : if (!sss_ldap_dn_in_search_bases(state, hostgroup_dn,
404 : state->search_bases,
405 : NULL)) {
406 0 : continue;
407 : }
408 :
409 0 : ret = sysdb_attrs_get_string(deref_result[i]->attrs,
410 0 : state->hostgroup_map[IPA_AT_HOSTGROUP_NAME].sys_name,
411 : &hostgroup_name);
412 0 : if (ret != EOK) goto done;
413 :
414 0 : DEBUG(SSSDBG_FUNC_DATA, "Dereferenced host group: %s\n",
415 : hostgroup_name);
416 0 : state->hostgroups[j] = talloc_steal(state->hostgroups,
417 : deref_result[i]->attrs);
418 0 : j++;
419 : }
420 0 : state->hostgroup_count = j;
421 : }
422 : }
423 :
424 : done:
425 0 : if (ret == EOK) {
426 0 : tevent_req_done(req);
427 : } else {
428 0 : DEBUG(SSSDBG_OP_FAILURE, "Error [%d][%s]\n", ret, strerror(ret));
429 0 : tevent_req_error(req, ret);
430 : }
431 : }
432 :
433 0 : errno_t ipa_host_info_recv(struct tevent_req *req,
434 : TALLOC_CTX *mem_ctx,
435 : size_t *host_count,
436 : struct sysdb_attrs ***hosts,
437 : size_t *hostgroup_count,
438 : struct sysdb_attrs ***hostgroups)
439 : {
440 : size_t c;
441 0 : struct ipa_host_state *state =
442 0 : tevent_req_data(req, struct ipa_host_state);
443 :
444 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
445 :
446 0 : *host_count = state->host_count;
447 0 : *hosts = talloc_steal(mem_ctx, state->hosts);
448 0 : for (c = 0; c < state->host_count; c++) {
449 : /* Guarantee the memory heirarchy of the list */
450 0 : talloc_steal(state->hosts, state->hosts[c]);
451 : }
452 :
453 0 : if (hostgroup_count) *hostgroup_count = state->hostgroup_count;
454 0 : if (hostgroups) *hostgroups = talloc_steal(mem_ctx, state->hostgroups);
455 :
456 0 : return EOK;
457 : }
|