Line data Source code
1 : /*
2 : SSSD
3 :
4 : Async IPA Helper routines for netgroups
5 :
6 : Authors:
7 : Jan Zeleny <jzeleny@redhat.com>
8 :
9 : Copyright (C) 2011 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 "util/util.h"
26 : #include "db/sysdb.h"
27 : #include "providers/ldap/sdap_async_private.h"
28 : #include "providers/ipa/ipa_id.h"
29 : #include "db/sysdb.h"
30 : #include <ctype.h>
31 :
32 : #define ENTITY_NG 1
33 : #define ENTITY_USER 2
34 : #define ENTITY_HOST 4
35 :
36 : struct ipa_get_netgroups_state {
37 : struct tevent_context *ev;
38 : struct sdap_options *opts;
39 : struct ipa_options *ipa_opts;
40 : struct sdap_handle *sh;
41 : struct sysdb_ctx *sysdb;
42 : struct sss_domain_info *dom;
43 : const char **attrs;
44 : int timeout;
45 :
46 : char *filter;
47 : const char *base_filter;
48 :
49 : size_t netgr_base_iter;
50 : size_t host_base_iter;
51 : size_t user_base_iter;
52 :
53 : /* Entities which have been already asked for
54 : * and are scheduled for inspection */
55 : hash_table_t *new_netgroups;
56 : hash_table_t *new_users;
57 : hash_table_t *new_hosts;
58 :
59 : int current_entity;
60 : int entities_found;
61 :
62 : struct sysdb_attrs **netgroups;
63 : int netgroups_count;
64 : };
65 :
66 0 : static errno_t ipa_save_netgroup(TALLOC_CTX *mem_ctx,
67 : struct sss_domain_info *dom,
68 : struct sdap_options *opts,
69 : struct sysdb_attrs *attrs)
70 : {
71 : struct ldb_message_element *el;
72 : struct sysdb_attrs *netgroup_attrs;
73 0 : const char *name = NULL;
74 : int ret;
75 : size_t c;
76 :
77 0 : ret = sysdb_attrs_get_el(attrs,
78 0 : opts->netgroup_map[IPA_AT_NETGROUP_NAME].sys_name,
79 : &el);
80 0 : if (ret) goto fail;
81 0 : if (el->num_values == 0) {
82 0 : ret = EINVAL;
83 0 : goto fail;
84 : }
85 0 : name = (const char *)el->values[0].data;
86 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Storing netgroup %s\n", name);
87 :
88 0 : netgroup_attrs = sysdb_new_attrs(mem_ctx);
89 0 : if (!netgroup_attrs) {
90 0 : ret = ENOMEM;
91 0 : goto fail;
92 : }
93 :
94 0 : ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
95 0 : if (ret) {
96 0 : goto fail;
97 : }
98 0 : if (el->num_values == 0) {
99 0 : DEBUG(SSSDBG_TRACE_LIBS,
100 : "Original DN is not available for [%s].\n", name);
101 : } else {
102 0 : DEBUG(SSSDBG_TRACE_LIBS,
103 : "Adding original DN [%s] to attributes of [%s].\n",
104 : el->values[0].data, name);
105 0 : ret = sysdb_attrs_add_string(netgroup_attrs, SYSDB_ORIG_DN,
106 0 : (const char *)el->values[0].data);
107 0 : if (ret) {
108 0 : goto fail;
109 : }
110 : }
111 :
112 0 : ret = sysdb_attrs_get_el(attrs, SYSDB_NETGROUP_TRIPLE, &el);
113 0 : if (ret) {
114 0 : goto fail;
115 : }
116 0 : if (el->num_values == 0) {
117 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "No netgroup triples for netgroup [%s].\n", name);
118 0 : ret = sysdb_attrs_get_el(netgroup_attrs, SYSDB_NETGROUP_TRIPLE, &el);
119 0 : if (ret != EOK) {
120 0 : goto fail;
121 : }
122 : } else {
123 0 : for(c = 0; c < el->num_values; c++) {
124 0 : ret = sysdb_attrs_add_string_safe(netgroup_attrs,
125 : SYSDB_NETGROUP_TRIPLE,
126 0 : (const char*)el->values[c].data);
127 0 : if (ret) {
128 0 : goto fail;
129 : }
130 : }
131 : }
132 :
133 0 : ret = sysdb_attrs_get_el(attrs,
134 0 : opts->netgroup_map[IPA_AT_NETGROUP_MEMBER].sys_name,
135 : &el);
136 0 : if (ret != EOK) {
137 0 : goto fail;
138 : }
139 0 : if (el->num_values == 0) {
140 0 : DEBUG(SSSDBG_TRACE_LIBS,
141 : "No original members for netgroup [%s]\n", name);
142 :
143 : } else {
144 0 : DEBUG(SSSDBG_TRACE_LIBS,
145 : "Adding original members to netgroup [%s]\n", name);
146 0 : for(c = 0; c < el->num_values; c++) {
147 0 : ret = sysdb_attrs_add_string(netgroup_attrs,
148 0 : opts->netgroup_map[IPA_AT_NETGROUP_MEMBER].sys_name,
149 0 : (const char*)el->values[c].data);
150 0 : if (ret) {
151 0 : goto fail;
152 : }
153 : }
154 : }
155 :
156 :
157 0 : ret = sysdb_attrs_get_el(attrs, SYSDB_NETGROUP_MEMBER, &el);
158 0 : if (ret != EOK) {
159 0 : goto fail;
160 : }
161 0 : if (el->num_values == 0) {
162 0 : DEBUG(SSSDBG_TRACE_LIBS, "No members for netgroup [%s]\n", name);
163 :
164 : } else {
165 0 : DEBUG(SSSDBG_TRACE_LIBS, "Adding members to netgroup [%s]\n", name);
166 0 : for(c = 0; c < el->num_values; c++) {
167 0 : ret = sysdb_attrs_add_string(netgroup_attrs, SYSDB_NETGROUP_MEMBER,
168 0 : (const char*)el->values[c].data);
169 0 : if (ret) {
170 0 : goto fail;
171 : }
172 : }
173 : }
174 :
175 0 : DEBUG(SSSDBG_TRACE_FUNC, "Storing info for netgroup %s\n", name);
176 :
177 0 : ret = sysdb_add_netgroup(dom, name, NULL, netgroup_attrs, NULL,
178 0 : dom->netgroup_timeout, 0);
179 0 : if (ret) goto fail;
180 :
181 0 : return EOK;
182 :
183 : fail:
184 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to save netgroup %s\n", name);
185 0 : return ret;
186 : }
187 :
188 : static errno_t ipa_netgr_next_base(struct tevent_req *req);
189 : static void ipa_get_netgroups_process(struct tevent_req *subreq);
190 : static int ipa_netgr_process_all(struct ipa_get_netgroups_state *state);
191 :
192 0 : struct tevent_req *ipa_get_netgroups_send(TALLOC_CTX *memctx,
193 : struct tevent_context *ev,
194 : struct sysdb_ctx *sysdb,
195 : struct sss_domain_info *dom,
196 : struct sdap_options *opts,
197 : struct ipa_options *ipa_options,
198 : struct sdap_handle *sh,
199 : const char **attrs,
200 : const char *filter,
201 : int timeout)
202 : {
203 : struct tevent_req *req;
204 : struct ipa_get_netgroups_state *state;
205 : int ret;
206 :
207 0 : req = tevent_req_create(memctx, &state, struct ipa_get_netgroups_state);
208 0 : if (!req) return NULL;
209 :
210 0 : state->ev = ev;
211 0 : state->opts = opts;
212 0 : state->ipa_opts = ipa_options;
213 0 : state->sh = sh;
214 0 : state->sysdb = sysdb;
215 0 : state->attrs = attrs;
216 0 : state->timeout = timeout;
217 0 : state->base_filter = filter;
218 0 : state->netgr_base_iter = 0;
219 0 : state->dom = dom;
220 :
221 0 : if (!ipa_options->id->sdom->netgroup_search_bases) {
222 0 : DEBUG(SSSDBG_CRIT_FAILURE,
223 : "Netgroup lookup request without a search base\n");
224 0 : ret = EINVAL;
225 0 : goto done;
226 : }
227 :
228 0 : ret = sss_hash_create(state, 32, &state->new_netgroups);
229 0 : if (ret != EOK) goto done;
230 0 : ret = sss_hash_create(state, 32, &state->new_users);
231 0 : if (ret != EOK) goto done;
232 0 : ret = sss_hash_create(state, 32, &state->new_hosts);
233 0 : if (ret != EOK) goto done;
234 :
235 :
236 0 : ret = ipa_netgr_next_base(req);
237 :
238 : done:
239 0 : if (ret != EOK) {
240 0 : tevent_req_error(req, ret);
241 0 : tevent_req_post(req, ev);
242 : }
243 :
244 0 : return req;
245 : }
246 :
247 0 : static errno_t ipa_netgr_next_base(struct tevent_req *req)
248 : {
249 : struct tevent_req *subreq;
250 : struct ipa_get_netgroups_state *state;
251 : struct sdap_search_base **netgr_bases;
252 :
253 0 : state = tevent_req_data(req, struct ipa_get_netgroups_state);
254 0 : netgr_bases = state->ipa_opts->id->sdom->netgroup_search_bases;
255 :
256 0 : talloc_zfree(state->filter);
257 0 : state->filter = sdap_combine_filters(
258 : state,
259 : state->base_filter,
260 0 : netgr_bases[state->netgr_base_iter]->filter);
261 0 : if (!state->filter) {
262 0 : return ENOMEM;
263 : }
264 :
265 0 : DEBUG(SSSDBG_TRACE_FUNC,
266 : "Searching for netgroups with base [%s]\n",
267 : netgr_bases[state->netgr_base_iter]->basedn);
268 :
269 0 : subreq = sdap_get_generic_send(
270 : state, state->ev, state->opts, state->sh,
271 0 : netgr_bases[state->netgr_base_iter]->basedn,
272 0 : netgr_bases[state->netgr_base_iter]->scope,
273 0 : state->filter, state->attrs,
274 0 : state->opts->netgroup_map, IPA_OPTS_NETGROUP,
275 : state->timeout,
276 : true);
277 0 : if (!subreq) {
278 0 : return ENOMEM;
279 : }
280 0 : tevent_req_set_callback(subreq, ipa_get_netgroups_process, req);
281 :
282 0 : return EOK;
283 : }
284 :
285 : static int ipa_netgr_fetch_netgroups(struct ipa_get_netgroups_state *state,
286 : struct tevent_req *req);
287 : static int ipa_netgr_fetch_users(struct ipa_get_netgroups_state *state,
288 : struct tevent_req *req);
289 : static int ipa_netgr_fetch_hosts(struct ipa_get_netgroups_state *state,
290 : struct tevent_req *req);
291 : static void ipa_netgr_members_process(struct tevent_req *subreq);
292 :
293 0 : static void ipa_get_netgroups_process(struct tevent_req *subreq)
294 : {
295 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
296 : struct tevent_req);
297 0 : struct ipa_get_netgroups_state *state = tevent_req_data(req,
298 : struct ipa_get_netgroups_state);
299 : int i, ret;
300 : struct ldb_message_element *el;
301 : struct sdap_search_base **netgr_bases;
302 : struct sysdb_attrs **netgroups;
303 : size_t netgroups_count;
304 : const char *orig_dn;
305 : char *dn;
306 : char *filter;
307 0 : bool fetch_members = false;
308 : hash_key_t key;
309 : hash_value_t value;
310 :
311 0 : netgr_bases = state->ipa_opts->id->sdom->netgroup_search_bases;
312 :
313 0 : ret = sdap_get_generic_recv(subreq, state, &netgroups_count, &netgroups);
314 0 : talloc_zfree(subreq);
315 0 : if (ret) {
316 0 : goto done;
317 : }
318 :
319 0 : DEBUG(SSSDBG_TRACE_FUNC, "Search for netgroups, returned %zu results.\n",
320 : netgroups_count);
321 :
322 0 : if (netgroups_count == 0) {
323 : /* No netgroups found in this search */
324 0 : state->netgr_base_iter++;
325 0 : if (netgr_bases[state->netgr_base_iter]) {
326 : /* There are more search bases to try */
327 0 : ret = ipa_netgr_next_base(req);
328 0 : if (ret != EOK) {
329 0 : tevent_req_error(req, ENOENT);
330 : }
331 0 : return;
332 : }
333 :
334 0 : ret = ENOENT;
335 0 : goto done;
336 : }
337 :
338 0 : filter = talloc_strdup(state, "(|");
339 0 : if (filter == NULL) {
340 0 : ret = ENOMEM;
341 0 : goto done;
342 : }
343 :
344 0 : for (i = 0; i < netgroups_count; i++) {
345 0 : ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_NETGROUP_MEMBER,
346 : &el);
347 0 : if (ret != EOK) goto done;
348 0 : if (el->num_values) state->entities_found |= ENTITY_NG;
349 :
350 0 : ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_MEMBER_USER,
351 : &el);
352 0 : if (ret != EOK) goto done;
353 0 : if (el->num_values) state->entities_found |= ENTITY_USER;
354 :
355 0 : ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_MEMBER_HOST,
356 : &el);
357 0 : if (ret != EOK) goto done;
358 0 : if (el->num_values) state->entities_found |= ENTITY_HOST;
359 :
360 0 : ret = sysdb_attrs_get_string(netgroups[i], SYSDB_ORIG_DN, &orig_dn);
361 0 : if (ret != EOK) {
362 0 : goto done;
363 : }
364 :
365 0 : key.type = HASH_KEY_STRING;
366 0 : value.type = HASH_VALUE_PTR;
367 0 : key.str = discard_const(orig_dn);
368 0 : value.ptr = netgroups[i];
369 0 : ret = hash_enter(state->new_netgroups, &key, &value);
370 0 : if (ret != HASH_SUCCESS) {
371 0 : ret = ENOMEM;
372 0 : goto done;
373 : }
374 :
375 0 : if (state->entities_found == 0) {
376 0 : continue;
377 : }
378 :
379 0 : ret = sss_filter_sanitize(state, orig_dn, &dn);
380 0 : if (ret != EOK) {
381 0 : goto done;
382 : }
383 : /* Add this to the filter */
384 0 : filter = talloc_asprintf_append(filter, "(%s=%s)",
385 0 : state->opts->netgroup_map[IPA_AT_NETGROUP_MEMBER_OF].name,
386 : dn);
387 0 : if (filter == NULL) {
388 0 : ret = ENOMEM;
389 0 : goto done;
390 : }
391 0 : fetch_members = true;
392 : }
393 :
394 0 : if (!fetch_members) {
395 0 : ret = ipa_netgr_process_all(state);
396 0 : if (ret != EOK) {
397 0 : tevent_req_error(req, ret);
398 : } else {
399 0 : tevent_req_done(req);
400 : }
401 0 : return;
402 : }
403 :
404 0 : state->filter = talloc_asprintf_append(filter, ")");
405 0 : if (state->filter == NULL) {
406 0 : ret = ENOMEM;
407 0 : goto done;
408 : }
409 :
410 0 : if (state->entities_found & ENTITY_NG) {
411 0 : state->netgr_base_iter = 0;
412 0 : ret = ipa_netgr_fetch_netgroups(state, req);
413 0 : if (ret != EOK) goto done;
414 0 : } else if (state->entities_found & ENTITY_USER) {
415 0 : ret = ipa_netgr_fetch_users(state, req);
416 0 : if (ret != EOK) goto done;
417 0 : } else if (state->entities_found & ENTITY_HOST) {
418 0 : ret = ipa_netgr_fetch_hosts(state, req);
419 0 : if (ret != EOK) goto done;
420 : }
421 :
422 0 : return;
423 : done:
424 0 : tevent_req_error(req, ret);
425 0 : return;
426 : }
427 :
428 0 : static int ipa_netgr_fetch_netgroups(struct ipa_get_netgroups_state *state,
429 : struct tevent_req *req)
430 : {
431 : char *filter;
432 : const char *base_filter;
433 : struct tevent_req *subreq;
434 : struct sdap_search_base **bases;
435 :
436 0 : bases = state->ipa_opts->id->sdom->netgroup_search_bases;
437 0 : if (bases[state->netgr_base_iter] == NULL) {
438 : /* No more bases to try */
439 0 : return ENOENT;
440 : }
441 0 : base_filter = bases[state->netgr_base_iter]->filter;
442 :
443 0 : filter = talloc_asprintf(state, "(&%s%s(objectclass=%s))",
444 : state->filter,
445 : base_filter?base_filter:"",
446 0 : state->opts->netgroup_map[SDAP_OC_NETGROUP].name);
447 0 : if (filter == NULL)
448 0 : return ENOMEM;
449 :
450 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
451 0 : bases[state->netgr_base_iter]->basedn,
452 0 : bases[state->netgr_base_iter]->scope,
453 0 : filter, state->attrs, state->opts->netgroup_map,
454 : IPA_OPTS_NETGROUP, state->timeout, true);
455 :
456 0 : state->current_entity = ENTITY_NG;
457 0 : if (subreq == NULL) {
458 0 : return ENOMEM;
459 : }
460 :
461 0 : tevent_req_set_callback(subreq, ipa_netgr_members_process, req);
462 :
463 0 : return EOK;
464 : }
465 :
466 0 : static int ipa_netgr_fetch_users(struct ipa_get_netgroups_state *state,
467 : struct tevent_req *req)
468 : {
469 0 : const char *attrs[] = { state->opts->user_map[SDAP_AT_USER_NAME].name,
470 0 : state->opts->user_map[SDAP_AT_USER_MEMBEROF].name,
471 : "objectclass", NULL };
472 : char *filter;
473 : const char *base_filter;
474 : struct tevent_req *subreq;
475 : struct sdap_search_base **bases;
476 :
477 0 : bases = state->ipa_opts->id->sdom->user_search_bases;
478 0 : if (bases[state->user_base_iter] == NULL) {
479 0 : return ENOENT;
480 : }
481 0 : base_filter = bases[state->user_base_iter]->filter;
482 :
483 0 : filter = talloc_asprintf(state, "(&%s%s(objectclass=%s))",
484 : state->filter,
485 : base_filter?base_filter:"",
486 0 : state->opts->user_map[SDAP_OC_USER].name);
487 0 : if (filter == NULL)
488 0 : return ENOMEM;
489 :
490 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
491 0 : dp_opt_get_string(state->opts->basic,
492 : SDAP_USER_SEARCH_BASE),
493 : LDAP_SCOPE_SUBTREE,
494 0 : filter, attrs, state->opts->user_map,
495 0 : state->opts->user_map_cnt,
496 : state->timeout, true);
497 :
498 0 : state->current_entity = ENTITY_USER;
499 0 : if (subreq == NULL) {
500 0 : talloc_free(attrs);
501 0 : return ENOMEM;
502 : }
503 :
504 0 : tevent_req_set_callback(subreq, ipa_netgr_members_process, req);
505 :
506 0 : return EOK;
507 : }
508 :
509 0 : static int ipa_netgr_fetch_hosts(struct ipa_get_netgroups_state *state,
510 : struct tevent_req *req)
511 : {
512 : const char **attrs;
513 : char *filter;
514 : const char *base_filter;
515 : struct tevent_req *subreq;
516 : int ret;
517 : struct sdap_search_base **bases;
518 :
519 0 : bases = state->ipa_opts->host_search_bases;
520 0 : if (bases[state->host_base_iter] == NULL) {
521 0 : return ENOENT;
522 : }
523 0 : base_filter = bases[state->host_base_iter]->filter;
524 :
525 0 : filter = talloc_asprintf(state, "(&%s%s(objectclass=%s))",
526 : state->filter,
527 : base_filter?base_filter:"",
528 0 : state->ipa_opts->host_map[IPA_OC_HOST].name);
529 0 : if (filter == NULL)
530 0 : return ENOMEM;
531 :
532 0 : ret = build_attrs_from_map(state, state->ipa_opts->host_map,
533 : IPA_OPTS_HOST, NULL, &attrs, NULL);
534 0 : if (ret != EOK) {
535 0 : talloc_free(filter);
536 0 : return ret;
537 : }
538 :
539 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
540 0 : bases[state->host_base_iter]->basedn,
541 0 : bases[state->host_base_iter]->scope,
542 0 : filter, attrs, state->ipa_opts->host_map,
543 : IPA_OPTS_HOST, state->timeout, true);
544 :
545 0 : state->current_entity = ENTITY_HOST;
546 0 : if (subreq == NULL) {
547 0 : talloc_free(filter);
548 0 : return ENOMEM;
549 : }
550 :
551 0 : tevent_req_set_callback(subreq, ipa_netgr_members_process, req);
552 :
553 0 : return EOK;
554 : }
555 :
556 0 : static void ipa_netgr_members_process(struct tevent_req *subreq)
557 : {
558 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
559 : struct tevent_req);
560 0 : struct ipa_get_netgroups_state *state = tevent_req_data(req,
561 : struct ipa_get_netgroups_state);
562 : struct sysdb_attrs **entities;
563 : size_t count;
564 : int ret, i;
565 : const char *orig_dn;
566 : char *orig_dn_lower;
567 : hash_table_t *table;
568 : hash_key_t key;
569 : hash_value_t value;
570 : int (* next_call)(struct ipa_get_netgroups_state *,
571 : struct tevent_req *);
572 0 : bool next_batch_scheduled = false;
573 :
574 0 : ret = sdap_get_generic_recv(subreq, state, &count, &entities);
575 0 : talloc_zfree(subreq);
576 0 : if (ret) {
577 0 : goto fail;
578 : }
579 :
580 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Found %zu members in current search base\n",
581 : count);
582 :
583 0 : next_call = NULL;
584 : /* While processing a batch of entities from one search base,
585 : * schedule query for another search base if there is one
586 : *
587 : * If there is no other search base, another class of entities
588 : * will be scheduled for lookup after processing of current
589 : * batch. The order of lookup is: netgroups -> users -> hosts
590 : */
591 0 : if (state->current_entity == ENTITY_NG) {
592 : /* We just received a batch of netgroups */
593 0 : state->netgr_base_iter++;
594 0 : ret = ipa_netgr_fetch_netgroups(state, req);
595 0 : table = state->new_netgroups;
596 : /* If there is a member netgroup, we always have to
597 : * ask for both member users and hosts
598 : * -> now schedule users
599 : */
600 0 : next_call = ipa_netgr_fetch_users;
601 0 : } else if (state->current_entity == ENTITY_USER) {
602 : /* We just received a batch of users */
603 0 : state->user_base_iter++;
604 0 : ret = ipa_netgr_fetch_users(state, req);
605 0 : table = state->new_users;
606 0 : if (state->entities_found & ENTITY_HOST ||
607 0 : state->entities_found & ENTITY_NG) {
608 0 : next_call = ipa_netgr_fetch_hosts;
609 : }
610 0 : } else if (state->current_entity == ENTITY_HOST) {
611 : /* We just received a batch of hosts */
612 0 : state->host_base_iter++;
613 0 : ret = ipa_netgr_fetch_hosts(state, req);
614 0 : table = state->new_hosts;
615 : } else {
616 0 : DEBUG(SSSDBG_CRIT_FAILURE,
617 : "Invalid entity type given for processing: %d\n",
618 : state->current_entity);
619 0 : ret = EINVAL;
620 0 : goto fail;
621 : }
622 :
623 0 : if (ret == EOK) {
624 : /* Next search base has been scheduled for inspection,
625 : * don't try to look for other type of entities
626 : */
627 0 : next_batch_scheduled = true;
628 0 : } else if (ret != ENOENT) {
629 0 : goto fail;
630 : }
631 :
632 : /* Process all member entites and store them in the designated hash table */
633 0 : key.type = HASH_KEY_STRING;
634 0 : value.type = HASH_VALUE_PTR;
635 0 : for (i = 0; i < count; i++) {
636 0 : ret = sysdb_attrs_get_string(entities[i], SYSDB_ORIG_DN, &orig_dn);
637 0 : if (ret != EOK) {
638 0 : goto fail;
639 : }
640 :
641 0 : orig_dn_lower = talloc_strdup(table, orig_dn);
642 0 : if (orig_dn_lower == NULL) {
643 0 : ret = ENOMEM;
644 0 : goto fail;
645 : }
646 : /* Transform the DN to lower case.
647 : * this is important, as the member/memberof attributes
648 : * have the value also in lower-case
649 : */
650 0 : key.str = orig_dn_lower;
651 0 : while (*orig_dn_lower != '\0') {
652 0 : *orig_dn_lower = tolower(*orig_dn_lower);
653 0 : orig_dn_lower++;
654 : }
655 0 : value.ptr = entities[i];
656 0 : ret = hash_enter(table, &key, &value);
657 0 : if (ret != HASH_SUCCESS) {
658 0 : goto fail;
659 : }
660 : }
661 :
662 0 : if (next_batch_scheduled) {
663 : /* The next search base is already scheduled to be searched */
664 0 : return;
665 : }
666 :
667 0 : if (next_call) {
668 : /* There is another class of members that has to be retrieved
669 : * - schedule the lookup
670 : */
671 0 : ret = next_call(state, req);
672 0 : if (ret != EOK) goto fail;
673 : } else {
674 : /* All members, that could have been fetched, were fetched */
675 0 : ret = ipa_netgr_process_all(state);
676 0 : if (ret != EOK) goto fail;
677 :
678 0 : tevent_req_done(req);
679 : }
680 :
681 0 : return;
682 :
683 : fail:
684 0 : tevent_req_error(req, ret);
685 0 : return;
686 : }
687 :
688 0 : static bool extract_netgroups(hash_entry_t *entry, void *pvt)
689 : {
690 : struct ipa_get_netgroups_state *state;
691 0 : state = talloc_get_type(pvt, struct ipa_get_netgroups_state);
692 :
693 0 : state->netgroups[state->netgroups_count] = talloc_get_type(entry->value.ptr,
694 : struct sysdb_attrs);
695 0 : state->netgroups_count++;
696 :
697 0 : return true;
698 : }
699 :
700 : struct extract_state {
701 : const char *group;
702 : const char *appropriateMemberOf;
703 :
704 : const char **entries;
705 : int entries_count;
706 : };
707 :
708 0 : static bool extract_entities(hash_entry_t *entry, void *pvt)
709 : {
710 : int ret;
711 : struct extract_state *state;
712 : struct sysdb_attrs *member;
713 : struct ldb_message_element *el;
714 : struct ldb_message_element *name_el;
715 :
716 0 : state = talloc_get_type(pvt, struct extract_state);
717 0 : member = talloc_get_type(entry->value.ptr, struct sysdb_attrs);
718 :
719 0 : ret = sysdb_attrs_get_el(member, state->appropriateMemberOf, &el);
720 0 : if (ret != EOK) {
721 0 : return false;
722 : }
723 :
724 0 : ret = sysdb_attrs_get_el(member, SYSDB_NAME, &name_el);
725 0 : if (ret != EOK || name_el == NULL || name_el->num_values == 0) {
726 0 : return false;
727 : }
728 :
729 0 : for (int j = 0; j < el->num_values; j++) {
730 0 : if (strcmp((char *)el->values[j].data, state->group) == 0) {
731 0 : state->entries = talloc_realloc(state, state->entries,
732 : const char *,
733 : state->entries_count + 1);
734 0 : if (state->entries == NULL) {
735 0 : return false;
736 : }
737 :
738 0 : state->entries[state->entries_count] = (char *)name_el->values[0].data;
739 0 : state->entries_count++;
740 0 : break;
741 : }
742 : }
743 :
744 0 : return true;
745 : }
746 :
747 0 : static int extract_members(TALLOC_CTX *mem_ctx,
748 : struct sysdb_attrs *netgroup,
749 : const char *member_type,
750 : const char *appropriateMemberOf,
751 : hash_table_t *lookup_table,
752 : const char ***_ret_array,
753 : int *_ret_count)
754 : {
755 : struct extract_state *state;
756 : struct ldb_message_element *el;
757 : struct sysdb_attrs *member;
758 : hash_key_t key;
759 : hash_value_t value;
760 0 : const char **process = NULL;
761 0 : const char **ret_array = NULL;
762 0 : int process_count = 0;
763 0 : int ret_count = 0;
764 : int ret, i, pi;
765 :
766 0 : key.type = HASH_KEY_STRING;
767 0 : value.type = HASH_VALUE_PTR;
768 :
769 0 : state = talloc_zero(mem_ctx, struct extract_state);
770 0 : if (state == NULL) {
771 0 : ret = ENOMEM;
772 0 : goto done;
773 : }
774 :
775 0 : state->appropriateMemberOf = appropriateMemberOf;
776 :
777 0 : ret = sysdb_attrs_get_el(netgroup, member_type, &el);
778 0 : if (ret != EOK && ret != ENOENT) {
779 0 : goto done;
780 : }
781 :
782 0 : if (ret == EOK) {
783 0 : for (i = 0; i < el->num_values; i++) {
784 0 : key.str = (char *)el->values[i].data;
785 0 : ret = hash_lookup(lookup_table, &key, &value);
786 0 : if (ret != HASH_SUCCESS && ret != HASH_ERROR_KEY_NOT_FOUND) {
787 0 : ret = ENOENT;
788 0 : goto done;
789 : }
790 :
791 0 : if (ret == HASH_ERROR_KEY_NOT_FOUND) {
792 0 : process = talloc_realloc(mem_ctx, process, const char *, process_count + 1);
793 0 : if (process == NULL) {
794 0 : ret = ENOMEM;
795 0 : goto done;
796 : }
797 :
798 0 : process[process_count] = (char *)el->values[i].data;
799 0 : process_count++;
800 : } else {
801 0 : ret_array = talloc_realloc(mem_ctx, ret_array, const char *, ret_count + 1);
802 0 : if (ret_array == NULL) {
803 0 : ret = ENOMEM;
804 0 : goto done;
805 : }
806 0 : member = talloc_get_type(value.ptr, struct sysdb_attrs);
807 0 : ret = sysdb_attrs_get_string(member, SYSDB_NAME, &ret_array[ret_count]);
808 0 : if (ret != EOK) {
809 0 : goto done;
810 : }
811 0 : ret_count++;
812 : }
813 :
814 0 : for (pi = 0; pi < process_count; pi++) {
815 0 : state->group = process[pi];
816 0 : hash_iterate(lookup_table, extract_entities, state);
817 0 : if (state->entries_count > 0) {
818 0 : ret_array = talloc_realloc(mem_ctx, ret_array, const char *,
819 : ret_count + state->entries_count);
820 0 : if (ret_array == NULL) {
821 0 : ret = ENOMEM;
822 0 : goto done;
823 : }
824 0 : memcpy(&ret_array[ret_count], state->entries,
825 0 : state->entries_count*sizeof(const char *));
826 0 : ret_count += state->entries_count;
827 : }
828 0 : state->entries_count = 0;
829 0 : talloc_zfree(state->entries);
830 : }
831 : }
832 : } else {
833 0 : ret_array = NULL;
834 : }
835 :
836 0 : *_ret_array = ret_array;
837 0 : *_ret_count = ret_count;
838 0 : ret = EOK;
839 :
840 : done:
841 0 : return ret;
842 : }
843 :
844 0 : static int ipa_netgr_process_all(struct ipa_get_netgroups_state *state)
845 : {
846 : int i, j, k, ret;
847 : const char **members;
848 : struct sysdb_attrs *member;
849 : const char *member_name;
850 : struct extract_state *extract_state;
851 : struct ldb_message_element *external_hosts;
852 0 : const char *dash[] = {"-"};
853 0 : const char **uids = NULL;
854 0 : const char **hosts = NULL;
855 0 : int uids_count = 0;
856 0 : int hosts_count = 0;
857 : hash_key_t key;
858 : hash_value_t value;
859 : const char *domain;
860 : char *triple;
861 :
862 0 : state->netgroups = talloc_zero_array(state, struct sysdb_attrs *,
863 : hash_count(state->new_netgroups));
864 0 : if (state->netgroups == NULL) {
865 0 : return ENOMEM;
866 : }
867 :
868 0 : extract_state = talloc_zero(state, struct extract_state);
869 0 : if (extract_state == NULL) {
870 0 : ret = ENOMEM;
871 0 : goto done;
872 : }
873 :
874 0 : key.type = HASH_KEY_STRING;
875 0 : value.type = HASH_VALUE_PTR;
876 :
877 0 : hash_iterate(state->new_netgroups, extract_netgroups, state);
878 0 : for (i = 0; i < state->netgroups_count; i++) {
879 : /* load all its member netgroups, translate */
880 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Extracting netgroup members of netgroup %d\n", i);
881 0 : ret = sysdb_attrs_get_string_array(state->netgroups[i],
882 : SYSDB_ORIG_NETGROUP_MEMBER,
883 : state, &members);
884 0 : if (ret != EOK && ret != ENOENT) {
885 0 : goto done;
886 : }
887 :
888 0 : j = 0;
889 0 : if (ret == EOK) {
890 0 : for (j = 0; members[j]; j++) {
891 0 : key.str = discard_const(members[j]);
892 0 : ret = hash_lookup(state->new_netgroups, &key, &value);
893 0 : if (ret != HASH_SUCCESS) {
894 0 : ret = ENOENT;
895 0 : goto done;
896 : }
897 :
898 0 : member = talloc_get_type(value.ptr, struct sysdb_attrs);
899 0 : ret = sysdb_attrs_get_string(member, SYSDB_NAME, &member_name);
900 0 : if (ret != EOK) {
901 0 : goto done;
902 : }
903 :
904 0 : ret = sysdb_attrs_add_string(state->netgroups[i],
905 : SYSDB_NETGROUP_MEMBER,
906 : member_name);
907 0 : if (ret != EOK) {
908 0 : goto done;
909 : }
910 : }
911 0 : talloc_zfree(members);
912 : }
913 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Extracted %d netgroup members\n", j);
914 :
915 : /* Load all UIDs */
916 0 : DEBUG(SSSDBG_TRACE_ALL, "Extracting user members of netgroup %d\n", i);
917 0 : ret = extract_members(state, state->netgroups[i],
918 : SYSDB_ORIG_MEMBER_USER,
919 0 : state->ipa_opts->id->user_map[SDAP_AT_USER_MEMBEROF].sys_name,
920 : state->new_users,
921 : &uids, &uids_count);
922 0 : if (ret != EOK) {
923 0 : goto done;
924 : }
925 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Extracted %d user members\n", uids_count);
926 :
927 0 : DEBUG(SSSDBG_TRACE_ALL, "Extracting host members of netgroup %d\n", i);
928 0 : ret = extract_members(state, state->netgroups[i],
929 : SYSDB_ORIG_MEMBER_HOST,
930 0 : state->ipa_opts->host_map[IPA_AT_HOST_MEMBER_OF].sys_name,
931 : state->new_hosts,
932 : &hosts, &hosts_count);
933 0 : if (ret != EOK) {
934 0 : goto done;
935 : }
936 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Extracted %d host members\n", hosts_count);
937 :
938 0 : ret = sysdb_attrs_get_el(state->netgroups[i],
939 : SYSDB_ORIG_NETGROUP_EXTERNAL_HOST,
940 : &external_hosts);
941 0 : if (ret != EOK) {
942 0 : goto done;
943 : }
944 :
945 0 : if (external_hosts->num_values > 0) {
946 0 : hosts = talloc_realloc(state, hosts, const char *,
947 : hosts_count + external_hosts->num_values);
948 0 : if (hosts == NULL) {
949 0 : ret = ENOMEM;
950 0 : goto done;
951 : }
952 :
953 0 : for (j = 0; j < external_hosts->num_values; j++) {
954 0 : hosts[hosts_count] = talloc_strdup(hosts, (char *)external_hosts->values[j].data);
955 0 : if (hosts[hosts_count] == NULL) {
956 0 : ret = ENOMEM;
957 0 : goto done;
958 : }
959 0 : hosts_count++;
960 : }
961 : }
962 :
963 0 : ret = sysdb_attrs_get_string(state->netgroups[i], SYSDB_NETGROUP_DOMAIN,
964 : &domain);
965 0 : if (ret != EOK) {
966 0 : goto done;
967 : }
968 :
969 0 : if (uids_count > 0 || hosts_count > 0) {
970 0 : if (uids_count == 0) {
971 0 : uids_count = 1;
972 0 : uids = dash;
973 : }
974 :
975 0 : if (hosts_count == 0) {
976 0 : hosts_count = 1;
977 0 : hosts = dash;
978 : }
979 :
980 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Putting together triples of "
981 : "netgroup %d\n", i);
982 0 : for (j = 0; j < uids_count; j++) {
983 0 : for (k = 0; k < hosts_count; k++) {
984 0 : triple = talloc_asprintf(state, "(%s,%s,%s)",
985 0 : hosts[k], uids[j],
986 : domain);
987 0 : if (triple == NULL) {
988 0 : ret = ENOMEM;
989 0 : goto done;
990 : }
991 :
992 0 : ret = sysdb_attrs_add_string(state->netgroups[i],
993 : SYSDB_NETGROUP_TRIPLE,
994 : triple);
995 0 : if (ret != EOK) {
996 0 : goto done;
997 : }
998 : }
999 : }
1000 : }
1001 :
1002 0 : ret = ipa_save_netgroup(state, state->dom,
1003 0 : state->opts, state->netgroups[i]);
1004 0 : if (ret != EOK) {
1005 0 : goto done;
1006 : }
1007 : }
1008 :
1009 0 : ret = EOK;
1010 : done:
1011 0 : return ret;
1012 : }
1013 :
1014 0 : int ipa_get_netgroups_recv(struct tevent_req *req,
1015 : TALLOC_CTX *mem_ctx,
1016 : size_t *reply_count,
1017 : struct sysdb_attrs ***reply)
1018 : {
1019 0 : struct ipa_get_netgroups_state *state = tevent_req_data(req,
1020 : struct ipa_get_netgroups_state);
1021 :
1022 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1023 :
1024 0 : if (reply_count) {
1025 0 : *reply_count = state->netgroups_count;
1026 : }
1027 :
1028 0 : if (reply) {
1029 0 : *reply = talloc_steal(mem_ctx, state->netgroups);
1030 : }
1031 :
1032 0 : return EOK;
1033 : }
|