Line data Source code
1 : /*
2 : SSSD
3 :
4 : Authors:
5 : Pavel Březina <pbrezina@redhat.com>
6 :
7 : Copyright (C) 2013 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 <errno.h>
24 : #include <string.h>
25 : #include <tevent.h>
26 : #include <talloc.h>
27 : #include <ldb.h>
28 : #include <dhash.h>
29 : #include <stdint.h>
30 : #include <time.h>
31 :
32 : #include "util/util.h"
33 : #include "db/sysdb.h"
34 : #include "providers/ldap/ldap_common.h"
35 : #include "providers/ldap/sdap_async.h"
36 : #include "providers/ldap/sdap_async_private.h"
37 : #include "providers/ldap/sdap_idmap.h"
38 :
39 : #define sdap_nested_group_sysdb_search_users(domain, filter) \
40 : sdap_nested_group_sysdb_search((domain), (filter), true)
41 :
42 : #define sdap_nested_group_sysdb_search_groups(domain, filter) \
43 : sdap_nested_group_sysdb_search((domain), (filter), false)
44 :
45 : enum sdap_nested_group_dn_type {
46 : SDAP_NESTED_GROUP_DN_USER,
47 : SDAP_NESTED_GROUP_DN_GROUP,
48 : SDAP_NESTED_GROUP_DN_UNKNOWN
49 : };
50 :
51 : struct sdap_nested_group_member {
52 : enum sdap_nested_group_dn_type type;
53 : const char *dn;
54 : const char *user_filter;
55 : const char *group_filter;
56 : };
57 :
58 : struct sdap_nested_group_ctx {
59 : struct sss_domain_info *domain;
60 : struct sdap_options *opts;
61 : struct sdap_search_base **user_search_bases;
62 : struct sdap_search_base **group_search_bases;
63 : struct sdap_handle *sh;
64 : hash_table_t *users;
65 : hash_table_t *groups;
66 : bool try_deref;
67 : int deref_treshold;
68 : int max_nesting_level;
69 : };
70 :
71 : static struct tevent_req *
72 : sdap_nested_group_process_send(TALLOC_CTX *mem_ctx,
73 : struct tevent_context *ev,
74 : struct sdap_nested_group_ctx *group_ctx,
75 : int nesting_level,
76 : struct sysdb_attrs *group);
77 :
78 : static errno_t sdap_nested_group_process_recv(struct tevent_req *req);
79 :
80 : static struct tevent_req *
81 : sdap_nested_group_single_send(TALLOC_CTX *mem_ctx,
82 : struct tevent_context *ev,
83 : struct sdap_nested_group_ctx *group_ctx,
84 : struct sdap_nested_group_member *members,
85 : int num_members,
86 : int num_groups_max,
87 : int nesting_level);
88 :
89 : static errno_t sdap_nested_group_single_recv(struct tevent_req *req);
90 :
91 : static struct tevent_req *
92 : sdap_nested_group_lookup_user_send(TALLOC_CTX *mem_ctx,
93 : struct tevent_context *ev,
94 : struct sdap_nested_group_ctx *group_ctx,
95 : struct sdap_nested_group_member *member);
96 :
97 : static errno_t sdap_nested_group_lookup_user_recv(TALLOC_CTX *mem_ctx,
98 : struct tevent_req *req,
99 : struct sysdb_attrs **_user);
100 :
101 : static struct tevent_req *
102 : sdap_nested_group_lookup_group_send(TALLOC_CTX *mem_ctx,
103 : struct tevent_context *ev,
104 : struct sdap_nested_group_ctx *group_ctx,
105 : struct sdap_nested_group_member *member);
106 :
107 : static errno_t sdap_nested_group_lookup_group_recv(TALLOC_CTX *mem_ctx,
108 : struct tevent_req *req,
109 : struct sysdb_attrs **_group);
110 :
111 : static struct tevent_req *
112 : sdap_nested_group_lookup_unknown_send(TALLOC_CTX *mem_ctx,
113 : struct tevent_context *ev,
114 : struct sdap_nested_group_ctx *group_ctx,
115 : struct sdap_nested_group_member *member);
116 :
117 : static errno_t
118 : sdap_nested_group_lookup_unknown_recv(TALLOC_CTX *mem_ctx,
119 : struct tevent_req *req,
120 : struct sysdb_attrs **_entry,
121 : enum sdap_nested_group_dn_type *_type);
122 :
123 : static struct tevent_req *
124 : sdap_nested_group_deref_send(TALLOC_CTX *mem_ctx,
125 : struct tevent_context *ev,
126 : struct sdap_nested_group_ctx *group_ctx,
127 : struct ldb_message_element *members,
128 : const char *group_dn,
129 : int nesting_level);
130 :
131 : static errno_t sdap_nested_group_deref_recv(struct tevent_req *req);
132 :
133 : static errno_t
134 12 : sdap_nested_group_extract_hash_table(TALLOC_CTX *mem_ctx,
135 : hash_table_t *table,
136 : unsigned long *_num_entries,
137 : struct sysdb_attrs ***_entries)
138 : {
139 12 : struct sysdb_attrs **entries = NULL;
140 12 : struct sysdb_attrs *entry = NULL;
141 : hash_value_t *values;
142 : unsigned long num_entries;
143 : unsigned int i;
144 : bool hret;
145 : errno_t ret;
146 :
147 12 : hret = hash_values(table, &num_entries, &values);
148 12 : if (hret != HASH_SUCCESS) {
149 0 : ret = EIO;
150 0 : goto done;
151 : }
152 :
153 12 : if (num_entries > 0) {
154 9 : entries = talloc_array(mem_ctx, struct sysdb_attrs *, num_entries);
155 9 : if (entries == NULL) {
156 0 : ret = ENOMEM;
157 0 : goto done;
158 : }
159 :
160 26 : for (i = 0; i < num_entries; i++) {
161 17 : entry = talloc_get_type(values[i].ptr, struct sysdb_attrs);
162 17 : entries[i] = talloc_steal(entries, entry);
163 : }
164 : }
165 :
166 12 : if (_num_entries != NULL) {
167 12 : *_num_entries = num_entries;
168 : }
169 :
170 12 : if (_entries != NULL) {
171 12 : *_entries = entries;
172 : }
173 :
174 12 : ret = EOK;
175 :
176 : done:
177 12 : talloc_free(values);
178 :
179 12 : if (ret != EOK) {
180 0 : talloc_free(entries);
181 : }
182 :
183 12 : return ret;
184 : }
185 :
186 22 : static errno_t sdap_nested_group_hash_entry(hash_table_t *table,
187 : struct sysdb_attrs *entry,
188 : const char *table_name)
189 : {
190 : hash_key_t key;
191 : hash_value_t value;
192 22 : const char *name = NULL;
193 : errno_t ret;
194 : int hret;
195 :
196 22 : ret = sysdb_attrs_get_string(entry, SYSDB_ORIG_DN, &name);
197 22 : if (ret != EOK) {
198 0 : return ret;
199 : }
200 :
201 22 : DEBUG(SSSDBG_TRACE_ALL, "Inserting [%s] into hash table [%s]\n",
202 : name, table_name);
203 :
204 22 : key.type = HASH_KEY_STRING;
205 22 : key.str = talloc_strdup(NULL, name);
206 22 : if (key.str == NULL) {
207 0 : return ENOMEM;
208 : }
209 :
210 22 : if (hash_has_key(table, &key)) {
211 2 : talloc_free(key.str);
212 2 : return EEXIST;
213 : }
214 :
215 20 : value.type = HASH_VALUE_PTR;
216 20 : value.ptr = entry;
217 :
218 20 : hret = hash_enter(table, &key, &value);
219 20 : if (hret != HASH_SUCCESS) {
220 0 : talloc_free(key.str);
221 0 : return EIO;
222 : }
223 :
224 20 : talloc_steal(table, key.str);
225 20 : talloc_steal(table, value.ptr);
226 :
227 20 : return EOK;
228 : }
229 :
230 : static errno_t
231 7 : sdap_nested_group_hash_user(struct sdap_nested_group_ctx *group_ctx,
232 : struct sysdb_attrs *user)
233 : {
234 7 : return sdap_nested_group_hash_entry(group_ctx->users, user, "users");
235 : }
236 :
237 : static errno_t
238 15 : sdap_nested_group_hash_group(struct sdap_nested_group_ctx *group_ctx,
239 : struct sysdb_attrs *group)
240 : {
241 15 : struct sdap_attr_map *map = group_ctx->opts->group_map;
242 : gid_t gid;
243 : errno_t ret;
244 15 : bool posix_group = true;
245 : bool use_id_mapping;
246 : bool can_find_gid;
247 : bool need_filter;
248 :
249 15 : ret = sdap_check_ad_group_type(group_ctx->domain, group_ctx->opts,
250 : group, "", &need_filter);
251 15 : if (ret != EOK) {
252 0 : return ret;
253 : }
254 :
255 15 : if (need_filter) {
256 0 : posix_group = false;
257 0 : gid = 0;
258 : }
259 :
260 15 : use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
261 15 : group_ctx->opts->idmap_ctx,
262 15 : group_ctx->domain->name,
263 15 : group_ctx->domain->domain_id);
264 :
265 15 : can_find_gid = posix_group && !use_id_mapping;
266 15 : if (can_find_gid) {
267 15 : ret = sysdb_attrs_get_uint32_t(group, map[SDAP_AT_GROUP_GID].sys_name,
268 : &gid);
269 : }
270 15 : if (!can_find_gid || ret == ENOENT || (ret == EOK && gid == 0)) {
271 0 : DEBUG(SSSDBG_TRACE_ALL,
272 : "The group's gid was %s\n", ret == ENOENT ? "missing" : "zero");
273 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
274 : "Marking group as non-posix and setting GID=0!\n");
275 :
276 0 : if (ret == ENOENT || !posix_group) {
277 0 : ret = sysdb_attrs_add_uint32(group,
278 0 : map[SDAP_AT_GROUP_GID].sys_name, 0);
279 0 : if (ret != EOK) {
280 0 : DEBUG(SSSDBG_CRIT_FAILURE,
281 : "Failed to add a GID to non-posix group!\n");
282 0 : return ret;
283 : }
284 : }
285 :
286 0 : ret = sysdb_attrs_add_bool(group, SYSDB_POSIX, false);
287 0 : if (ret != EOK) {
288 0 : DEBUG(SSSDBG_OP_FAILURE,
289 : "Error: Failed to mark group as non-posix!\n");
290 0 : return ret;
291 : }
292 15 : } else if (ret != EOK) {
293 0 : return ret;
294 : }
295 :
296 15 : return sdap_nested_group_hash_entry(group_ctx->groups, group, "groups");
297 : }
298 :
299 32 : static errno_t sdap_nested_group_sysdb_search(struct sss_domain_info *domain,
300 : const char *filter,
301 : bool user)
302 : {
303 : static const char *attrs[] = {SYSDB_CACHE_EXPIRE,
304 : SYSDB_UIDNUM,
305 : NULL};
306 32 : struct ldb_message **msgs = NULL;
307 : size_t count;
308 32 : time_t now = time(NULL);
309 : uint64_t expire;
310 : uid_t uid;
311 : errno_t ret;
312 :
313 32 : if (user) {
314 16 : ret = sysdb_search_users(NULL, domain, filter, attrs,
315 : &count, &msgs);
316 : } else {
317 16 : ret = sysdb_search_groups(NULL, domain, filter, attrs,
318 : &count, &msgs);
319 : }
320 32 : if (ret != EOK) {
321 32 : goto done;
322 : }
323 :
324 0 : if (count != 1) {
325 0 : DEBUG(SSSDBG_OP_FAILURE, "More than one entry found?\n");
326 0 : ret = EFAULT;
327 0 : goto done;
328 : }
329 :
330 : /* we found an object with this origDN in the sysdb,
331 : * check if it is valid */
332 0 : if (user) {
333 0 : uid = ldb_msg_find_attr_as_uint64(msgs[0], SYSDB_UIDNUM, 0);
334 0 : if (uid == 0) {
335 0 : DEBUG(SSSDBG_OP_FAILURE, "User with no UID?\n");
336 0 : ret = EINVAL;
337 0 : goto done;
338 : }
339 : }
340 :
341 0 : expire = ldb_msg_find_attr_as_uint64(msgs[0], SYSDB_CACHE_EXPIRE, 0);
342 0 : if (expire != 0 && expire <= now) {
343 : /* needs refresh */
344 0 : ret = EAGAIN;
345 0 : goto done;
346 : }
347 :
348 : /* valid object */
349 0 : ret = EOK;
350 :
351 : done:
352 32 : talloc_zfree(msgs);
353 32 : return ret;
354 : }
355 :
356 : static errno_t
357 16 : sdap_nested_group_check_cache(struct sdap_options *opts,
358 : struct sss_domain_info *domain,
359 : const char *member_dn,
360 : enum sdap_nested_group_dn_type *_type)
361 : {
362 16 : TALLOC_CTX *tmp_ctx = NULL;
363 16 : struct sdap_domain *sdap_domain = NULL;
364 16 : struct sss_domain_info *member_domain = NULL;
365 16 : char *sanitized_dn = NULL;
366 16 : char *filter = NULL;
367 : errno_t ret;
368 :
369 16 : tmp_ctx = talloc_new(NULL);
370 16 : if (tmp_ctx == NULL) {
371 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
372 0 : return ENOMEM;
373 : }
374 :
375 16 : ret = sss_filter_sanitize(tmp_ctx, member_dn, &sanitized_dn);
376 16 : if (ret != EOK) {
377 0 : goto done;
378 : }
379 :
380 16 : filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_ORIG_DN, sanitized_dn);
381 16 : if (filter == NULL) {
382 0 : ret = ENOMEM;
383 0 : goto done;
384 : }
385 :
386 : /* determine correct domain of this member */
387 16 : sdap_domain = sdap_domain_get_by_dn(opts, member_dn);
388 16 : member_domain = sdap_domain == NULL ? domain : sdap_domain->dom;
389 :
390 : /* search in users */
391 16 : ret = sdap_nested_group_sysdb_search_users(member_domain, filter);
392 16 : if (ret == EOK || ret == EAGAIN) {
393 : /* user found */
394 0 : *_type = SDAP_NESTED_GROUP_DN_USER;
395 0 : goto done;
396 16 : } else if (ret != ENOENT) {
397 : /* error */
398 0 : goto done;
399 : }
400 :
401 : /* search in groups */
402 16 : ret = sdap_nested_group_sysdb_search_groups(member_domain, filter);
403 16 : if (ret == EOK || ret == EAGAIN) {
404 : /* group found */
405 0 : *_type = SDAP_NESTED_GROUP_DN_GROUP;
406 0 : goto done;
407 16 : } else if (ret != ENOENT) {
408 : /* error */
409 0 : goto done;
410 : }
411 :
412 : /* not found in the sysdb */
413 16 : ret = ENOENT;
414 :
415 : done:
416 16 : talloc_free(tmp_ctx);
417 16 : return ret;
418 : }
419 :
420 : static bool
421 32 : sdap_nested_member_is_ent(struct sdap_nested_group_ctx *group_ctx,
422 : const char *dn, char **filter, bool is_user)
423 : {
424 32 : struct sdap_domain *sditer = NULL;
425 32 : bool ret = false;
426 : struct sdap_search_base **search_bases;
427 :
428 48 : DLIST_FOR_EACH(sditer, group_ctx->opts->sdom) {
429 32 : search_bases = is_user ? sditer->user_search_bases : \
430 : sditer->group_search_bases;
431 :
432 32 : ret = sss_ldap_dn_in_search_bases(group_ctx, dn, search_bases,
433 : filter);
434 32 : if (ret == true) {
435 16 : break;
436 : }
437 : }
438 :
439 32 : return ret;
440 : }
441 :
442 : static inline bool
443 16 : sdap_nested_member_is_user(struct sdap_nested_group_ctx *group_ctx,
444 : const char *dn, char **filter)
445 : {
446 16 : return sdap_nested_member_is_ent(group_ctx, dn, filter, true);
447 : }
448 :
449 : static inline bool
450 16 : sdap_nested_member_is_group(struct sdap_nested_group_ctx *group_ctx,
451 : const char *dn, char **filter)
452 : {
453 16 : return sdap_nested_member_is_ent(group_ctx, dn, filter, false);
454 : }
455 :
456 : static errno_t
457 10 : sdap_nested_group_split_members(TALLOC_CTX *mem_ctx,
458 : struct sdap_nested_group_ctx *group_ctx,
459 : int nesting_level,
460 : struct ldb_message_element *members,
461 : struct sdap_nested_group_member **_missing,
462 : int *_num_missing,
463 : int *_num_groups)
464 : {
465 10 : TALLOC_CTX *tmp_ctx = NULL;
466 10 : struct sdap_nested_group_member *missing = NULL;
467 : enum sdap_nested_group_dn_type type;
468 10 : char *dn = NULL;
469 10 : char *user_filter = NULL;
470 10 : char *group_filter = NULL;
471 10 : int num_missing = 0;
472 10 : int num_groups = 0;
473 : hash_key_t key;
474 : bool bret;
475 : bool is_user;
476 : bool is_group;
477 : errno_t ret;
478 : int i;
479 :
480 10 : tmp_ctx = talloc_new(NULL);
481 10 : if (tmp_ctx == NULL) {
482 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
483 0 : return ENOMEM;
484 : }
485 :
486 10 : missing = talloc_zero_array(tmp_ctx, struct sdap_nested_group_member,
487 : members->num_values);
488 10 : if (missing == NULL) {
489 0 : ret = ENOMEM;
490 0 : goto done;
491 : }
492 :
493 : /* create list of missing members
494 : * skip dn if:
495 : * - is present in user or group hash table
496 : * - is present in sysdb and not expired
497 : * - it is a group and we have reached the maximal nesting level
498 : * - it is not under user nor group search bases
499 : *
500 : * if dn is in sysdb but expired
501 : * - we know what object type it is
502 : *
503 : * if dn is not in hash table or sysdb
504 : * - try to determine type of object by search base that match dn
505 : */
506 26 : for (i = 0; i < members->num_values; i++) {
507 16 : dn = (char*)members->values[i].data;
508 16 : type = SDAP_NESTED_GROUP_DN_UNKNOWN;
509 :
510 : /* check hash tables */
511 16 : key.type = HASH_KEY_STRING;
512 16 : key.str = dn;
513 :
514 16 : bret = hash_has_key(group_ctx->users, &key);
515 16 : if (bret) {
516 0 : continue;
517 : }
518 :
519 16 : bret = hash_has_key(group_ctx->groups, &key);
520 16 : if (bret) {
521 0 : continue;
522 : }
523 :
524 : /* check sysdb */
525 16 : ret = sdap_nested_group_check_cache(group_ctx->opts, group_ctx->domain,
526 : dn, &type);
527 16 : if (ret == EOK) {
528 : /* found and valid */
529 0 : DEBUG(SSSDBG_TRACE_ALL, "[%s] found in cache, skipping\n", dn);
530 0 : continue;
531 16 : } else if (ret != EAGAIN && ret != ENOENT) {
532 : /* error */
533 0 : goto done;
534 : }
535 :
536 : /* try to determine type by dn */
537 16 : if (type == SDAP_NESTED_GROUP_DN_UNKNOWN) {
538 : /* user */
539 16 : is_user = sdap_nested_member_is_user(group_ctx, dn,
540 : &user_filter);
541 :
542 16 : is_group = sdap_nested_member_is_group(group_ctx, dn,
543 : &group_filter);
544 :
545 16 : if (is_user && is_group) {
546 : /* search bases overlap */
547 0 : DEBUG(SSSDBG_TRACE_ALL, "[%s] is unknown object\n", dn);
548 0 : type = SDAP_NESTED_GROUP_DN_UNKNOWN;
549 16 : } else if (is_user) {
550 8 : DEBUG(SSSDBG_TRACE_ALL, "[%s] is a user\n", dn);
551 8 : type = SDAP_NESTED_GROUP_DN_USER;
552 8 : } else if (is_group) {
553 8 : DEBUG(SSSDBG_TRACE_ALL, "[%s] is a group\n", dn);
554 8 : type = SDAP_NESTED_GROUP_DN_GROUP;
555 : } else {
556 : /* dn is outside search bases */
557 0 : DEBUG(SSSDBG_TRACE_ALL, "[%s] is out of scope of configured "
558 : "search bases, skipping\n", dn);
559 0 : continue;
560 : }
561 : }
562 :
563 : /* check nesting level */
564 16 : if (type == SDAP_NESTED_GROUP_DN_GROUP) {
565 8 : if (nesting_level >= group_ctx->max_nesting_level) {
566 0 : DEBUG(SSSDBG_TRACE_ALL, "[%s] is outside nesting limit "
567 : "(level %d), skipping\n", dn, nesting_level);
568 0 : talloc_zfree(user_filter);
569 0 : talloc_zfree(group_filter);
570 0 : continue;
571 : }
572 : }
573 :
574 16 : missing[num_missing].dn = talloc_strdup(missing, dn);
575 16 : if (missing[num_missing].dn == NULL) {
576 0 : ret = ENOMEM;
577 0 : goto done;
578 : }
579 :
580 16 : missing[num_missing].type = type;
581 16 : missing[num_missing].user_filter = talloc_steal(missing, user_filter);
582 16 : missing[num_missing].group_filter = talloc_steal(missing, group_filter);
583 :
584 16 : num_missing++;
585 :
586 16 : if (type != SDAP_NESTED_GROUP_DN_USER) {
587 8 : num_groups++;
588 : }
589 : }
590 :
591 10 : missing = talloc_realloc(mem_ctx, missing,
592 : struct sdap_nested_group_member, num_missing);
593 : /* talloc_realloc behaves as talloc_free if 3rd parameter (count) is 0,
594 : * so it's OK to return NULL then
595 : */
596 10 : if (missing == NULL && num_missing > 0) {
597 0 : ret = ENOMEM;
598 0 : goto done;
599 : }
600 :
601 10 : if (_missing) {
602 10 : *_missing = talloc_steal(mem_ctx, missing);
603 : }
604 :
605 10 : if (_num_missing) {
606 10 : *_num_missing = num_missing;
607 : }
608 :
609 10 : if (_num_groups) {
610 10 : *_num_groups = num_groups;
611 : }
612 :
613 10 : ret = EOK;
614 :
615 : done:
616 10 : talloc_free(tmp_ctx);
617 :
618 10 : return ret;
619 : }
620 :
621 :
622 : struct sdap_nested_group_state {
623 : struct sdap_nested_group_ctx *group_ctx;
624 : };
625 :
626 : static void sdap_nested_group_done(struct tevent_req *subreq);
627 :
628 : struct tevent_req *
629 7 : sdap_nested_group_send(TALLOC_CTX *mem_ctx,
630 : struct tevent_context *ev,
631 : struct sdap_domain *sdom,
632 : struct sdap_options *opts,
633 : struct sdap_handle *sh,
634 : struct sysdb_attrs *group)
635 : {
636 7 : struct sdap_nested_group_state *state = NULL;
637 7 : struct tevent_req *req = NULL;
638 7 : struct tevent_req *subreq = NULL;
639 : errno_t ret;
640 : int i;
641 :
642 7 : req = tevent_req_create(mem_ctx, &state, struct sdap_nested_group_state);
643 7 : if (req == NULL) {
644 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
645 0 : return NULL;
646 : }
647 :
648 : /* create main nested group context */
649 7 : state->group_ctx = talloc_zero(state, struct sdap_nested_group_ctx);
650 7 : if (state->group_ctx == NULL) {
651 0 : ret = ENOMEM;
652 0 : goto immediately;
653 : }
654 :
655 7 : ret = sss_hash_create(state->group_ctx, 32, &state->group_ctx->users);
656 7 : if (ret != EOK) {
657 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n",
658 : ret, strerror(ret));
659 0 : goto immediately;
660 : }
661 :
662 7 : ret = sss_hash_create(state->group_ctx, 32, &state->group_ctx->groups);
663 7 : if (ret != EOK) {
664 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n",
665 : ret, strerror(ret));
666 0 : goto immediately;
667 : }
668 :
669 7 : state->group_ctx->try_deref = true;
670 7 : state->group_ctx->deref_treshold = dp_opt_get_int(opts->basic,
671 : SDAP_DEREF_THRESHOLD);
672 7 : state->group_ctx->max_nesting_level = dp_opt_get_int(opts->basic,
673 : SDAP_NESTING_LEVEL);
674 7 : state->group_ctx->domain = sdom->dom;
675 7 : state->group_ctx->opts = opts;
676 7 : state->group_ctx->user_search_bases = sdom->user_search_bases;
677 7 : state->group_ctx->group_search_bases = sdom->group_search_bases;
678 7 : state->group_ctx->sh = sh;
679 7 : state->group_ctx->try_deref = sdap_has_deref_support(sh, opts);
680 :
681 : /* disable deref if threshold <= 0 */
682 7 : if (state->group_ctx->deref_treshold <= 0) {
683 0 : state->group_ctx->try_deref = false;
684 : }
685 :
686 : /* if any search base contains filter, disable dereference. */
687 7 : if (state->group_ctx->try_deref) {
688 0 : for (i = 0; opts->sdom->user_search_bases[i] != NULL; i++) {
689 0 : if (opts->sdom->user_search_bases[i]->filter != NULL) {
690 0 : DEBUG(SSSDBG_TRACE_FUNC, "User search base contains filter, "
691 : "dereference will be disabled\n");
692 0 : state->group_ctx->try_deref = false;
693 0 : break;
694 : }
695 : }
696 : }
697 :
698 7 : if (state->group_ctx->try_deref) {
699 0 : for (i = 0; opts->sdom->group_search_bases[i] != NULL; i++) {
700 0 : if (opts->sdom->group_search_bases[i]->filter != NULL) {
701 0 : DEBUG(SSSDBG_TRACE_FUNC, "Group search base contains filter, "
702 : "dereference will be disabled\n");
703 0 : state->group_ctx->try_deref = false;
704 0 : break;
705 : }
706 : }
707 : }
708 :
709 : /* insert initial group into hash table */
710 7 : ret = sdap_nested_group_hash_group(state->group_ctx, group);
711 7 : if (ret != EOK) {
712 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to insert group into hash table "
713 : "[%d]: %s\n", ret, strerror(ret));
714 0 : goto immediately;
715 : }
716 :
717 : /* resolve group */
718 7 : subreq = sdap_nested_group_process_send(state, ev, state->group_ctx,
719 : 0, group);
720 7 : if (subreq == NULL) {
721 0 : ret = ENOMEM;
722 0 : goto immediately;
723 : }
724 :
725 7 : tevent_req_set_callback(subreq, sdap_nested_group_done, req);
726 :
727 7 : return req;
728 :
729 : immediately:
730 0 : if (ret == EOK) {
731 0 : tevent_req_done(req);
732 : } else {
733 0 : tevent_req_error(req, ret);
734 : }
735 0 : tevent_req_post(req, ev);
736 :
737 0 : return req;
738 : }
739 :
740 7 : static void sdap_nested_group_done(struct tevent_req *subreq)
741 : {
742 7 : struct tevent_req *req = NULL;
743 : errno_t ret;
744 :
745 7 : req = tevent_req_callback_data(subreq, struct tevent_req);
746 :
747 7 : ret = sdap_nested_group_process_recv(subreq);
748 7 : talloc_zfree(subreq);
749 7 : if (ret != EOK) {
750 1 : tevent_req_error(req, ret);
751 1 : return;
752 : }
753 :
754 6 : tevent_req_done(req);
755 : }
756 :
757 7 : errno_t sdap_nested_group_recv(TALLOC_CTX *mem_ctx,
758 : struct tevent_req *req,
759 : unsigned long *_num_users,
760 : struct sysdb_attrs ***_users,
761 : unsigned long *_num_groups,
762 : struct sysdb_attrs ***_groups)
763 : {
764 7 : struct sdap_nested_group_state *state = NULL;
765 7 : struct sysdb_attrs **users = NULL;
766 7 : struct sysdb_attrs **groups = NULL;
767 : unsigned long num_users;
768 : unsigned long num_groups;
769 : errno_t ret;
770 :
771 7 : state = tevent_req_data(req, struct sdap_nested_group_state);
772 :
773 8 : TEVENT_REQ_RETURN_ON_ERROR(req);
774 :
775 6 : ret = sdap_nested_group_extract_hash_table(state, state->group_ctx->users,
776 : &num_users, &users);
777 6 : if (ret != EOK) {
778 0 : return ret;
779 : }
780 :
781 6 : DEBUG(SSSDBG_TRACE_FUNC, "%lu users found in the hash table\n",
782 : num_users);
783 :
784 6 : ret = sdap_nested_group_extract_hash_table(state, state->group_ctx->groups,
785 : &num_groups, &groups);
786 6 : if (ret != EOK) {
787 0 : return ret;
788 : }
789 :
790 6 : DEBUG(SSSDBG_TRACE_FUNC, "%lu groups found in the hash table\n",
791 : num_groups);
792 :
793 6 : if (_num_users != NULL) {
794 6 : *_num_users = num_users;
795 : }
796 :
797 6 : if (_users != NULL) {
798 6 : *_users = talloc_steal(mem_ctx, users);
799 : }
800 :
801 6 : if (_num_groups!= NULL) {
802 6 : *_num_groups = num_groups;
803 : }
804 :
805 6 : if (_groups != NULL) {
806 6 : *_groups = talloc_steal(mem_ctx, groups);
807 : }
808 :
809 6 : return EOK;
810 : }
811 :
812 : struct sdap_nested_group_process_state {
813 : struct tevent_context *ev;
814 : struct sdap_nested_group_ctx *group_ctx;
815 : struct sdap_nested_group_member *missing;
816 : int num_missing_total;
817 : int num_missing_groups;
818 : int nesting_level;
819 : char *group_dn;
820 : bool deref;
821 : };
822 :
823 : static void sdap_nested_group_process_done(struct tevent_req *subreq);
824 :
825 : static struct tevent_req *
826 14 : sdap_nested_group_process_send(TALLOC_CTX *mem_ctx,
827 : struct tevent_context *ev,
828 : struct sdap_nested_group_ctx *group_ctx,
829 : int nesting_level,
830 : struct sysdb_attrs *group)
831 : {
832 14 : struct sdap_nested_group_process_state *state = NULL;
833 14 : struct sdap_attr_map *group_map = NULL;
834 14 : struct tevent_req *req = NULL;
835 14 : struct tevent_req *subreq = NULL;
836 14 : struct ldb_message_element *members = NULL;
837 14 : const char *orig_dn = NULL;
838 : errno_t ret;
839 :
840 14 : req = tevent_req_create(mem_ctx, &state,
841 : struct sdap_nested_group_process_state);
842 14 : if (req == NULL) {
843 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
844 0 : return NULL;
845 : }
846 :
847 14 : state->ev = ev;
848 14 : state->group_ctx = group_ctx;
849 14 : state->nesting_level = nesting_level;
850 14 : group_map = state->group_ctx->opts->group_map;
851 :
852 : /* get original dn */
853 14 : ret = sysdb_attrs_get_string(group, SYSDB_ORIG_DN, &orig_dn);
854 14 : if (ret != EOK) {
855 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve original dn "
856 : "[%d]: %s\n", ret, strerror(ret));
857 0 : goto immediately;
858 : }
859 :
860 14 : state->group_dn = talloc_strdup(state, orig_dn);
861 14 : if (state->group_dn == NULL) {
862 0 : ret = ENOMEM;
863 0 : goto immediately;
864 : }
865 :
866 14 : DEBUG(SSSDBG_TRACE_INTERNAL, "About to process group [%s]\n", orig_dn);
867 :
868 : /* get member list */
869 14 : ret = sysdb_attrs_get_el_ext(group, group_map[SDAP_AT_GROUP_MEMBER].sys_name,
870 : false, &members);
871 14 : if (ret == ENOENT) {
872 4 : ret = EOK; /* no members */
873 4 : goto immediately;
874 10 : } else if (ret != EOK) {
875 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve member list "
876 : "[%d]: %s\n", ret, strerror(ret));
877 0 : goto immediately;
878 : }
879 :
880 : /* get members that need to be refreshed */
881 40 : ret = sdap_nested_group_split_members(state, state->group_ctx,
882 10 : state->nesting_level, members,
883 10 : &state->missing,
884 10 : &state->num_missing_total,
885 10 : &state->num_missing_groups);
886 10 : if (ret != EOK) {
887 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to split member list "
888 : "[%d]: %s\n", ret, sss_strerror(ret));
889 0 : goto immediately;
890 : }
891 :
892 10 : DEBUG(SSSDBG_TRACE_INTERNAL, "Looking up %d/%d members of group [%s]\n",
893 : state->num_missing_total, members->num_values, orig_dn);
894 :
895 10 : if (state->num_missing_total == 0) {
896 0 : ret = EOK; /* we're done */
897 0 : goto immediately;
898 : }
899 :
900 : /* process members */
901 10 : if (group_ctx->try_deref
902 0 : && state->num_missing_total > group_ctx->deref_treshold) {
903 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Dereferencing members of group [%s]\n",
904 : orig_dn);
905 0 : state->deref = true;
906 0 : subreq = sdap_nested_group_deref_send(state, ev, group_ctx, members,
907 : orig_dn,
908 0 : state->nesting_level);
909 : } else {
910 10 : DEBUG(SSSDBG_TRACE_INTERNAL, "Members of group [%s] will be "
911 : "processed individually\n", orig_dn);
912 10 : state->deref = false;
913 40 : subreq = sdap_nested_group_single_send(state, ev, group_ctx,
914 10 : state->missing,
915 10 : state->num_missing_total,
916 10 : state->num_missing_groups,
917 10 : state->nesting_level);
918 : }
919 10 : if (subreq == NULL) {
920 0 : ret = ENOMEM;
921 0 : goto immediately;
922 : }
923 :
924 10 : tevent_req_set_callback(subreq, sdap_nested_group_process_done, req);
925 :
926 10 : return req;
927 :
928 : immediately:
929 4 : if (ret == EOK) {
930 4 : tevent_req_done(req);
931 : } else {
932 0 : tevent_req_error(req, ret);
933 : }
934 4 : tevent_req_post(req, ev);
935 :
936 4 : return req;
937 : }
938 :
939 10 : static void sdap_nested_group_process_done(struct tevent_req *subreq)
940 : {
941 10 : struct sdap_nested_group_process_state *state = NULL;
942 10 : struct tevent_req *req = NULL;
943 : errno_t ret;
944 :
945 10 : req = tevent_req_callback_data(subreq, struct tevent_req);
946 10 : state = tevent_req_data(req, struct sdap_nested_group_process_state);
947 :
948 10 : if (state->deref) {
949 0 : ret = sdap_nested_group_deref_recv(subreq);
950 0 : talloc_zfree(subreq);
951 0 : if (ret == ENOTSUP) {
952 : /* dereference is not supported, try again without dereference */
953 0 : state->group_ctx->try_deref = false;
954 0 : state->deref = false;
955 :
956 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Members of group [%s] will be "
957 : "processed individually\n", state->group_dn);
958 :
959 0 : subreq = sdap_nested_group_single_send(state,
960 : state->ev,
961 : state->group_ctx,
962 : state->missing,
963 : state->num_missing_total,
964 : state->num_missing_groups,
965 : state->nesting_level);
966 0 : if (subreq == NULL) {
967 0 : ret = ENOMEM;
968 0 : goto done;
969 : }
970 :
971 0 : tevent_req_set_callback(subreq, sdap_nested_group_process_done,
972 : req);
973 :
974 0 : ret = EAGAIN;
975 : }
976 : } else {
977 10 : ret = sdap_nested_group_single_recv(subreq);
978 10 : talloc_zfree(subreq);
979 : }
980 :
981 : done:
982 10 : if (ret == EOK) {
983 7 : tevent_req_done(req);
984 3 : } else if (ret != EAGAIN) {
985 3 : tevent_req_error(req, ret);
986 : }
987 10 : }
988 :
989 14 : static errno_t sdap_nested_group_process_recv(struct tevent_req *req)
990 : {
991 17 : TEVENT_REQ_RETURN_ON_ERROR(req);
992 :
993 11 : return EOK;
994 : }
995 :
996 : struct sdap_nested_group_recurse_state {
997 : struct tevent_context *ev;
998 : struct sdap_nested_group_ctx *group_ctx;
999 : struct sysdb_attrs **groups;
1000 : int num_groups;
1001 : int index;
1002 : int nesting_level;
1003 : };
1004 :
1005 : static errno_t sdap_nested_group_recurse_step(struct tevent_req *req);
1006 : static void sdap_nested_group_recurse_done(struct tevent_req *subreq);
1007 :
1008 : static struct tevent_req *
1009 9 : sdap_nested_group_recurse_send(TALLOC_CTX *mem_ctx,
1010 : struct tevent_context *ev,
1011 : struct sdap_nested_group_ctx *group_ctx,
1012 : struct sysdb_attrs **nested_groups,
1013 : int num_groups,
1014 : int nesting_level)
1015 : {
1016 9 : struct sdap_nested_group_recurse_state *state = NULL;
1017 9 : struct tevent_req *req = NULL;
1018 : errno_t ret;
1019 :
1020 9 : req = tevent_req_create(mem_ctx, &state,
1021 : struct sdap_nested_group_recurse_state);
1022 9 : if (req == NULL) {
1023 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
1024 0 : return NULL;
1025 : }
1026 :
1027 9 : state->ev = ev;
1028 9 : state->group_ctx = group_ctx;
1029 9 : state->groups = nested_groups;
1030 9 : state->num_groups = num_groups;
1031 9 : state->index = 0;
1032 9 : state->nesting_level = nesting_level;
1033 :
1034 : /* process each group individually */
1035 9 : ret = sdap_nested_group_recurse_step(req);
1036 9 : if (ret != EAGAIN) {
1037 3 : goto immediately;
1038 : }
1039 :
1040 6 : return req;
1041 :
1042 : immediately:
1043 3 : if (ret == EOK) {
1044 3 : tevent_req_done(req);
1045 : } else {
1046 0 : tevent_req_error(req, ret);
1047 : }
1048 3 : tevent_req_post(req, ev);
1049 :
1050 3 : return req;
1051 : }
1052 :
1053 14 : static errno_t sdap_nested_group_recurse_step(struct tevent_req *req)
1054 : {
1055 14 : struct sdap_nested_group_recurse_state *state = NULL;
1056 14 : struct tevent_req *subreq = NULL;
1057 :
1058 14 : state = tevent_req_data(req, struct sdap_nested_group_recurse_state);
1059 :
1060 14 : if (state->index >= state->num_groups) {
1061 : /* we're done */
1062 7 : return EOK;
1063 : }
1064 :
1065 7 : subreq = sdap_nested_group_process_send(state, state->ev, state->group_ctx,
1066 : state->nesting_level,
1067 7 : state->groups[state->index]);
1068 7 : if (subreq == NULL) {
1069 0 : return ENOMEM;
1070 : }
1071 :
1072 7 : tevent_req_set_callback(subreq, sdap_nested_group_recurse_done, req);
1073 :
1074 7 : state->index++;
1075 :
1076 7 : return EAGAIN;
1077 : }
1078 :
1079 7 : static void sdap_nested_group_recurse_done(struct tevent_req *subreq)
1080 : {
1081 7 : struct tevent_req *req = NULL;
1082 : errno_t ret;
1083 :
1084 7 : req = tevent_req_callback_data(subreq, struct tevent_req);
1085 :
1086 7 : ret = sdap_nested_group_process_recv(subreq);
1087 7 : talloc_zfree(subreq);
1088 7 : if (ret != EOK) {
1089 2 : goto done;
1090 : }
1091 :
1092 5 : ret = sdap_nested_group_recurse_step(req);
1093 :
1094 : done:
1095 7 : if (ret == EOK) {
1096 4 : tevent_req_done(req);
1097 3 : } else if (ret != EAGAIN) {
1098 2 : tevent_req_error(req, ret);
1099 : }
1100 :
1101 7 : return;
1102 : }
1103 :
1104 9 : static errno_t sdap_nested_group_recurse_recv(struct tevent_req *req)
1105 : {
1106 11 : TEVENT_REQ_RETURN_ON_ERROR(req);
1107 :
1108 7 : return EOK;
1109 : }
1110 :
1111 : struct sdap_nested_group_single_state {
1112 : struct tevent_context *ev;
1113 : struct sdap_nested_group_ctx *group_ctx;
1114 : struct sdap_nested_group_member *members;
1115 : int nesting_level;
1116 :
1117 : struct sdap_nested_group_member *current_member;
1118 : int num_members;
1119 : int member_index;
1120 :
1121 : struct sysdb_attrs **nested_groups;
1122 : int num_groups;
1123 : };
1124 :
1125 : static errno_t sdap_nested_group_single_step(struct tevent_req *req);
1126 : static void sdap_nested_group_single_step_done(struct tevent_req *subreq);
1127 : static void sdap_nested_group_single_done(struct tevent_req *subreq);
1128 :
1129 : static struct tevent_req *
1130 10 : sdap_nested_group_single_send(TALLOC_CTX *mem_ctx,
1131 : struct tevent_context *ev,
1132 : struct sdap_nested_group_ctx *group_ctx,
1133 : struct sdap_nested_group_member *members,
1134 : int num_members,
1135 : int num_groups_max,
1136 : int nesting_level)
1137 : {
1138 10 : struct sdap_nested_group_single_state *state = NULL;
1139 10 : struct tevent_req *req = NULL;
1140 : errno_t ret;
1141 :
1142 10 : req = tevent_req_create(mem_ctx, &state,
1143 : struct sdap_nested_group_single_state);
1144 10 : if (req == NULL) {
1145 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
1146 0 : return NULL;
1147 : }
1148 :
1149 10 : state->ev = ev;
1150 10 : state->group_ctx = group_ctx;
1151 10 : state->members = members;
1152 10 : state->nesting_level = nesting_level;
1153 10 : state->current_member = NULL;
1154 10 : state->num_members = num_members;
1155 10 : state->member_index = 0;
1156 10 : state->nested_groups = talloc_zero_array(state, struct sysdb_attrs *,
1157 : num_groups_max);
1158 10 : if (state->nested_groups == NULL) {
1159 0 : ret = ENOMEM;
1160 0 : goto immediately;
1161 : }
1162 10 : state->num_groups = 0; /* we will count exact number of the groups */
1163 :
1164 : /* process each member individually */
1165 10 : ret = sdap_nested_group_single_step(req);
1166 10 : if (ret != EAGAIN) {
1167 0 : goto immediately;
1168 : }
1169 :
1170 10 : return req;
1171 :
1172 : immediately:
1173 0 : if (ret == EOK) {
1174 0 : tevent_req_done(req);
1175 : } else {
1176 0 : tevent_req_error(req, ret);
1177 : }
1178 0 : tevent_req_post(req, ev);
1179 :
1180 0 : return req;
1181 : }
1182 :
1183 25 : static errno_t sdap_nested_group_single_step(struct tevent_req *req)
1184 : {
1185 25 : struct sdap_nested_group_single_state *state = NULL;
1186 25 : struct tevent_req *subreq = NULL;
1187 :
1188 25 : state = tevent_req_data(req, struct sdap_nested_group_single_state);
1189 :
1190 25 : if (state->member_index >= state->num_members) {
1191 : /* we're done */
1192 9 : return EOK;
1193 : }
1194 :
1195 16 : state->current_member = &state->members[state->member_index];
1196 16 : state->member_index++;
1197 :
1198 16 : switch (state->current_member->type) {
1199 : case SDAP_NESTED_GROUP_DN_USER:
1200 8 : subreq = sdap_nested_group_lookup_user_send(state, state->ev,
1201 : state->group_ctx,
1202 : state->current_member);
1203 8 : break;
1204 : case SDAP_NESTED_GROUP_DN_GROUP:
1205 8 : subreq = sdap_nested_group_lookup_group_send(state, state->ev,
1206 : state->group_ctx,
1207 : state->current_member);
1208 8 : break;
1209 : case SDAP_NESTED_GROUP_DN_UNKNOWN:
1210 0 : subreq = sdap_nested_group_lookup_unknown_send(state, state->ev,
1211 : state->group_ctx,
1212 : state->current_member);
1213 0 : break;
1214 : }
1215 :
1216 16 : if (subreq == NULL) {
1217 0 : return ENOMEM;
1218 : }
1219 :
1220 16 : tevent_req_set_callback(subreq, sdap_nested_group_single_step_done, req);
1221 :
1222 16 : return EAGAIN;
1223 : }
1224 :
1225 : static errno_t
1226 16 : sdap_nested_group_single_step_process(struct tevent_req *subreq)
1227 : {
1228 16 : struct sdap_nested_group_single_state *state = NULL;
1229 16 : struct tevent_req *req = NULL;
1230 16 : struct sysdb_attrs *entry = NULL;
1231 16 : enum sdap_nested_group_dn_type type = SDAP_NESTED_GROUP_DN_UNKNOWN;
1232 16 : const char *orig_dn = NULL;
1233 : errno_t ret;
1234 :
1235 16 : req = tevent_req_callback_data(subreq, struct tevent_req);
1236 16 : state = tevent_req_data(req, struct sdap_nested_group_single_state);
1237 :
1238 : /* set correct type if possible */
1239 16 : if (state->current_member->type == SDAP_NESTED_GROUP_DN_UNKNOWN) {
1240 0 : ret = sdap_nested_group_lookup_unknown_recv(state, subreq,
1241 : &entry, &type);
1242 0 : if (ret != EOK) {
1243 0 : goto done;
1244 : }
1245 :
1246 0 : if (entry != NULL) {
1247 0 : state->current_member->type = type;
1248 : }
1249 : }
1250 :
1251 16 : switch (state->current_member->type) {
1252 : case SDAP_NESTED_GROUP_DN_USER:
1253 8 : if (entry == NULL) {
1254 : /* type was not unknown, receive data */
1255 8 : ret = sdap_nested_group_lookup_user_recv(state, subreq, &entry);
1256 8 : if (ret != EOK) {
1257 1 : goto done;
1258 : }
1259 :
1260 7 : if (entry == NULL) {
1261 : /* user not found, continue */
1262 0 : break;
1263 : }
1264 : }
1265 :
1266 : /* save user in hash table */
1267 7 : ret = sdap_nested_group_hash_user(state->group_ctx, entry);
1268 7 : if (ret == EEXIST) {
1269 : /* the user is already present, skip it */
1270 1 : talloc_zfree(entry);
1271 1 : ret = EOK;
1272 1 : goto done;
1273 6 : } else if (ret != EOK) {
1274 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save user in hash table "
1275 : "[%d]: %s\n", ret, strerror(ret));
1276 0 : goto done;
1277 : }
1278 6 : break;
1279 : case SDAP_NESTED_GROUP_DN_GROUP:
1280 8 : if (entry == NULL) {
1281 : /* type was not unknown, receive data */
1282 8 : ret = sdap_nested_group_lookup_group_recv(state, subreq, &entry);
1283 8 : if (ret != EOK) {
1284 0 : goto done;
1285 : }
1286 :
1287 8 : if (entry == NULL) {
1288 : /* group not found, continue */
1289 0 : break;
1290 : }
1291 : } else {
1292 : /* the type was unknown so we had to pull the group,
1293 : * but we don't want to process it if we have reached
1294 : * the nesting level */
1295 0 : if (state->nesting_level >= state->group_ctx->max_nesting_level) {
1296 0 : ret = sysdb_attrs_get_string(entry, SYSDB_ORIG_DN, &orig_dn);
1297 0 : if (ret != EOK) {
1298 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1299 : "The entry has no originalDN\n");
1300 0 : orig_dn = "invalid";
1301 : }
1302 :
1303 0 : DEBUG(SSSDBG_TRACE_ALL, "[%s] is outside nesting limit "
1304 : "(level %d), skipping\n", orig_dn, state->nesting_level);
1305 0 : break;
1306 : }
1307 : }
1308 :
1309 : /* save group in hash table */
1310 8 : ret = sdap_nested_group_hash_group(state->group_ctx, entry);
1311 8 : if (ret == EEXIST) {
1312 : /* the group is already present, skip it */
1313 1 : talloc_zfree(entry);
1314 1 : ret = EOK;
1315 1 : goto done;
1316 7 : } else if (ret != EOK) {
1317 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save group in hash table "
1318 : "[%d]: %s\n", ret, strerror(ret));
1319 0 : goto done;
1320 : }
1321 :
1322 : /* remember the group for later processing */
1323 7 : state->nested_groups[state->num_groups] = entry;
1324 7 : state->num_groups++;
1325 :
1326 7 : break;
1327 : case SDAP_NESTED_GROUP_DN_UNKNOWN:
1328 : /* not found in users nor nested_groups, continue */
1329 0 : break;
1330 : }
1331 :
1332 13 : ret = EOK;
1333 :
1334 : done:
1335 16 : return ret;
1336 : }
1337 :
1338 16 : static void sdap_nested_group_single_step_done(struct tevent_req *subreq)
1339 : {
1340 16 : struct sdap_nested_group_single_state *state = NULL;
1341 16 : struct tevent_req *req = NULL;
1342 : errno_t ret;
1343 :
1344 16 : req = tevent_req_callback_data(subreq, struct tevent_req);
1345 16 : state = tevent_req_data(req, struct sdap_nested_group_single_state);
1346 :
1347 : /* process direct members */
1348 16 : ret = sdap_nested_group_single_step_process(subreq);
1349 16 : talloc_zfree(subreq);
1350 16 : if (ret != EOK) {
1351 1 : DEBUG(SSSDBG_CRIT_FAILURE, "Error processing direct membership "
1352 : "[%d]: %s\n", ret, strerror(ret));
1353 1 : goto done;
1354 : }
1355 :
1356 15 : ret = sdap_nested_group_single_step(req);
1357 15 : if (ret == EOK) {
1358 : /* we have processed all direct members,
1359 : * now recurse and process nested groups */
1360 9 : subreq = sdap_nested_group_recurse_send(state, state->ev,
1361 : state->group_ctx,
1362 : state->nested_groups,
1363 : state->num_groups,
1364 9 : state->nesting_level + 1);
1365 9 : if (subreq == NULL) {
1366 0 : ret = ENOMEM;
1367 0 : goto done;
1368 : }
1369 :
1370 9 : tevent_req_set_callback(subreq, sdap_nested_group_single_done, req);
1371 6 : } else if (ret != EAGAIN) {
1372 : /* error */
1373 0 : goto done;
1374 : }
1375 :
1376 : /* we're not done yet */
1377 15 : ret = EAGAIN;
1378 :
1379 : done:
1380 16 : if (ret == EOK) {
1381 : /* tevent_req_error() cannot cope with EOK */
1382 0 : DEBUG(SSSDBG_CRIT_FAILURE, "We should not get here with EOK\n");
1383 0 : tevent_req_error(req, EINVAL);
1384 16 : } else if (ret != EAGAIN) {
1385 1 : tevent_req_error(req, ret);
1386 : }
1387 :
1388 16 : return;
1389 : }
1390 :
1391 9 : static void sdap_nested_group_single_done(struct tevent_req *subreq)
1392 : {
1393 9 : struct tevent_req *req = NULL;
1394 : errno_t ret;
1395 :
1396 9 : req = tevent_req_callback_data(subreq, struct tevent_req);
1397 :
1398 : /* all nested groups are completed */
1399 9 : ret = sdap_nested_group_recurse_recv(subreq);
1400 9 : talloc_zfree(subreq);
1401 9 : if (ret != EOK) {
1402 2 : DEBUG(SSSDBG_CRIT_FAILURE, "Error processing nested groups "
1403 : "[%d]: %s.\n", ret, strerror(ret));
1404 2 : tevent_req_error(req, ret);
1405 2 : return;
1406 : }
1407 :
1408 7 : tevent_req_done(req);
1409 :
1410 7 : return;
1411 : }
1412 :
1413 10 : static errno_t sdap_nested_group_single_recv(struct tevent_req *req)
1414 : {
1415 13 : TEVENT_REQ_RETURN_ON_ERROR(req);
1416 :
1417 7 : return EOK;
1418 : }
1419 :
1420 : /* This should be a function pointer set from the IPA provider */
1421 0 : static errno_t sdap_nested_group_get_ipa_user(TALLOC_CTX *mem_ctx,
1422 : const char *user_dn,
1423 : struct sysdb_ctx *sysdb,
1424 : struct sysdb_attrs **_user)
1425 : {
1426 : errno_t ret;
1427 0 : struct sysdb_attrs *user = NULL;
1428 : char *name;
1429 0 : struct ldb_dn *dn = NULL;
1430 : const char *rdn_name;
1431 : const char *users_comp_name;
1432 : const char *acct_comp_name;
1433 : const struct ldb_val *rdn_val;
1434 : const struct ldb_val *users_comp_val;
1435 : const struct ldb_val *acct_comp_val;
1436 : TALLOC_CTX *tmp_ctx;
1437 :
1438 0 : tmp_ctx = talloc_new(NULL);
1439 0 : if (!tmp_ctx) return ENOMEM;
1440 :
1441 : /* return username if dn is in form:
1442 : * uid=username,cn=users,cn=accounts,dc=example,dc=com */
1443 :
1444 0 : dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(sysdb), user_dn);
1445 0 : if (dn == NULL) {
1446 0 : ret = ENOMEM;
1447 0 : goto done;
1448 : }
1449 :
1450 : /* rdn, users, accounts and least one domain component */
1451 0 : if (ldb_dn_get_comp_num(dn) < 4) {
1452 0 : ret = ENOENT;
1453 0 : goto done;
1454 : }
1455 :
1456 0 : rdn_name = ldb_dn_get_rdn_name(dn);
1457 0 : if (rdn_name == NULL) {
1458 0 : ret = EINVAL;
1459 0 : goto done;
1460 : }
1461 :
1462 : /* rdn must be 'uid' */
1463 0 : if (strcasecmp("uid", rdn_name) != 0) {
1464 0 : ret = ENOENT;
1465 0 : goto done;
1466 : }
1467 :
1468 : /* second component must be 'cn=users' */
1469 0 : users_comp_name = ldb_dn_get_component_name(dn, 1);
1470 0 : if (strcasecmp("cn", users_comp_name) != 0) {
1471 0 : ret = ENOENT;
1472 0 : goto done;
1473 : }
1474 :
1475 0 : users_comp_val = ldb_dn_get_component_val(dn, 1);
1476 0 : if (strncasecmp("users", (const char *) users_comp_val->data,
1477 : users_comp_val->length) != 0) {
1478 0 : ret = ENOENT;
1479 0 : goto done;
1480 : }
1481 :
1482 : /* third component must be 'cn=accounts' */
1483 0 : acct_comp_name = ldb_dn_get_component_name(dn, 2);
1484 0 : if (strcasecmp("cn", acct_comp_name) != 0) {
1485 0 : ret = ENOENT;
1486 0 : goto done;
1487 : }
1488 :
1489 0 : acct_comp_val = ldb_dn_get_component_val(dn, 2);
1490 0 : if (strncasecmp("accounts", (const char *) acct_comp_val->data,
1491 : acct_comp_val->length) != 0) {
1492 0 : ret = ENOENT;
1493 0 : goto done;
1494 : }
1495 :
1496 : /* value of rdn is username */
1497 0 : user = sysdb_new_attrs(tmp_ctx);
1498 0 : if (user == NULL) {
1499 0 : ret = ENOMEM;
1500 0 : goto done;
1501 : }
1502 :
1503 0 : rdn_val = ldb_dn_get_rdn_val(dn);
1504 0 : name = talloc_strndup(user, (const char *)rdn_val->data, rdn_val->length);
1505 0 : if (name == NULL) {
1506 0 : ret = ENOMEM;
1507 0 : goto done;
1508 : }
1509 :
1510 0 : ret = sysdb_attrs_add_string(user, SYSDB_NAME, name);
1511 0 : if (ret != EOK) {
1512 0 : goto done;
1513 : }
1514 :
1515 0 : ret = sysdb_attrs_add_string(user, SYSDB_ORIG_DN, user_dn);
1516 0 : if (ret != EOK) {
1517 0 : goto done;
1518 : }
1519 :
1520 0 : ret = sysdb_attrs_add_string(user, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS);
1521 0 : if (ret != EOK) {
1522 0 : goto done;
1523 : }
1524 :
1525 0 : *_user = talloc_steal(mem_ctx, user);
1526 :
1527 : done:
1528 0 : talloc_free(tmp_ctx);
1529 0 : return ret;
1530 : }
1531 :
1532 : struct sdap_nested_group_lookup_user_state {
1533 : struct sysdb_attrs *user;
1534 : };
1535 :
1536 : static void sdap_nested_group_lookup_user_done(struct tevent_req *subreq);
1537 :
1538 : static struct tevent_req *
1539 8 : sdap_nested_group_lookup_user_send(TALLOC_CTX *mem_ctx,
1540 : struct tevent_context *ev,
1541 : struct sdap_nested_group_ctx *group_ctx,
1542 : struct sdap_nested_group_member *member)
1543 : {
1544 8 : struct sdap_nested_group_lookup_user_state *state = NULL;
1545 8 : struct tevent_req *req = NULL;
1546 8 : struct tevent_req *subreq = NULL;
1547 8 : const char **attrs = NULL;
1548 8 : const char *base_filter = NULL;
1549 8 : const char *filter = NULL;
1550 : errno_t ret;
1551 :
1552 8 : req = tevent_req_create(mem_ctx, &state,
1553 : struct sdap_nested_group_lookup_user_state);
1554 8 : if (req == NULL) {
1555 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
1556 0 : return NULL;
1557 : }
1558 :
1559 8 : if (group_ctx->opts->schema_type == SDAP_SCHEMA_IPA_V1) {
1560 : /* if the schema is IPA, then just shortcut and guess the name */
1561 0 : ret = sdap_nested_group_get_ipa_user(state, member->dn,
1562 0 : group_ctx->domain->sysdb,
1563 0 : &state->user);
1564 0 : if (ret == EOK) {
1565 0 : goto immediately;
1566 : }
1567 :
1568 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Couldn't parse out user information "
1569 : "based on DN %s, falling back to an LDAP lookup\n", member->dn);
1570 : }
1571 :
1572 : /* only pull down username and originalDN */
1573 8 : attrs = talloc_array(state, const char *, 3);
1574 8 : if (attrs == NULL) {
1575 0 : ret = ENOMEM;
1576 0 : goto immediately;
1577 : }
1578 :
1579 8 : attrs[0] = "objectClass";
1580 8 : attrs[1] = group_ctx->opts->user_map[SDAP_AT_USER_NAME].name;
1581 8 : attrs[2] = NULL;
1582 :
1583 : /* create filter */
1584 8 : base_filter = talloc_asprintf(state, "(objectclass=%s)",
1585 8 : group_ctx->opts->user_map[SDAP_OC_USER].name);
1586 8 : if (base_filter == NULL) {
1587 0 : ret = ENOMEM;
1588 0 : goto immediately;
1589 : }
1590 :
1591 : /* use search base filter if needed */
1592 8 : filter = sdap_get_id_specific_filter(state, base_filter,
1593 : member->user_filter);
1594 8 : if (filter == NULL) {
1595 0 : ret = ENOMEM;
1596 0 : goto immediately;
1597 : }
1598 :
1599 : /* search */
1600 24 : subreq = sdap_get_generic_send(state, ev, group_ctx->opts, group_ctx->sh,
1601 : member->dn, LDAP_SCOPE_BASE, filter, attrs,
1602 8 : group_ctx->opts->user_map,
1603 8 : group_ctx->opts->user_map_cnt,
1604 8 : dp_opt_get_int(group_ctx->opts->basic,
1605 : SDAP_SEARCH_TIMEOUT),
1606 : false);
1607 8 : if (subreq == NULL) {
1608 0 : ret = ENOMEM;
1609 0 : goto immediately;
1610 : }
1611 :
1612 8 : tevent_req_set_callback(subreq, sdap_nested_group_lookup_user_done, req);
1613 :
1614 8 : return req;
1615 :
1616 : immediately:
1617 0 : if (ret == EOK) {
1618 0 : tevent_req_done(req);
1619 : } else {
1620 0 : tevent_req_error(req, ret);
1621 : }
1622 0 : tevent_req_post(req, ev);
1623 :
1624 0 : return req;
1625 : }
1626 :
1627 8 : static void sdap_nested_group_lookup_user_done(struct tevent_req *subreq)
1628 : {
1629 8 : struct sdap_nested_group_lookup_user_state *state = NULL;
1630 8 : struct tevent_req *req = NULL;
1631 8 : struct sysdb_attrs **user = NULL;
1632 8 : size_t count = 0;
1633 : errno_t ret;
1634 :
1635 8 : req = tevent_req_callback_data(subreq, struct tevent_req);
1636 8 : state = tevent_req_data(req, struct sdap_nested_group_lookup_user_state);
1637 :
1638 8 : ret = sdap_get_generic_recv(subreq, state, &count, &user);
1639 8 : talloc_zfree(subreq);
1640 8 : if (ret == ENOENT) {
1641 0 : count = 0;
1642 8 : } else if (ret != EOK) {
1643 1 : goto done;
1644 : }
1645 :
1646 7 : if (count == 1) {
1647 7 : state->user = user[0];
1648 0 : } else if (count == 0) {
1649 : /* group not found */
1650 0 : state->user = NULL;
1651 : } else {
1652 0 : DEBUG(SSSDBG_OP_FAILURE,
1653 : "BASE search returned more than one records\n");
1654 0 : ret = EIO;
1655 0 : goto done;
1656 : }
1657 :
1658 7 : ret = EOK;
1659 :
1660 : done:
1661 8 : if (ret != EOK) {
1662 1 : tevent_req_error(req, ret);
1663 1 : return;
1664 : }
1665 :
1666 7 : tevent_req_done(req);
1667 : }
1668 :
1669 8 : static errno_t sdap_nested_group_lookup_user_recv(TALLOC_CTX *mem_ctx,
1670 : struct tevent_req *req,
1671 : struct sysdb_attrs **_user)
1672 : {
1673 8 : struct sdap_nested_group_lookup_user_state *state = NULL;
1674 8 : state = tevent_req_data(req, struct sdap_nested_group_lookup_user_state);
1675 :
1676 9 : TEVENT_REQ_RETURN_ON_ERROR(req);
1677 :
1678 7 : if (_user != NULL) {
1679 7 : *_user = talloc_steal(mem_ctx, state->user);
1680 : }
1681 :
1682 7 : return EOK;
1683 : }
1684 :
1685 : struct sdap_nested_group_lookup_group_state {
1686 : struct sysdb_attrs *group;
1687 : };
1688 :
1689 : static void sdap_nested_group_lookup_group_done(struct tevent_req *subreq);
1690 :
1691 : static struct tevent_req *
1692 8 : sdap_nested_group_lookup_group_send(TALLOC_CTX *mem_ctx,
1693 : struct tevent_context *ev,
1694 : struct sdap_nested_group_ctx *group_ctx,
1695 : struct sdap_nested_group_member *member)
1696 : {
1697 8 : struct sdap_nested_group_lookup_group_state *state = NULL;
1698 8 : struct tevent_req *req = NULL;
1699 8 : struct tevent_req *subreq = NULL;
1700 8 : struct sdap_attr_map *map = group_ctx->opts->group_map;
1701 8 : const char **attrs = NULL;
1702 8 : const char *base_filter = NULL;
1703 8 : const char *filter = NULL;
1704 : char *oc_list;
1705 : errno_t ret;
1706 :
1707 8 : req = tevent_req_create(mem_ctx, &state,
1708 : struct sdap_nested_group_lookup_group_state);
1709 8 : if (req == NULL) {
1710 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
1711 0 : return NULL;
1712 : }
1713 :
1714 8 : ret = build_attrs_from_map(state, group_ctx->opts->group_map,
1715 : SDAP_OPTS_GROUP, NULL, &attrs, NULL);
1716 8 : if (ret != EOK) {
1717 0 : goto immediately;
1718 : }
1719 :
1720 : /* create filter */
1721 8 : oc_list = sdap_make_oc_list(state, map);
1722 8 : if (oc_list == NULL) {
1723 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
1724 0 : ret = ENOMEM;
1725 0 : goto immediately;
1726 : }
1727 :
1728 8 : base_filter = talloc_asprintf(attrs, "(&(%s)(%s=*))", oc_list,
1729 8 : map[SDAP_AT_GROUP_NAME].name);
1730 8 : if (base_filter == NULL) {
1731 0 : ret = ENOMEM;
1732 0 : goto immediately;
1733 : }
1734 :
1735 : /* use search base filter if needed */
1736 8 : filter = sdap_get_id_specific_filter(state, base_filter,
1737 : member->group_filter);
1738 8 : if (filter == NULL) {
1739 0 : ret = ENOMEM;
1740 0 : goto immediately;
1741 : }
1742 :
1743 : /* search */
1744 8 : subreq = sdap_get_generic_send(state, ev, group_ctx->opts, group_ctx->sh,
1745 : member->dn, LDAP_SCOPE_BASE, filter, attrs,
1746 : map, SDAP_OPTS_GROUP,
1747 8 : dp_opt_get_int(group_ctx->opts->basic,
1748 : SDAP_SEARCH_TIMEOUT),
1749 : false);
1750 8 : if (subreq == NULL) {
1751 0 : ret = ENOMEM;
1752 0 : goto immediately;
1753 : }
1754 :
1755 8 : tevent_req_set_callback(subreq, sdap_nested_group_lookup_group_done, req);
1756 :
1757 8 : return req;
1758 :
1759 : immediately:
1760 0 : if (ret == EOK) {
1761 0 : tevent_req_done(req);
1762 : } else {
1763 0 : tevent_req_error(req, ret);
1764 : }
1765 0 : tevent_req_post(req, ev);
1766 :
1767 0 : return req;
1768 : }
1769 :
1770 8 : static void sdap_nested_group_lookup_group_done(struct tevent_req *subreq)
1771 : {
1772 8 : struct sdap_nested_group_lookup_group_state *state = NULL;
1773 8 : struct tevent_req *req = NULL;
1774 8 : struct sysdb_attrs **group = NULL;
1775 8 : size_t count = 0;
1776 : errno_t ret;
1777 :
1778 8 : req = tevent_req_callback_data(subreq, struct tevent_req);
1779 8 : state = tevent_req_data(req, struct sdap_nested_group_lookup_group_state);
1780 :
1781 8 : ret = sdap_get_generic_recv(subreq, state, &count, &group);
1782 8 : talloc_zfree(subreq);
1783 8 : if (ret == ENOENT) {
1784 0 : count = 0;
1785 8 : } else if (ret != EOK) {
1786 0 : goto done;
1787 : }
1788 :
1789 8 : if (count == 1) {
1790 8 : state->group = group[0];
1791 0 : } else if (count == 0) {
1792 : /* group not found */
1793 0 : state->group = NULL;
1794 : } else {
1795 0 : DEBUG(SSSDBG_OP_FAILURE,
1796 : "BASE search returned more than one records\n");
1797 0 : ret = EIO;
1798 0 : goto done;
1799 : }
1800 :
1801 8 : ret = EOK;
1802 :
1803 : done:
1804 8 : if (ret != EOK) {
1805 0 : tevent_req_error(req, ret);
1806 0 : return;
1807 : }
1808 :
1809 8 : tevent_req_done(req);
1810 : }
1811 :
1812 8 : static errno_t sdap_nested_group_lookup_group_recv(TALLOC_CTX *mem_ctx,
1813 : struct tevent_req *req,
1814 : struct sysdb_attrs **_group)
1815 : {
1816 8 : struct sdap_nested_group_lookup_group_state *state = NULL;
1817 8 : state = tevent_req_data(req, struct sdap_nested_group_lookup_group_state);
1818 :
1819 8 : TEVENT_REQ_RETURN_ON_ERROR(req);
1820 :
1821 8 : if (_group != NULL) {
1822 8 : *_group = talloc_steal(mem_ctx, state->group);
1823 : }
1824 :
1825 8 : return EOK;
1826 : }
1827 :
1828 : struct sdap_nested_group_lookup_unknown_state {
1829 : struct tevent_context *ev;
1830 : struct sdap_nested_group_ctx *group_ctx;
1831 : struct sdap_nested_group_member *member;
1832 : enum sdap_nested_group_dn_type type;
1833 : struct sysdb_attrs *entry;
1834 : };
1835 :
1836 : static void
1837 : sdap_nested_group_lookup_unknown_user_done(struct tevent_req *subreq);
1838 :
1839 : static void
1840 : sdap_nested_group_lookup_unknown_group_done(struct tevent_req *subreq);
1841 :
1842 : static struct tevent_req *
1843 0 : sdap_nested_group_lookup_unknown_send(TALLOC_CTX *mem_ctx,
1844 : struct tevent_context *ev,
1845 : struct sdap_nested_group_ctx *group_ctx,
1846 : struct sdap_nested_group_member *member)
1847 : {
1848 0 : struct sdap_nested_group_lookup_unknown_state *state = NULL;
1849 0 : struct tevent_req *req = NULL;
1850 0 : struct tevent_req *subreq = NULL;
1851 : errno_t ret;
1852 :
1853 0 : req = tevent_req_create(mem_ctx, &state,
1854 : struct sdap_nested_group_lookup_unknown_state);
1855 0 : if (req == NULL) {
1856 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
1857 0 : return NULL;
1858 : }
1859 :
1860 0 : state->ev = ev;
1861 0 : state->group_ctx = group_ctx;
1862 0 : state->member = member;
1863 :
1864 : /* try users first */
1865 0 : subreq = sdap_nested_group_lookup_user_send(state,
1866 0 : state->ev,
1867 0 : state->group_ctx,
1868 0 : state->member);
1869 0 : if (subreq == NULL) {
1870 0 : ret = ENOMEM;
1871 0 : goto immediately;
1872 : }
1873 :
1874 0 : tevent_req_set_callback(subreq, sdap_nested_group_lookup_unknown_user_done,
1875 : req);
1876 :
1877 0 : return req;
1878 :
1879 : immediately:
1880 0 : if (ret == EOK) {
1881 0 : tevent_req_done(req);
1882 : } else {
1883 0 : tevent_req_error(req, ret);
1884 : }
1885 0 : tevent_req_post(req, ev);
1886 :
1887 0 : return req;
1888 : }
1889 :
1890 : static void
1891 0 : sdap_nested_group_lookup_unknown_user_done(struct tevent_req *subreq)
1892 : {
1893 0 : struct sdap_nested_group_lookup_unknown_state *state = NULL;
1894 0 : struct tevent_req *req = NULL;
1895 0 : struct sysdb_attrs *entry = NULL;
1896 : errno_t ret;
1897 :
1898 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1899 0 : state = tevent_req_data(req, struct sdap_nested_group_lookup_unknown_state);
1900 :
1901 0 : ret = sdap_nested_group_lookup_user_recv(state, subreq, &entry);
1902 0 : talloc_zfree(subreq);
1903 0 : if (ret != EOK) {
1904 0 : goto done;
1905 : }
1906 :
1907 0 : if (entry != NULL) {
1908 : /* found in users */
1909 0 : state->entry = entry;
1910 0 : state->type = SDAP_NESTED_GROUP_DN_USER;
1911 0 : ret = EOK;
1912 0 : goto done;
1913 : }
1914 :
1915 : /* not found in users, try group */
1916 0 : subreq = sdap_nested_group_lookup_group_send(state,
1917 : state->ev,
1918 : state->group_ctx,
1919 : state->member);
1920 0 : if (subreq == NULL) {
1921 0 : ret = ENOMEM;
1922 0 : goto done;
1923 : }
1924 :
1925 0 : tevent_req_set_callback(subreq, sdap_nested_group_lookup_unknown_group_done,
1926 : req);
1927 :
1928 0 : ret = EAGAIN;
1929 :
1930 : done:
1931 0 : if (ret == EOK) {
1932 0 : tevent_req_done(req);
1933 0 : } else if (ret != EAGAIN) {
1934 0 : tevent_req_error(req, ret);
1935 : }
1936 :
1937 0 : return;
1938 : }
1939 :
1940 : static void
1941 0 : sdap_nested_group_lookup_unknown_group_done(struct tevent_req *subreq)
1942 : {
1943 0 : struct sdap_nested_group_lookup_unknown_state *state = NULL;
1944 0 : struct tevent_req *req = NULL;
1945 0 : struct sysdb_attrs *entry = NULL;
1946 : errno_t ret;
1947 :
1948 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1949 0 : state = tevent_req_data(req, struct sdap_nested_group_lookup_unknown_state);
1950 :
1951 0 : ret = sdap_nested_group_lookup_group_recv(state, subreq, &entry);
1952 0 : talloc_zfree(subreq);
1953 0 : if (ret != EOK) {
1954 0 : goto done;
1955 : }
1956 :
1957 0 : if (entry == NULL) {
1958 : /* not found, end request */
1959 0 : state->entry = NULL;
1960 0 : state->type = SDAP_NESTED_GROUP_DN_UNKNOWN;
1961 : } else {
1962 : /* found in groups */
1963 0 : state->entry = entry;
1964 0 : state->type = SDAP_NESTED_GROUP_DN_GROUP;
1965 : }
1966 :
1967 0 : ret = EOK;
1968 :
1969 : done:
1970 0 : if (ret != EOK) {
1971 0 : tevent_req_error(req, ret);
1972 0 : return;
1973 : }
1974 :
1975 0 : tevent_req_done(req);
1976 : }
1977 :
1978 : static errno_t
1979 0 : sdap_nested_group_lookup_unknown_recv(TALLOC_CTX *mem_ctx,
1980 : struct tevent_req *req,
1981 : struct sysdb_attrs **_entry,
1982 : enum sdap_nested_group_dn_type *_type)
1983 : {
1984 0 : struct sdap_nested_group_lookup_unknown_state *state = NULL;
1985 0 : state = tevent_req_data(req, struct sdap_nested_group_lookup_unknown_state);
1986 :
1987 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1988 :
1989 0 : if (_entry != NULL) {
1990 0 : *_entry = talloc_steal(mem_ctx, state->entry);
1991 : }
1992 :
1993 0 : if (_type != NULL) {
1994 0 : *_type = state->type;
1995 : }
1996 :
1997 :
1998 0 : return EOK;
1999 : }
2000 :
2001 : struct sdap_nested_group_deref_state {
2002 : struct tevent_context *ev;
2003 : struct sdap_nested_group_ctx *group_ctx;
2004 : struct ldb_message_element *members;
2005 : int nesting_level;
2006 :
2007 : struct sysdb_attrs **nested_groups;
2008 : int num_groups;
2009 : };
2010 :
2011 : static void sdap_nested_group_deref_direct_done(struct tevent_req *subreq);
2012 : static void sdap_nested_group_deref_done(struct tevent_req *subreq);
2013 :
2014 : static struct tevent_req *
2015 0 : sdap_nested_group_deref_send(TALLOC_CTX *mem_ctx,
2016 : struct tevent_context *ev,
2017 : struct sdap_nested_group_ctx *group_ctx,
2018 : struct ldb_message_element *members,
2019 : const char *group_dn,
2020 : int nesting_level)
2021 : {
2022 0 : struct sdap_nested_group_deref_state *state = NULL;
2023 0 : struct tevent_req *req = NULL;
2024 0 : struct tevent_req *subreq = NULL;
2025 0 : struct sdap_attr_map_info *maps = NULL;
2026 : static const int num_maps = 2;
2027 0 : struct sdap_options *opts = group_ctx->opts;
2028 0 : const char **attrs = NULL;
2029 0 : size_t num_attrs = 0;
2030 : errno_t ret;
2031 :
2032 0 : req = tevent_req_create(mem_ctx, &state,
2033 : struct sdap_nested_group_deref_state);
2034 0 : if (req == NULL) {
2035 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
2036 0 : return NULL;
2037 : }
2038 :
2039 0 : state->ev = ev;
2040 0 : state->group_ctx = group_ctx;
2041 0 : state->members = members;
2042 0 : state->nesting_level = nesting_level;
2043 0 : state->num_groups = 0; /* we will count exact number of the groups */
2044 :
2045 0 : maps = talloc_array(state, struct sdap_attr_map_info, num_maps);
2046 0 : if (maps == NULL) {
2047 0 : ret = ENOMEM;
2048 0 : goto immediately;
2049 : }
2050 :
2051 0 : maps[0].map = opts->user_map;
2052 0 : maps[0].num_attrs = opts->user_map_cnt;
2053 0 : maps[1].map = opts->group_map;
2054 0 : maps[1].num_attrs = SDAP_OPTS_GROUP;
2055 :
2056 : /* pull down the whole group map,
2057 : * but only pull down username and originalDN for users */
2058 0 : ret = build_attrs_from_map(state, opts->group_map, SDAP_OPTS_GROUP,
2059 : NULL, &attrs, &num_attrs);
2060 0 : if (ret != EOK) {
2061 0 : goto immediately;
2062 : }
2063 :
2064 0 : attrs = talloc_realloc(state, attrs, const char *, num_attrs + 2);
2065 0 : if (attrs == NULL) {
2066 0 : ret = ENOMEM;
2067 0 : goto immediately;
2068 : }
2069 :
2070 0 : attrs[num_attrs] = group_ctx->opts->user_map[SDAP_AT_USER_NAME].name;
2071 0 : attrs[num_attrs + 1] = NULL;
2072 :
2073 : /* send request */
2074 0 : subreq = sdap_deref_search_send(state, ev, opts, group_ctx->sh, group_dn,
2075 0 : opts->group_map[SDAP_AT_GROUP_MEMBER].name,
2076 : attrs, num_maps, maps,
2077 : dp_opt_get_int(opts->basic,
2078 : SDAP_SEARCH_TIMEOUT));
2079 0 : if (subreq == NULL) {
2080 0 : ret = ENOMEM;
2081 0 : goto immediately;
2082 : }
2083 :
2084 0 : tevent_req_set_callback(subreq, sdap_nested_group_deref_direct_done, req);
2085 :
2086 0 : return req;
2087 :
2088 : immediately:
2089 0 : if (ret == EOK) {
2090 0 : tevent_req_done(req);
2091 : } else {
2092 0 : tevent_req_error(req, ret);
2093 : }
2094 0 : tevent_req_post(req, ev);
2095 :
2096 0 : return req;
2097 : }
2098 :
2099 : static errno_t
2100 0 : sdap_nested_group_deref_direct_process(struct tevent_req *subreq)
2101 : {
2102 0 : struct sdap_nested_group_deref_state *state = NULL;
2103 0 : struct tevent_req *req = NULL;
2104 0 : struct sdap_options *opts = NULL;
2105 0 : struct sdap_deref_attrs **entries = NULL;
2106 0 : struct ldb_message_element *members = NULL;
2107 0 : const char *orig_dn = NULL;
2108 0 : const char *member_dn = NULL;
2109 0 : size_t num_entries = 0;
2110 : size_t i, j;
2111 : bool member_found;
2112 : errno_t ret;
2113 :
2114 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
2115 0 : state = tevent_req_data(req, struct sdap_nested_group_deref_state);
2116 :
2117 0 : opts = state->group_ctx->opts;
2118 0 : members = state->members;
2119 :
2120 0 : ret = sdap_deref_search_recv(subreq, state, &num_entries, &entries);
2121 0 : if (ret != EOK) {
2122 0 : goto done;
2123 : }
2124 :
2125 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Received %zu dereference results, "
2126 : "about to process them\n", num_entries);
2127 :
2128 : /*
2129 : * We don't have any knowledge about possible number of groups when
2130 : * dereferencing. We expect that every member is a group and we will
2131 : * allocate enough space to hold it. We will shrink the memory later.
2132 : */
2133 0 : state->nested_groups = talloc_zero_array(state, struct sysdb_attrs *,
2134 : num_entries);
2135 0 : if (state->nested_groups == NULL) {
2136 0 : ret = ENOMEM;
2137 0 : goto done;
2138 : }
2139 :
2140 0 : for (i = 0; i < num_entries; i++) {
2141 0 : ret = sysdb_attrs_get_string(entries[i]->attrs,
2142 : SYSDB_ORIG_DN, &orig_dn);
2143 0 : if (ret != EOK) {
2144 0 : DEBUG(SSSDBG_CRIT_FAILURE, "The entry has no originalDN\n");
2145 0 : goto done;
2146 : }
2147 :
2148 : /* Ensure that all members returned from the deref request are included
2149 : * in the member processing. Sometimes we will get more results back
2150 : * from deref/asq than we got from the initial lookup, as is the case
2151 : * with Active Directory and its range retrieval mechanism.
2152 : */
2153 0 : member_found = false;
2154 0 : for (j = 0; j < members->num_values; j++) {
2155 : /* FIXME: This is inefficient for very large sets of groups */
2156 0 : member_dn = (const char *)members->values[j].data;
2157 0 : if (strcasecmp(orig_dn, member_dn) == 0) {
2158 0 : member_found = true;
2159 0 : break;
2160 : }
2161 : }
2162 :
2163 0 : if (!member_found) {
2164 : /* Append newly found member to member list.
2165 : * Changes in state->members will propagate into sysdb_attrs of
2166 : * the group. */
2167 0 : state->members->values = talloc_realloc(members, members->values,
2168 : struct ldb_val,
2169 : members->num_values + 1);
2170 0 : if (members->values == NULL) {
2171 0 : ret = ENOMEM;
2172 0 : goto done;
2173 : }
2174 :
2175 0 : members->values[members->num_values].data =
2176 0 : (uint8_t *)talloc_strdup(members->values, orig_dn);
2177 0 : if (members->values[members->num_values].data == NULL) {
2178 0 : ret = ENOMEM;
2179 0 : goto done;
2180 : }
2181 :
2182 0 : members->values[members->num_values].length = strlen(orig_dn);
2183 0 : members->num_values++;
2184 : }
2185 :
2186 0 : if (entries[i]->map == opts->user_map) {
2187 : /* we found a user */
2188 :
2189 : /* skip the user if it is not amongst configured search bases */
2190 0 : if (!sdap_nested_member_is_user(state->group_ctx, orig_dn, NULL)) {
2191 0 : continue;
2192 : }
2193 :
2194 : /* save user in hash table */
2195 0 : ret = sdap_nested_group_hash_user(state->group_ctx,
2196 0 : entries[i]->attrs);
2197 0 : if (ret != EOK && ret != EEXIST) {
2198 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2199 : "Unable to save user in hash table "
2200 : "[%d]: %s\n", ret, strerror(ret));
2201 0 : goto done;
2202 : }
2203 :
2204 0 : } else if (entries[i]->map == opts->group_map) {
2205 : /* we found a group */
2206 :
2207 : /* skip the group if we have reached the nesting limit */
2208 0 : if (state->nesting_level >= state->group_ctx->max_nesting_level) {
2209 0 : DEBUG(SSSDBG_TRACE_ALL, "[%s] is outside nesting limit "
2210 : "(level %d), skipping\n", orig_dn, state->nesting_level);
2211 0 : continue;
2212 : }
2213 :
2214 : /* skip the group if it is not amongst configured search bases */
2215 0 : if (!sdap_nested_member_is_group(state->group_ctx, orig_dn, NULL)) {
2216 0 : continue;
2217 : }
2218 :
2219 : /* save group in hash table */
2220 0 : ret = sdap_nested_group_hash_group(state->group_ctx,
2221 0 : entries[i]->attrs);
2222 0 : if (ret == EEXIST) {
2223 0 : continue;
2224 0 : } else if (ret != EOK) {
2225 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2226 : "Unable to save group in hash table "
2227 : "[%d]: %s\n", ret, strerror(ret));
2228 0 : goto done;
2229 : }
2230 :
2231 : /* remember the group for later processing */
2232 0 : state->nested_groups[state->num_groups] = entries[i]->attrs;
2233 0 : state->num_groups++;
2234 :
2235 : } else {
2236 : /* this should never happen, but if it does, do not loop forever */
2237 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2238 : "Entry does not match any known map, skipping\n");
2239 0 : continue;
2240 : }
2241 : }
2242 :
2243 : /* adjust size of nested groups array */
2244 0 : if (state->num_groups > 0) {
2245 0 : state->nested_groups = talloc_realloc(state, state->nested_groups,
2246 : struct sysdb_attrs *,
2247 : state->num_groups);
2248 0 : if (state->nested_groups == NULL) {
2249 0 : ret = ENOMEM;
2250 0 : goto done;
2251 : }
2252 : } else {
2253 0 : talloc_zfree(state->nested_groups);
2254 : }
2255 :
2256 0 : ret = EOK;
2257 :
2258 : done:
2259 0 : return ret;
2260 : }
2261 :
2262 0 : static void sdap_nested_group_deref_direct_done(struct tevent_req *subreq)
2263 : {
2264 0 : struct sdap_nested_group_deref_state *state = NULL;
2265 0 : struct tevent_req *req = NULL;
2266 : errno_t ret;
2267 :
2268 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
2269 0 : state = tevent_req_data(req, struct sdap_nested_group_deref_state);
2270 :
2271 : /* process direct members */
2272 0 : ret = sdap_nested_group_deref_direct_process(subreq);
2273 0 : talloc_zfree(subreq);
2274 0 : if (ret != EOK) {
2275 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error processing direct membership "
2276 : "[%d]: %s\n", ret, strerror(ret));
2277 0 : goto done;
2278 : }
2279 :
2280 : /* we have processed all direct members,
2281 : * now recurse and process nested groups */
2282 0 : subreq = sdap_nested_group_recurse_send(state, state->ev,
2283 : state->group_ctx,
2284 : state->nested_groups,
2285 : state->num_groups,
2286 0 : state->nesting_level + 1);
2287 0 : if (subreq == NULL) {
2288 0 : ret = ENOMEM;
2289 0 : goto done;
2290 : }
2291 :
2292 0 : tevent_req_set_callback(subreq, sdap_nested_group_deref_done, req);
2293 :
2294 0 : ret = EAGAIN;
2295 :
2296 : done:
2297 0 : if (ret == EOK) {
2298 : /* tevent_req_error() cannot cope with EOK */
2299 0 : DEBUG(SSSDBG_CRIT_FAILURE, "We should not get here with EOK\n");
2300 0 : tevent_req_error(req, EINVAL);
2301 0 : } else if (ret != EAGAIN) {
2302 0 : tevent_req_error(req, ret);
2303 : }
2304 :
2305 0 : return;
2306 :
2307 : }
2308 :
2309 0 : static void sdap_nested_group_deref_done(struct tevent_req *subreq)
2310 : {
2311 0 : struct tevent_req *req = NULL;
2312 : errno_t ret;
2313 :
2314 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
2315 :
2316 : /* process nested groups */
2317 0 : ret = sdap_nested_group_recurse_recv(subreq);
2318 0 : talloc_zfree(subreq);
2319 :
2320 0 : if (ret == EOK) {
2321 0 : tevent_req_done(req);
2322 : } else {
2323 0 : tevent_req_error(req, ret);
2324 : }
2325 :
2326 0 : return;
2327 : }
2328 :
2329 0 : static errno_t sdap_nested_group_deref_recv(struct tevent_req *req)
2330 : {
2331 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2332 :
2333 0 : return EOK;
2334 : }
|