Line data Source code
1 : /*
2 : SSSD
3 :
4 : Async LDAP Helper routines - initgroups operation
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
7 : Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
8 : Copyright (C) Jan Zeleny <jzeleny@redhat.com> - 2011
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "util/util.h"
25 : #include "db/sysdb.h"
26 : #include "providers/ldap/sdap_async_private.h"
27 : #include "providers/ldap/ldap_common.h"
28 : #include "providers/ldap/sdap_idmap.h"
29 : #include "providers/ldap/sdap_users.h"
30 :
31 : /* ==Save-fake-group-list=====================================*/
32 0 : errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
33 : struct sss_domain_info *domain,
34 : struct sdap_options *opts,
35 : char **groupnames,
36 : struct sysdb_attrs **ldap_groups,
37 : int ldap_groups_count)
38 : {
39 : TALLOC_CTX *tmp_ctx;
40 : struct ldb_message *msg;
41 : int i, mi, ai;
42 : const char *groupname;
43 : const char *original_dn;
44 0 : const char *uuid = NULL;
45 : char **missing;
46 : gid_t gid;
47 : int ret;
48 : errno_t sret;
49 0 : bool in_transaction = false;
50 : bool posix;
51 : time_t now;
52 0 : char *sid_str = NULL;
53 : bool use_id_mapping;
54 : bool need_filter;
55 : char *tmp_name;
56 :
57 : /* There are no groups in LDAP but we should add user to groups ?? */
58 0 : if (ldap_groups_count == 0) return EOK;
59 :
60 0 : tmp_ctx = talloc_new(NULL);
61 0 : if (!tmp_ctx) return ENOMEM;
62 :
63 0 : missing = talloc_array(tmp_ctx, char *, ldap_groups_count+1);
64 0 : if (!missing) {
65 0 : ret = ENOMEM;
66 0 : goto done;
67 : }
68 0 : mi = 0;
69 :
70 0 : for (i=0; groupnames[i]; i++) {
71 0 : tmp_name = sss_get_domain_name(tmp_ctx, groupnames[i], domain);
72 0 : if (tmp_name == NULL) {
73 0 : DEBUG(SSSDBG_OP_FAILURE,
74 : "Failed to format original name [%s]\n", groupnames[i]);
75 0 : ret = ENOMEM;
76 0 : goto done;
77 : }
78 :
79 0 : ret = sysdb_search_group_by_name(tmp_ctx, domain, tmp_name, NULL,
80 : &msg);
81 0 : if (ret == EOK) {
82 0 : continue;
83 0 : } else if (ret == ENOENT) {
84 0 : missing[mi] = talloc_steal(missing, tmp_name);
85 0 : DEBUG(SSSDBG_TRACE_LIBS, "Group #%d [%s][%s] is not cached, " \
86 : "need to add a fake entry\n",
87 : i, groupnames[i], missing[mi]);
88 0 : mi++;
89 0 : continue;
90 0 : } else if (ret != ENOENT) {
91 0 : DEBUG(SSSDBG_CRIT_FAILURE, "search for group failed [%d]: %s\n",
92 : ret, strerror(ret));
93 0 : goto done;
94 : }
95 : }
96 0 : missing[mi] = NULL;
97 :
98 : /* All groups are cached, nothing to do */
99 0 : if (mi == 0) {
100 0 : ret = EOK;
101 0 : goto done;
102 : }
103 :
104 0 : use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx,
105 0 : domain->name,
106 0 : domain->domain_id);
107 :
108 0 : ret = sysdb_transaction_start(sysdb);
109 0 : if (ret != EOK) {
110 0 : DEBUG(SSSDBG_CRIT_FAILURE,
111 : "Cannot start sysdb transaction [%d]: %s\n",
112 : ret, strerror(ret));
113 0 : goto done;
114 : }
115 0 : in_transaction = true;
116 :
117 :
118 0 : now = time(NULL);
119 0 : for (i=0; missing[i]; i++) {
120 : /* The group is not in sysdb, need to add a fake entry */
121 0 : for (ai=0; ai < ldap_groups_count; ai++) {
122 0 : ret = sdap_get_group_primary_name(tmp_ctx, opts, ldap_groups[ai],
123 : domain, &groupname);
124 0 : if (ret != EOK) {
125 0 : DEBUG(SSSDBG_CRIT_FAILURE,
126 : "The group has no name attribute\n");
127 0 : goto done;
128 : }
129 :
130 0 : if (strcmp(groupname, missing[i]) == 0) {
131 0 : posix = true;
132 :
133 0 : ret = sdap_attrs_get_sid_str(
134 0 : tmp_ctx, opts->idmap_ctx, ldap_groups[ai],
135 0 : opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name,
136 : &sid_str);
137 0 : if (ret != EOK && ret != ENOENT) goto done;
138 :
139 0 : if (use_id_mapping) {
140 0 : if (sid_str == NULL) {
141 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No SID for group [%s] " \
142 : "while id-mapping.\n",
143 : groupname);
144 0 : ret = EINVAL;
145 0 : goto done;
146 : }
147 :
148 0 : DEBUG(SSSDBG_TRACE_LIBS,
149 : "Mapping group [%s] objectSID to unix ID\n", groupname);
150 :
151 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
152 : "Group [%s] has objectSID [%s]\n",
153 : groupname, sid_str);
154 :
155 : /* Convert the SID into a UNIX group ID */
156 0 : ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str,
157 : &gid);
158 0 : if (ret == EOK) {
159 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
160 : "Group [%s] has mapped gid [%lu]\n",
161 : groupname, (unsigned long)gid);
162 : } else {
163 0 : posix = false;
164 0 : gid = 0;
165 :
166 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
167 : "Group [%s] cannot be mapped. "
168 : "Treating as a non-POSIX group\n",
169 : groupname);
170 : }
171 :
172 : } else {
173 0 : ret = sysdb_attrs_get_uint32_t(ldap_groups[ai],
174 : SYSDB_GIDNUM,
175 : &gid);
176 0 : if (ret == ENOENT || (ret == EOK && gid == 0)) {
177 0 : DEBUG(SSSDBG_TRACE_LIBS, "The group %s gid was %s\n",
178 : groupname, ret == ENOENT ? "missing" : "zero");
179 0 : DEBUG(SSSDBG_TRACE_FUNC,
180 : "Marking group %s as non-posix and setting GID=0!\n",
181 : groupname);
182 0 : gid = 0;
183 0 : posix = false;
184 0 : } else if (ret) {
185 0 : DEBUG(SSSDBG_CRIT_FAILURE,
186 : "The GID attribute is malformed\n");
187 0 : goto done;
188 : }
189 : }
190 :
191 0 : ret = sysdb_attrs_get_string(ldap_groups[ai],
192 : SYSDB_ORIG_DN,
193 : &original_dn);
194 0 : if (ret) {
195 0 : DEBUG(SSSDBG_FUNC_DATA,
196 : "The group has no original DN\n");
197 0 : original_dn = NULL;
198 : }
199 :
200 0 : ret = sysdb_handle_original_uuid(
201 0 : opts->group_map[SDAP_AT_GROUP_UUID].def_name,
202 0 : ldap_groups[ai],
203 0 : opts->group_map[SDAP_AT_GROUP_UUID].sys_name,
204 0 : ldap_groups[ai], "uniqueIDstr");
205 0 : if (ret != EOK) {
206 0 : DEBUG((ret == ENOENT) ? SSSDBG_TRACE_ALL : SSSDBG_MINOR_FAILURE,
207 : "Failed to retrieve UUID [%d][%s].\n",
208 : ret, sss_strerror(ret));
209 : }
210 :
211 0 : ret = sysdb_attrs_get_string(ldap_groups[ai],
212 : "uniqueIDstr",
213 : &uuid);
214 0 : if (ret) {
215 0 : DEBUG(SSSDBG_FUNC_DATA,
216 : "The group has no UUID\n");
217 0 : uuid = NULL;
218 : }
219 :
220 0 : ret = sdap_check_ad_group_type(domain, opts, ldap_groups[ai],
221 : groupname, &need_filter);
222 0 : if (ret != EOK) {
223 0 : goto done;
224 : }
225 :
226 0 : if (need_filter) {
227 0 : posix = false;
228 0 : gid = 0;
229 : }
230 :
231 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
232 : "Adding fake group %s to sysdb\n", groupname);
233 0 : ret = sysdb_add_incomplete_group(domain, groupname, gid,
234 : original_dn, sid_str,
235 : uuid, posix, now);
236 0 : if (ret != EOK) {
237 0 : goto done;
238 : }
239 0 : break;
240 : }
241 : }
242 :
243 0 : if (ai == ldap_groups_count) {
244 0 : DEBUG(SSSDBG_OP_FAILURE,
245 : "Group %s not present in LDAP\n", missing[i]);
246 0 : ret = EINVAL;
247 0 : goto done;
248 : }
249 : }
250 :
251 0 : ret = sysdb_transaction_commit(sysdb);
252 0 : if (ret != EOK) {
253 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_transaction_commit failed.\n");
254 0 : goto done;
255 : }
256 0 : in_transaction = false;
257 0 : ret = EOK;
258 :
259 : done:
260 0 : if (in_transaction) {
261 0 : sret = sysdb_transaction_cancel(sysdb);
262 0 : if (sret != EOK) {
263 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
264 : }
265 : }
266 0 : talloc_free(tmp_ctx);
267 0 : return ret;
268 : }
269 :
270 0 : int sdap_initgr_common_store(struct sysdb_ctx *sysdb,
271 : struct sss_domain_info *domain,
272 : struct sdap_options *opts,
273 : const char *name,
274 : enum sysdb_member_type type,
275 : char **sysdb_grouplist,
276 : struct sysdb_attrs **ldap_groups,
277 : int ldap_groups_count)
278 : {
279 : TALLOC_CTX *tmp_ctx;
280 0 : char **ldap_grouplist = NULL;
281 : char **add_groups;
282 : char **del_groups;
283 : int ret, tret;
284 0 : bool in_transaction = false;
285 :
286 0 : tmp_ctx = talloc_new(NULL);
287 0 : if (!tmp_ctx) return ENOMEM;
288 :
289 0 : if (ldap_groups_count == 0) {
290 : /* No groups for this user in LDAP.
291 : * We need to ensure that there are no groups
292 : * in the sysdb either.
293 : */
294 0 : ldap_grouplist = NULL;
295 : } else {
296 0 : ret = sysdb_attrs_primary_name_list(
297 : sysdb, tmp_ctx,
298 : ldap_groups, ldap_groups_count,
299 0 : opts->group_map[SDAP_AT_GROUP_NAME].name,
300 : &ldap_grouplist);
301 0 : if (ret != EOK) {
302 0 : DEBUG(SSSDBG_CRIT_FAILURE,
303 : "sysdb_attrs_primary_name_list failed [%d]: %s\n",
304 : ret, strerror(ret));
305 0 : goto done;
306 : }
307 : }
308 :
309 : /* Find the differences between the sysdb and LDAP lists
310 : * Groups in the sysdb only must be removed.
311 : */
312 0 : ret = diff_string_lists(tmp_ctx, ldap_grouplist, sysdb_grouplist,
313 : &add_groups, &del_groups, NULL);
314 0 : if (ret != EOK) goto done;
315 :
316 0 : ret = sysdb_transaction_start(sysdb);
317 0 : if (ret != EOK) {
318 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
319 0 : goto done;
320 : }
321 0 : in_transaction = true;
322 :
323 : /* Add fake entries for any groups the user should be added as
324 : * member of but that are not cached in sysdb
325 : */
326 0 : if (add_groups && add_groups[0]) {
327 0 : ret = sdap_add_incomplete_groups(sysdb, domain, opts,
328 : add_groups, ldap_groups,
329 : ldap_groups_count);
330 0 : if (ret != EOK) {
331 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Adding incomplete users failed\n");
332 0 : goto done;
333 : }
334 : }
335 :
336 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Updating memberships for %s\n", name);
337 0 : ret = sysdb_update_members(domain, name, type,
338 : (const char *const *) add_groups,
339 : (const char *const *) del_groups);
340 0 : if (ret != EOK) {
341 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Membership update failed [%d]: %s\n",
342 : ret, strerror(ret));
343 0 : goto done;
344 : }
345 :
346 0 : ret = sysdb_transaction_commit(sysdb);
347 0 : if (ret != EOK) {
348 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
349 0 : goto done;
350 : }
351 0 : in_transaction = false;
352 :
353 0 : ret = EOK;
354 : done:
355 0 : if (in_transaction) {
356 0 : tret = sysdb_transaction_cancel(sysdb);
357 0 : if (tret != EOK) {
358 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
359 : }
360 : }
361 0 : talloc_zfree(tmp_ctx);
362 0 : return ret;
363 : }
364 :
365 : /* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307===================== */
366 :
367 : struct sdap_initgr_rfc2307_state {
368 : struct tevent_context *ev;
369 : struct sysdb_ctx *sysdb;
370 : struct sss_domain_info *domain;
371 : struct sdap_options *opts;
372 : struct sdap_handle *sh;
373 : const char **attrs;
374 : const char *name;
375 : const char *base_filter;
376 : const char *orig_dn;
377 : char *filter;
378 : int timeout;
379 :
380 : struct sdap_op *op;
381 :
382 : struct sysdb_attrs **ldap_groups;
383 : size_t ldap_groups_count;
384 :
385 : size_t base_iter;
386 : struct sdap_search_base **search_bases;
387 : };
388 :
389 : static errno_t sdap_initgr_rfc2307_next_base(struct tevent_req *req);
390 : static void sdap_initgr_rfc2307_process(struct tevent_req *subreq);
391 0 : struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
392 : struct tevent_context *ev,
393 : struct sdap_options *opts,
394 : struct sysdb_ctx *sysdb,
395 : struct sss_domain_info *domain,
396 : struct sdap_handle *sh,
397 : const char *name)
398 : {
399 : struct tevent_req *req;
400 : struct sdap_initgr_rfc2307_state *state;
401 : const char **attr_filter;
402 : char *clean_name;
403 : errno_t ret;
404 : char *oc_list;
405 :
406 0 : req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
407 0 : if (!req) return NULL;
408 :
409 0 : state->ev = ev;
410 0 : state->opts = opts;
411 0 : state->sysdb = sysdb;
412 0 : state->domain = domain;
413 0 : state->sh = sh;
414 0 : state->op = NULL;
415 0 : state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
416 0 : state->ldap_groups = NULL;
417 0 : state->ldap_groups_count = 0;
418 0 : state->base_iter = 0;
419 0 : state->search_bases = opts->sdom->group_search_bases;
420 :
421 0 : if (!state->search_bases) {
422 0 : DEBUG(SSSDBG_CRIT_FAILURE,
423 : "Initgroups lookup request without a group search base\n");
424 0 : ret = EINVAL;
425 0 : goto done;
426 : }
427 :
428 0 : state->name = talloc_strdup(state, name);
429 0 : if (!state->name) {
430 0 : talloc_zfree(req);
431 0 : return NULL;
432 : }
433 :
434 0 : attr_filter = talloc_array(state, const char *, 2);
435 0 : if (!attr_filter) {
436 0 : talloc_free(req);
437 0 : return NULL;
438 : }
439 :
440 0 : attr_filter[0] = opts->group_map[SDAP_AT_GROUP_MEMBER].name;
441 0 : attr_filter[1] = NULL;
442 :
443 0 : ret = build_attrs_from_map(state, opts->group_map, SDAP_OPTS_GROUP,
444 0 : attr_filter, &state->attrs, NULL);
445 0 : if (ret != EOK) {
446 0 : talloc_free(req);
447 0 : return NULL;
448 : }
449 :
450 0 : ret = sss_filter_sanitize(state, name, &clean_name);
451 0 : if (ret != EOK) {
452 0 : talloc_free(req);
453 0 : return NULL;
454 : }
455 :
456 0 : oc_list = sdap_make_oc_list(state, opts->group_map);
457 0 : if (oc_list == NULL) {
458 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
459 0 : ret = ENOMEM;
460 0 : goto done;
461 : }
462 :
463 0 : state->base_filter = talloc_asprintf(state,
464 : "(&(%s=%s)(%s)(%s=*)(&(%s=*)(!(%s=0))))",
465 0 : opts->group_map[SDAP_AT_GROUP_MEMBER].name,
466 : clean_name, oc_list,
467 0 : opts->group_map[SDAP_AT_GROUP_NAME].name,
468 0 : opts->group_map[SDAP_AT_GROUP_GID].name,
469 0 : opts->group_map[SDAP_AT_GROUP_GID].name);
470 0 : if (!state->base_filter) {
471 0 : talloc_zfree(req);
472 0 : return NULL;
473 : }
474 0 : talloc_zfree(clean_name);
475 :
476 0 : ret = sdap_initgr_rfc2307_next_base(req);
477 :
478 : done:
479 0 : if (ret != EOK) {
480 0 : tevent_req_error(req, ret);
481 0 : tevent_req_post(req, ev);
482 : }
483 :
484 0 : return req;
485 : }
486 :
487 0 : static errno_t sdap_initgr_rfc2307_next_base(struct tevent_req *req)
488 : {
489 : struct tevent_req *subreq;
490 : struct sdap_initgr_rfc2307_state *state;
491 :
492 0 : state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
493 :
494 0 : talloc_zfree(state->filter);
495 :
496 0 : state->filter = sdap_get_id_specific_filter(
497 : state, state->base_filter,
498 0 : state->search_bases[state->base_iter]->filter);
499 0 : if (!state->filter) {
500 0 : return ENOMEM;
501 : }
502 :
503 0 : DEBUG(SSSDBG_TRACE_FUNC,
504 : "Searching for groups with base [%s]\n",
505 : state->search_bases[state->base_iter]->basedn);
506 :
507 0 : subreq = sdap_get_generic_send(
508 : state, state->ev, state->opts, state->sh,
509 0 : state->search_bases[state->base_iter]->basedn,
510 0 : state->search_bases[state->base_iter]->scope,
511 0 : state->filter, state->attrs,
512 0 : state->opts->group_map, SDAP_OPTS_GROUP,
513 : state->timeout,
514 : true);
515 0 : if (!subreq) {
516 0 : return ENOMEM;
517 : }
518 :
519 0 : tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);
520 :
521 0 : return EOK;
522 : }
523 :
524 0 : static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
525 : {
526 : struct tevent_req *req;
527 : struct sdap_initgr_rfc2307_state *state;
528 : struct sysdb_attrs **ldap_groups;
529 0 : char **sysdb_grouplist = NULL;
530 : size_t count;
531 : int ret;
532 : int i;
533 :
534 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
535 0 : state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
536 :
537 0 : ret = sdap_get_generic_recv(subreq, state, &count, &ldap_groups);
538 0 : talloc_zfree(subreq);
539 0 : if (ret) {
540 0 : tevent_req_error(req, ret);
541 0 : return;
542 : }
543 :
544 : /* Add this batch of groups to the list */
545 0 : if (count > 0) {
546 0 : state->ldap_groups =
547 0 : talloc_realloc(state,
548 : state->ldap_groups,
549 : struct sysdb_attrs *,
550 : state->ldap_groups_count + count + 1);
551 0 : if (!state->ldap_groups) {
552 0 : tevent_req_error(req, ENOMEM);
553 0 : return;
554 : }
555 :
556 : /* Copy the new groups into the list.
557 : */
558 0 : for (i = 0; i < count; i++) {
559 0 : state->ldap_groups[state->ldap_groups_count + i] =
560 0 : talloc_steal(state->ldap_groups, ldap_groups[i]);
561 : }
562 :
563 0 : state->ldap_groups_count += count;
564 :
565 0 : state->ldap_groups[state->ldap_groups_count] = NULL;
566 : }
567 :
568 0 : state->base_iter++;
569 :
570 : /* Check for additional search bases, and iterate
571 : * through again.
572 : */
573 0 : if (state->search_bases[state->base_iter] != NULL) {
574 0 : ret = sdap_initgr_rfc2307_next_base(req);
575 0 : if (ret != EOK) {
576 0 : tevent_req_error(req, ret);
577 : }
578 0 : return;
579 : }
580 :
581 : /* Search for all groups for which this user is a member */
582 0 : ret = get_sysdb_grouplist(state, state->sysdb, state->domain,
583 : state->name, &sysdb_grouplist);
584 0 : if (ret != EOK) {
585 0 : tevent_req_error(req, ret);
586 0 : return;
587 : }
588 :
589 : /* There are no nested groups here so we can just update the
590 : * memberships */
591 0 : ret = sdap_initgr_common_store(state->sysdb,
592 : state->domain,
593 : state->opts,
594 : state->name,
595 : SYSDB_MEMBER_USER,
596 : sysdb_grouplist,
597 : state->ldap_groups,
598 0 : state->ldap_groups_count);
599 0 : if (ret != EOK) {
600 0 : tevent_req_error(req, ret);
601 0 : return;
602 : }
603 :
604 0 : tevent_req_done(req);
605 : }
606 :
607 0 : static int sdap_initgr_rfc2307_recv(struct tevent_req *req)
608 : {
609 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
610 :
611 0 : return EOK;
612 : }
613 :
614 : /* ==Common code for pure RFC2307bis and IPA/AD========================= */
615 : static errno_t
616 0 : sdap_nested_groups_store(struct sysdb_ctx *sysdb,
617 : struct sss_domain_info *domain,
618 : struct sdap_options *opts,
619 : struct sysdb_attrs **groups,
620 : unsigned long count)
621 : {
622 : errno_t ret, tret;
623 : TALLOC_CTX *tmp_ctx;
624 0 : char **groupnamelist = NULL;
625 0 : bool in_transaction = false;
626 :
627 0 : tmp_ctx = talloc_new(NULL);
628 0 : if (!tmp_ctx) return ENOMEM;
629 :
630 0 : if (count > 0) {
631 0 : ret = sysdb_attrs_primary_name_list(sysdb, tmp_ctx,
632 : groups, count,
633 0 : opts->group_map[SDAP_AT_GROUP_NAME].name,
634 : &groupnamelist);
635 0 : if (ret != EOK) {
636 0 : DEBUG(SSSDBG_MINOR_FAILURE,
637 : "sysdb_attrs_primary_name_list failed [%d]: %s\n",
638 : ret, strerror(ret));
639 0 : goto done;
640 : }
641 : }
642 :
643 0 : ret = sysdb_transaction_start(sysdb);
644 0 : if (ret != EOK) {
645 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
646 0 : goto done;
647 : }
648 0 : in_transaction = true;
649 :
650 0 : ret = sdap_add_incomplete_groups(sysdb, domain, opts, groupnamelist,
651 : groups, count);
652 0 : if (ret != EOK) {
653 0 : DEBUG(SSSDBG_TRACE_FUNC, "Could not add incomplete groups [%d]: %s\n",
654 : ret, strerror(ret));
655 0 : goto done;
656 : }
657 :
658 0 : ret = sysdb_transaction_commit(sysdb);
659 0 : if (ret != EOK) {
660 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
661 0 : goto done;
662 : }
663 0 : in_transaction = false;
664 :
665 0 : ret = EOK;
666 : done:
667 0 : if (in_transaction) {
668 0 : tret = sysdb_transaction_cancel(sysdb);
669 0 : if (tret != EOK) {
670 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
671 : }
672 : }
673 :
674 0 : talloc_free(tmp_ctx);
675 0 : return ret;
676 : }
677 :
678 : struct membership_diff {
679 : struct membership_diff *prev;
680 : struct membership_diff *next;
681 :
682 : const char *name;
683 : char **add;
684 : char **del;
685 : };
686 :
687 : static errno_t
688 0 : build_membership_diff(TALLOC_CTX *mem_ctx, const char *name,
689 : char **ldap_parent_names, char **sysdb_parent_names,
690 : struct membership_diff **_mdiff)
691 : {
692 : TALLOC_CTX *tmp_ctx;
693 : struct membership_diff *mdiff;
694 : errno_t ret;
695 : char **add_groups;
696 : char **del_groups;
697 :
698 0 : tmp_ctx = talloc_new(NULL);
699 0 : if (!tmp_ctx) {
700 0 : ret = ENOMEM;
701 0 : goto done;
702 : }
703 :
704 0 : mdiff = talloc_zero(tmp_ctx, struct membership_diff);
705 0 : if (!mdiff) {
706 0 : ret = ENOMEM;
707 0 : goto done;
708 : }
709 0 : mdiff->name = talloc_strdup(mdiff, name);
710 0 : if (!mdiff->name) {
711 0 : ret = ENOMEM;
712 0 : goto done;
713 : }
714 :
715 : /* Find the differences between the sysdb and ldap lists
716 : * Groups in ldap only must be added to the sysdb;
717 : * groups in the sysdb only must be removed.
718 : */
719 0 : ret = diff_string_lists(tmp_ctx,
720 : ldap_parent_names, sysdb_parent_names,
721 : &add_groups, &del_groups, NULL);
722 0 : if (ret != EOK) {
723 0 : goto done;
724 : }
725 0 : mdiff->add = talloc_steal(mdiff, add_groups);
726 0 : mdiff->del = talloc_steal(mdiff, del_groups);
727 :
728 0 : ret = EOK;
729 0 : *_mdiff = talloc_steal(mem_ctx, mdiff);
730 : done:
731 0 : talloc_free(tmp_ctx);
732 0 : return ret;
733 : }
734 :
735 : /* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */
736 :
737 : struct sdap_initgr_nested_state {
738 : struct tevent_context *ev;
739 : struct sysdb_ctx *sysdb;
740 : struct sdap_options *opts;
741 : struct sss_domain_info *dom;
742 : struct sdap_handle *sh;
743 :
744 : struct sysdb_attrs *user;
745 : const char *username;
746 : const char *orig_dn;
747 :
748 : const char **grp_attrs;
749 :
750 : struct ldb_message_element *memberof;
751 : char *filter;
752 : char **group_dns;
753 : int cur;
754 :
755 : struct sdap_op *op;
756 :
757 : struct sysdb_attrs **groups;
758 : int groups_cur;
759 : };
760 :
761 : static errno_t sdap_initgr_nested_deref_search(struct tevent_req *req);
762 : static errno_t sdap_initgr_nested_noderef_search(struct tevent_req *req);
763 : static void sdap_initgr_nested_search(struct tevent_req *subreq);
764 : static void sdap_initgr_nested_store(struct tevent_req *req);
765 0 : static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
766 : struct tevent_context *ev,
767 : struct sdap_options *opts,
768 : struct sysdb_ctx *sysdb,
769 : struct sss_domain_info *dom,
770 : struct sdap_handle *sh,
771 : struct sysdb_attrs *user,
772 : const char **grp_attrs)
773 : {
774 : struct tevent_req *req;
775 : struct sdap_initgr_nested_state *state;
776 : errno_t ret;
777 : int deref_threshold;
778 :
779 0 : req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);
780 0 : if (!req) return NULL;
781 :
782 0 : state->ev = ev;
783 0 : state->opts = opts;
784 0 : state->sysdb = sysdb;
785 0 : state->dom = dom;
786 0 : state->sh = sh;
787 0 : state->grp_attrs = grp_attrs;
788 0 : state->user = user;
789 0 : state->op = NULL;
790 :
791 0 : ret = sdap_get_user_primary_name(memctx, opts, user, dom, &state->username);
792 0 : if (ret != EOK) {
793 0 : DEBUG(SSSDBG_CRIT_FAILURE, "User entry had no username\n");
794 0 : goto immediate;
795 : }
796 :
797 0 : ret = sysdb_attrs_get_el(state->user, SYSDB_MEMBEROF, &state->memberof);
798 0 : if (ret || !state->memberof || state->memberof->num_values == 0) {
799 0 : DEBUG(SSSDBG_CONF_SETTINGS, "User entry lacks original memberof ?\n");
800 : /* We can't find any groups for this user, so we'll
801 : * have to assume there aren't any. Just return
802 : * success here.
803 : */
804 0 : ret = EOK;
805 0 : goto immediate;
806 : }
807 :
808 0 : state->groups = talloc_zero_array(state, struct sysdb_attrs *,
809 : state->memberof->num_values + 1);;
810 0 : if (!state->groups) {
811 0 : ret = ENOMEM;
812 0 : goto immediate;
813 : }
814 0 : state->groups_cur = 0;
815 :
816 0 : deref_threshold = dp_opt_get_int(state->opts->basic,
817 : SDAP_DEREF_THRESHOLD);
818 0 : if (sdap_has_deref_support(state->sh, state->opts) &&
819 0 : deref_threshold < state->memberof->num_values) {
820 0 : ret = sysdb_attrs_get_string(user, SYSDB_ORIG_DN,
821 0 : &state->orig_dn);
822 0 : if (ret != EOK) goto immediate;
823 :
824 0 : ret = sdap_initgr_nested_deref_search(req);
825 0 : if (ret != EAGAIN) goto immediate;
826 : } else {
827 0 : ret = sdap_initgr_nested_noderef_search(req);
828 0 : if (ret != EAGAIN) goto immediate;
829 : }
830 :
831 0 : return req;
832 :
833 : immediate:
834 0 : if (ret == EOK) {
835 0 : tevent_req_done(req);
836 : } else {
837 0 : tevent_req_error(req, ret);
838 : }
839 0 : tevent_req_post(req, ev);
840 0 : return req;
841 : }
842 :
843 0 : static errno_t sdap_initgr_nested_noderef_search(struct tevent_req *req)
844 : {
845 : int i;
846 : struct tevent_req *subreq;
847 : struct sdap_initgr_nested_state *state;
848 : char *oc_list;
849 :
850 0 : state = tevent_req_data(req, struct sdap_initgr_nested_state);
851 :
852 0 : state->group_dns = talloc_array(state, char *,
853 : state->memberof->num_values + 1);
854 0 : if (!state->group_dns) {
855 0 : return ENOMEM;
856 : }
857 0 : for (i = 0; i < state->memberof->num_values; i++) {
858 0 : state->group_dns[i] = talloc_strdup(state->group_dns,
859 0 : (char *)state->memberof->values[i].data);
860 0 : if (!state->group_dns[i]) {
861 0 : return ENOMEM;
862 : }
863 : }
864 0 : state->group_dns[i] = NULL; /* terminate */
865 0 : state->cur = 0;
866 :
867 0 : oc_list = sdap_make_oc_list(state, state->opts->group_map);
868 0 : if (oc_list == NULL) {
869 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
870 0 : return ENOMEM;
871 : }
872 :
873 0 : state->filter = talloc_asprintf(state, "(&(%s)(%s=*))", oc_list,
874 0 : state->opts->group_map[SDAP_AT_GROUP_NAME].name);
875 0 : if (!state->filter) {
876 0 : return ENOMEM;
877 : }
878 :
879 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
880 0 : state->group_dns[state->cur],
881 : LDAP_SCOPE_BASE,
882 0 : state->filter, state->grp_attrs,
883 0 : state->opts->group_map, SDAP_OPTS_GROUP,
884 0 : dp_opt_get_int(state->opts->basic,
885 : SDAP_SEARCH_TIMEOUT),
886 : false);
887 0 : if (!subreq) {
888 0 : return ENOMEM;
889 : }
890 0 : tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
891 :
892 0 : return EAGAIN;
893 : }
894 :
895 : static void sdap_initgr_nested_deref_done(struct tevent_req *subreq);
896 :
897 0 : static errno_t sdap_initgr_nested_deref_search(struct tevent_req *req)
898 : {
899 : struct tevent_req *subreq;
900 : struct sdap_attr_map_info *maps;
901 0 : const int num_maps = 1;
902 : const char **sdap_attrs;
903 : errno_t ret;
904 : int timeout;
905 : struct sdap_initgr_nested_state *state;
906 :
907 0 : state = tevent_req_data(req, struct sdap_initgr_nested_state);
908 :
909 0 : maps = talloc_array(state, struct sdap_attr_map_info, num_maps+1);
910 0 : if (!maps) return ENOMEM;
911 :
912 0 : maps[0].map = state->opts->group_map;
913 0 : maps[0].num_attrs = SDAP_OPTS_GROUP;
914 0 : maps[1].map = NULL;
915 :
916 0 : ret = build_attrs_from_map(state, state->opts->group_map, SDAP_OPTS_GROUP,
917 : NULL, &sdap_attrs, NULL);
918 0 : if (ret != EOK) goto fail;
919 :
920 0 : timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
921 :
922 0 : subreq = sdap_deref_search_send(state, state->ev, state->opts,
923 : state->sh, state->orig_dn,
924 0 : state->opts->user_map[SDAP_AT_USER_MEMBEROF].name,
925 : sdap_attrs, num_maps, maps, timeout);
926 0 : if (!subreq) {
927 0 : ret = EIO;
928 0 : goto fail;
929 : }
930 0 : talloc_steal(subreq, sdap_attrs);
931 0 : talloc_steal(subreq, maps);
932 :
933 0 : tevent_req_set_callback(subreq, sdap_initgr_nested_deref_done, req);
934 0 : return EAGAIN;
935 :
936 : fail:
937 0 : talloc_free(sdap_attrs);
938 0 : talloc_free(maps);
939 0 : return ret;
940 : }
941 :
942 0 : static void sdap_initgr_nested_deref_done(struct tevent_req *subreq)
943 : {
944 : errno_t ret;
945 : struct tevent_req *req;
946 : struct sdap_initgr_nested_state *state;
947 : size_t num_results;
948 : size_t i;
949 : struct sdap_deref_attrs **deref_result;
950 :
951 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
952 0 : state = tevent_req_data(req, struct sdap_initgr_nested_state);
953 :
954 0 : ret = sdap_deref_search_recv(subreq, state,
955 : &num_results,
956 : &deref_result);
957 0 : talloc_zfree(subreq);
958 0 : if (ret == ENOTSUP) {
959 0 : ret = sdap_initgr_nested_noderef_search(req);
960 0 : if (ret != EAGAIN) {
961 0 : if (ret == EOK) {
962 0 : tevent_req_done(req);
963 : } else {
964 0 : tevent_req_error(req, ret);
965 : }
966 : }
967 0 : return;
968 0 : } else if (ret != EOK && ret != ENOENT) {
969 0 : tevent_req_error(req, ret);
970 0 : return;
971 0 : } else if (ret == ENOENT || deref_result == NULL) {
972 : /* Nothing could be dereferenced. Done. */
973 0 : tevent_req_done(req);
974 0 : return;
975 : }
976 :
977 0 : for (i=0; i < num_results; i++) {
978 0 : state->groups[i] = talloc_steal(state->groups,
979 : deref_result[i]->attrs);
980 : }
981 :
982 0 : state->groups_cur = num_results;
983 0 : sdap_initgr_nested_store(req);
984 : }
985 :
986 0 : static void sdap_initgr_nested_search(struct tevent_req *subreq)
987 : {
988 : struct tevent_req *req;
989 : struct sdap_initgr_nested_state *state;
990 : struct sysdb_attrs **groups;
991 : size_t count;
992 : int ret;
993 :
994 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
995 0 : state = tevent_req_data(req, struct sdap_initgr_nested_state);
996 :
997 0 : ret = sdap_get_generic_recv(subreq, state, &count, &groups);
998 0 : talloc_zfree(subreq);
999 0 : if (ret) {
1000 0 : tevent_req_error(req, ret);
1001 0 : return;
1002 : }
1003 :
1004 0 : if (count == 1) {
1005 0 : state->groups[state->groups_cur] = talloc_steal(state->groups,
1006 : groups[0]);
1007 0 : state->groups_cur++;
1008 : } else {
1009 0 : DEBUG(SSSDBG_OP_FAILURE,
1010 : "Search for group %s, returned %zu results. Skipping\n",
1011 : state->group_dns[state->cur], count);
1012 : }
1013 :
1014 0 : state->cur++;
1015 : /* note that state->memberof->num_values is the count of original
1016 : * memberOf which might not be only groups, but permissions, etc.
1017 : * Use state->groups_cur for group index cap */
1018 0 : if (state->cur < state->memberof->num_values) {
1019 0 : subreq = sdap_get_generic_send(state, state->ev,
1020 : state->opts, state->sh,
1021 0 : state->group_dns[state->cur],
1022 : LDAP_SCOPE_BASE,
1023 0 : state->filter, state->grp_attrs,
1024 0 : state->opts->group_map,
1025 : SDAP_OPTS_GROUP,
1026 0 : dp_opt_get_int(state->opts->basic,
1027 : SDAP_SEARCH_TIMEOUT),
1028 : false);
1029 0 : if (!subreq) {
1030 0 : tevent_req_error(req, ENOMEM);
1031 0 : return;
1032 : }
1033 0 : tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
1034 : } else {
1035 0 : sdap_initgr_nested_store(req);
1036 : }
1037 : }
1038 :
1039 : static errno_t
1040 : sdap_initgr_store_groups(struct sdap_initgr_nested_state *state);
1041 : static errno_t
1042 : sdap_initgr_store_group_memberships(struct sdap_initgr_nested_state *state);
1043 : static errno_t
1044 : sdap_initgr_store_user_memberships(struct sdap_initgr_nested_state *state);
1045 :
1046 0 : static void sdap_initgr_nested_store(struct tevent_req *req)
1047 : {
1048 : errno_t ret;
1049 : struct sdap_initgr_nested_state *state;
1050 0 : bool in_transaction = false;
1051 : errno_t tret;
1052 :
1053 0 : state = tevent_req_data(req, struct sdap_initgr_nested_state);
1054 :
1055 0 : ret = sysdb_transaction_start(state->sysdb);
1056 0 : if (ret != EOK) {
1057 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1058 0 : goto fail;
1059 : }
1060 0 : in_transaction = true;
1061 :
1062 : /* save the groups if they are not already */
1063 0 : ret = sdap_initgr_store_groups(state);
1064 0 : if (ret != EOK) {
1065 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not save groups [%d]: %s\n",
1066 : ret, strerror(ret));
1067 0 : goto fail;
1068 : }
1069 :
1070 : /* save the group memberships */
1071 0 : ret = sdap_initgr_store_group_memberships(state);
1072 0 : if (ret != EOK) {
1073 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1074 : "Could not save group memberships [%d]: %s\n",
1075 : ret, strerror(ret));
1076 0 : goto fail;
1077 : }
1078 :
1079 : /* save the user memberships */
1080 0 : ret = sdap_initgr_store_user_memberships(state);
1081 0 : if (ret != EOK) {
1082 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1083 : "Could not save user memberships [%d]: %s\n",
1084 : ret, strerror(ret));
1085 0 : goto fail;
1086 : }
1087 :
1088 0 : ret = sysdb_transaction_commit(state->sysdb);
1089 0 : if (ret != EOK) {
1090 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
1091 0 : goto fail;
1092 : }
1093 0 : in_transaction = false;
1094 :
1095 0 : tevent_req_done(req);
1096 0 : return;
1097 :
1098 : fail:
1099 0 : if (in_transaction) {
1100 0 : tret = sysdb_transaction_cancel(state->sysdb);
1101 0 : if (tret != EOK) {
1102 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
1103 : }
1104 : }
1105 0 : tevent_req_error(req, ret);
1106 0 : return;
1107 : }
1108 :
1109 : static errno_t
1110 0 : sdap_initgr_store_groups(struct sdap_initgr_nested_state *state)
1111 : {
1112 0 : return sdap_nested_groups_store(state->sysdb, state->dom,
1113 : state->opts, state->groups,
1114 0 : state->groups_cur);
1115 : }
1116 :
1117 : static errno_t
1118 : sdap_initgr_nested_get_membership_diff(TALLOC_CTX *mem_ctx,
1119 : struct sysdb_ctx *sysdb,
1120 : struct sdap_options *opts,
1121 : struct sss_domain_info *dom,
1122 : struct sysdb_attrs *group,
1123 : struct sysdb_attrs **all_groups,
1124 : int groups_count,
1125 : struct membership_diff **mdiff);
1126 :
1127 : static int sdap_initgr_nested_get_direct_parents(TALLOC_CTX *mem_ctx,
1128 : struct sysdb_attrs *attrs,
1129 : struct sysdb_attrs **groups,
1130 : int ngroups,
1131 : struct sysdb_attrs ***_direct_parents,
1132 : int *_ndirect);
1133 :
1134 : static errno_t
1135 0 : sdap_initgr_store_group_memberships(struct sdap_initgr_nested_state *state)
1136 : {
1137 : errno_t ret;
1138 : int i, tret;
1139 : TALLOC_CTX *tmp_ctx;
1140 0 : struct membership_diff *miter = NULL;
1141 0 : struct membership_diff *memberships = NULL;
1142 0 : bool in_transaction = false;
1143 :
1144 0 : tmp_ctx = talloc_new(NULL);
1145 0 : if (!tmp_ctx) return ENOMEM;
1146 :
1147 : /* Compute the diffs first in order to keep the transaction as small
1148 : * as possible
1149 : */
1150 0 : for (i=0; i < state->groups_cur; i++) {
1151 0 : ret = sdap_initgr_nested_get_membership_diff(tmp_ctx, state->sysdb,
1152 : state->opts, state->dom,
1153 0 : state->groups[i],
1154 : state->groups,
1155 : state->groups_cur,
1156 : &miter);
1157 0 : if (ret) {
1158 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1159 : "Could not compute memberships for group %d [%d]: %s\n",
1160 : i, ret, strerror(ret));
1161 0 : goto done;
1162 : }
1163 :
1164 0 : DLIST_ADD(memberships, miter);
1165 : }
1166 :
1167 0 : ret = sysdb_transaction_start(state->sysdb);
1168 0 : if (ret != EOK) {
1169 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1170 0 : goto done;
1171 : }
1172 0 : in_transaction = true;
1173 :
1174 0 : DLIST_FOR_EACH(miter, memberships) {
1175 0 : ret = sysdb_update_members(state->dom, miter->name,
1176 : SYSDB_MEMBER_GROUP,
1177 0 : (const char *const *) miter->add,
1178 0 : (const char *const *) miter->del);
1179 0 : if (ret != EOK) {
1180 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Failed to update memberships\n");
1181 0 : goto done;
1182 : }
1183 : }
1184 :
1185 0 : ret = sysdb_transaction_commit(state->sysdb);
1186 0 : if (ret != EOK) {
1187 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
1188 0 : goto done;
1189 : }
1190 0 : in_transaction = false;
1191 :
1192 0 : ret = EOK;
1193 : done:
1194 0 : if (in_transaction) {
1195 0 : tret = sysdb_transaction_cancel(state->sysdb);
1196 0 : if (tret != EOK) {
1197 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
1198 : }
1199 : }
1200 0 : talloc_free(tmp_ctx);
1201 0 : return ret;
1202 : }
1203 :
1204 : static errno_t
1205 0 : sdap_initgr_store_user_memberships(struct sdap_initgr_nested_state *state)
1206 : {
1207 : errno_t ret;
1208 : int tret;
1209 : const char *orig_dn;
1210 :
1211 0 : char **sysdb_parent_name_list = NULL;
1212 0 : char **ldap_parent_name_list = NULL;
1213 :
1214 : int nparents;
1215 : struct sysdb_attrs **ldap_parentlist;
1216 : struct ldb_message_element *el;
1217 : int i, mi;
1218 : char **add_groups;
1219 : char **del_groups;
1220 : TALLOC_CTX *tmp_ctx;
1221 0 : bool in_transaction = false;
1222 :
1223 0 : tmp_ctx = talloc_new(NULL);
1224 0 : if (!tmp_ctx) {
1225 0 : ret = ENOMEM;
1226 0 : goto done;
1227 : }
1228 :
1229 : /* Get direct LDAP parents */
1230 0 : ret = sysdb_attrs_get_string(state->user, SYSDB_ORIG_DN, &orig_dn);
1231 0 : if (ret != EOK) {
1232 0 : DEBUG(SSSDBG_OP_FAILURE, "The user has no original DN\n");
1233 0 : goto done;
1234 : }
1235 :
1236 0 : ldap_parentlist = talloc_zero_array(tmp_ctx, struct sysdb_attrs *,
1237 : state->groups_cur + 1);
1238 0 : if (!ldap_parentlist) {
1239 0 : ret = ENOMEM;
1240 0 : goto done;
1241 : }
1242 0 : nparents = 0;
1243 :
1244 0 : for (i=0; i < state->groups_cur ; i++) {
1245 0 : ret = sysdb_attrs_get_el(state->groups[i], SYSDB_MEMBER, &el);
1246 0 : if (ret) {
1247 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1248 : "A group with no members during initgroups?\n");
1249 0 : goto done;
1250 : }
1251 :
1252 0 : for (mi = 0; mi < el->num_values; mi++) {
1253 0 : if (strcasecmp((const char *) el->values[mi].data, orig_dn) != 0) {
1254 0 : continue;
1255 : }
1256 :
1257 0 : ldap_parentlist[nparents] = state->groups[i];
1258 0 : nparents++;
1259 : }
1260 : }
1261 :
1262 0 : DEBUG(SSSDBG_TRACE_LIBS,
1263 : "The user %s is a direct member of %d LDAP groups\n",
1264 : state->username, nparents);
1265 :
1266 0 : if (nparents == 0) {
1267 0 : ldap_parent_name_list = NULL;
1268 : } else {
1269 0 : ret = sysdb_attrs_primary_name_list(state->sysdb, tmp_ctx,
1270 : ldap_parentlist,
1271 : nparents,
1272 0 : state->opts->group_map[SDAP_AT_GROUP_NAME].name,
1273 : &ldap_parent_name_list);
1274 0 : if (ret != EOK) {
1275 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1276 : "sysdb_attrs_primary_name_list failed [%d]: %s\n",
1277 : ret, strerror(ret));
1278 0 : goto done;
1279 : }
1280 : }
1281 :
1282 0 : ret = sysdb_get_direct_parents(tmp_ctx, state->dom, SYSDB_MEMBER_USER,
1283 : state->username, &sysdb_parent_name_list);
1284 0 : if (ret) {
1285 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1286 : "Could not get direct sysdb parents for %s: %d [%s]\n",
1287 : state->username, ret, strerror(ret));
1288 0 : goto done;
1289 : }
1290 :
1291 0 : ret = diff_string_lists(tmp_ctx,
1292 : ldap_parent_name_list, sysdb_parent_name_list,
1293 : &add_groups, &del_groups, NULL);
1294 0 : if (ret != EOK) {
1295 0 : goto done;
1296 : }
1297 :
1298 0 : ret = sysdb_transaction_start(state->sysdb);
1299 0 : if (ret != EOK) {
1300 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1301 0 : goto done;
1302 : }
1303 0 : in_transaction = true;
1304 :
1305 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1306 : "Updating memberships for %s\n", state->username);
1307 0 : ret = sysdb_update_members(state->dom, state->username, SYSDB_MEMBER_USER,
1308 : (const char *const *) add_groups,
1309 : (const char *const *) del_groups);
1310 0 : if (ret != EOK) {
1311 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1312 : "Could not update sysdb memberships for %s: %d [%s]\n",
1313 : state->username, ret, strerror(ret));
1314 0 : goto done;
1315 : }
1316 :
1317 0 : ret = sysdb_transaction_commit(state->sysdb);
1318 0 : if (ret != EOK) {
1319 0 : goto done;
1320 : }
1321 0 : in_transaction = false;
1322 :
1323 0 : ret = EOK;
1324 : done:
1325 0 : if (in_transaction) {
1326 0 : tret = sysdb_transaction_cancel(state->sysdb);
1327 0 : if (tret != EOK) {
1328 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
1329 : }
1330 : }
1331 0 : talloc_zfree(tmp_ctx);
1332 0 : return ret;
1333 : }
1334 :
1335 : static errno_t
1336 0 : sdap_initgr_nested_get_membership_diff(TALLOC_CTX *mem_ctx,
1337 : struct sysdb_ctx *sysdb,
1338 : struct sdap_options *opts,
1339 : struct sss_domain_info *dom,
1340 : struct sysdb_attrs *group,
1341 : struct sysdb_attrs **all_groups,
1342 : int groups_count,
1343 : struct membership_diff **_mdiff)
1344 : {
1345 : errno_t ret;
1346 : struct membership_diff *mdiff;
1347 : const char *group_name;
1348 :
1349 : struct sysdb_attrs **ldap_parentlist;
1350 : int parents_count;
1351 :
1352 0 : char **ldap_parent_names_list = NULL;
1353 0 : char **sysdb_parents_names_list = NULL;
1354 :
1355 : TALLOC_CTX *tmp_ctx;
1356 :
1357 0 : tmp_ctx = talloc_new(NULL);
1358 0 : if (!tmp_ctx) {
1359 0 : ret = ENOMEM;
1360 0 : goto done;
1361 : }
1362 :
1363 : /* Get direct sysdb parents */
1364 0 : ret = sdap_get_group_primary_name(tmp_ctx, opts, group, dom, &group_name);
1365 0 : if (ret != EOK) {
1366 0 : goto done;
1367 : }
1368 :
1369 0 : ret = sysdb_get_direct_parents(tmp_ctx, dom, SYSDB_MEMBER_GROUP,
1370 : group_name, &sysdb_parents_names_list);
1371 0 : if (ret) {
1372 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1373 : "Could not get direct sysdb parents for %s: %d [%s]\n",
1374 : group_name, ret, strerror(ret));
1375 0 : goto done;
1376 : }
1377 :
1378 : /* For each group, filter only parents from full set */
1379 0 : ret = sdap_initgr_nested_get_direct_parents(tmp_ctx,
1380 : group,
1381 : all_groups,
1382 : groups_count,
1383 : &ldap_parentlist,
1384 : &parents_count);
1385 0 : if (ret != EOK) {
1386 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get parent groups for %s [%d]: %s\n",
1387 : group_name, ret, strerror(ret));
1388 0 : goto done;
1389 : }
1390 0 : DEBUG(SSSDBG_TRACE_LIBS,
1391 : "The group %s is a direct member of %d LDAP groups\n",
1392 : group_name, parents_count);
1393 :
1394 0 : if (parents_count > 0) {
1395 0 : ret = sysdb_attrs_primary_name_list(sysdb, tmp_ctx,
1396 : ldap_parentlist,
1397 : parents_count,
1398 0 : opts->group_map[SDAP_AT_GROUP_NAME].name,
1399 : &ldap_parent_names_list);
1400 0 : if (ret != EOK) {
1401 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1402 : "sysdb_attrs_primary_name_list failed [%d]: %s\n",
1403 : ret, strerror(ret));
1404 0 : goto done;
1405 : }
1406 : }
1407 :
1408 0 : ret = build_membership_diff(tmp_ctx, group_name, ldap_parent_names_list,
1409 : sysdb_parents_names_list, &mdiff);
1410 0 : if (ret != EOK) {
1411 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1412 : "Could not build membership diff for %s [%d]: %s\n",
1413 : group_name, ret, strerror(ret));
1414 0 : goto done;
1415 : }
1416 :
1417 0 : ret = EOK;
1418 0 : *_mdiff = talloc_steal(mem_ctx, mdiff);
1419 : done:
1420 0 : talloc_free(tmp_ctx);
1421 0 : return ret;
1422 : }
1423 :
1424 0 : static int sdap_initgr_nested_get_direct_parents(TALLOC_CTX *mem_ctx,
1425 : struct sysdb_attrs *attrs,
1426 : struct sysdb_attrs **groups,
1427 : int ngroups,
1428 : struct sysdb_attrs ***_direct_parents,
1429 : int *_ndirect)
1430 : {
1431 : TALLOC_CTX *tmp_ctx;
1432 : struct ldb_message_element *member;
1433 : int i, mi;
1434 : int ret;
1435 : const char *orig_dn;
1436 :
1437 : int ndirect;
1438 : struct sysdb_attrs **direct_groups;
1439 :
1440 0 : tmp_ctx = talloc_new(NULL);
1441 0 : if (!tmp_ctx) return ENOMEM;
1442 :
1443 0 : direct_groups = talloc_zero_array(tmp_ctx, struct sysdb_attrs *,
1444 : ngroups + 1);
1445 0 : if (!direct_groups) {
1446 0 : ret = ENOMEM;
1447 0 : goto done;
1448 : }
1449 0 : ndirect = 0;
1450 :
1451 0 : ret = sysdb_attrs_get_string(attrs, SYSDB_ORIG_DN, &orig_dn);
1452 0 : if (ret != EOK) {
1453 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Missing originalDN\n");
1454 0 : goto done;
1455 : }
1456 0 : DEBUG(SSSDBG_TRACE_ALL,
1457 : "Looking up direct parents for group [%s]\n", orig_dn);
1458 :
1459 : /* FIXME - Filter only parents from full set to avoid searching
1460 : * through all members of huge groups. That requires asking for memberOf
1461 : * with the group LDAP search
1462 : */
1463 :
1464 : /* Filter only direct parents from the list of all groups */
1465 0 : for (i=0; i < ngroups; i++) {
1466 0 : ret = sysdb_attrs_get_el(groups[i], SYSDB_MEMBER, &member);
1467 0 : if (ret) {
1468 0 : DEBUG(SSSDBG_TRACE_LIBS,
1469 : "A group with no members during initgroups?\n");
1470 0 : continue;
1471 : }
1472 :
1473 0 : for (mi = 0; mi < member->num_values; mi++) {
1474 0 : if (strcasecmp((const char *) member->values[mi].data, orig_dn) != 0) {
1475 0 : continue;
1476 : }
1477 :
1478 0 : direct_groups[ndirect] = groups[i];
1479 0 : ndirect++;
1480 : }
1481 : }
1482 0 : direct_groups[ndirect] = NULL;
1483 :
1484 0 : DEBUG(SSSDBG_TRACE_ALL,
1485 : "The group [%s] has %d direct parents\n", orig_dn, ndirect);
1486 :
1487 0 : *_direct_parents = talloc_steal(mem_ctx, direct_groups);
1488 0 : *_ndirect = ndirect;
1489 0 : ret = EOK;
1490 : done:
1491 0 : talloc_zfree(tmp_ctx);
1492 0 : return ret;
1493 : }
1494 :
1495 0 : static int sdap_initgr_nested_recv(struct tevent_req *req)
1496 : {
1497 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1498 :
1499 0 : return EOK;
1500 : }
1501 :
1502 : /* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-BIS================= */
1503 : struct sdap_initgr_rfc2307bis_state {
1504 : struct tevent_context *ev;
1505 : struct sysdb_ctx *sysdb;
1506 : struct sdap_options *opts;
1507 : struct sss_domain_info *dom;
1508 : struct sdap_handle *sh;
1509 : const char *name;
1510 : char *base_filter;
1511 : char *filter;
1512 : const char **attrs;
1513 : const char *orig_dn;
1514 :
1515 : int timeout;
1516 :
1517 : size_t base_iter;
1518 : struct sdap_search_base **search_bases;
1519 :
1520 : struct sdap_op *op;
1521 :
1522 : hash_table_t *group_hash;
1523 : size_t num_direct_parents;
1524 : struct sysdb_attrs **direct_groups;
1525 : };
1526 :
1527 : struct sdap_nested_group {
1528 : struct sysdb_attrs *group;
1529 : struct sysdb_attrs **ldap_parents;
1530 : size_t parents_count;
1531 : };
1532 :
1533 : static errno_t sdap_initgr_rfc2307bis_next_base(struct tevent_req *req);
1534 : static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq);
1535 : static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq);
1536 : errno_t save_rfc2307bis_user_memberships(
1537 : struct sdap_initgr_rfc2307bis_state *state);
1538 : struct tevent_req *rfc2307bis_nested_groups_send(
1539 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1540 : struct sdap_options *opts, struct sysdb_ctx *sysdb,
1541 : struct sss_domain_info *dom, struct sdap_handle *sh,
1542 : struct sdap_search_base **search_bases,
1543 : struct sysdb_attrs **groups, size_t num_groups,
1544 : hash_table_t *group_hash, size_t nesting);
1545 : static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req);
1546 :
1547 0 : static struct tevent_req *sdap_initgr_rfc2307bis_send(
1548 : TALLOC_CTX *memctx,
1549 : struct tevent_context *ev,
1550 : struct sdap_options *opts,
1551 : struct sdap_domain *sdom,
1552 : struct sdap_handle *sh,
1553 : const char *name,
1554 : const char *orig_dn)
1555 : {
1556 : errno_t ret;
1557 : struct tevent_req *req;
1558 : struct sdap_initgr_rfc2307bis_state *state;
1559 : const char **attr_filter;
1560 : char *clean_orig_dn;
1561 : bool use_id_mapping;
1562 : char *oc_list;
1563 :
1564 0 : req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307bis_state);
1565 0 : if (!req) return NULL;
1566 :
1567 0 : state->ev = ev;
1568 0 : state->opts = opts;
1569 0 : state->sysdb = sdom->dom->sysdb;
1570 0 : state->dom = sdom->dom;
1571 0 : state->sh = sh;
1572 0 : state->op = NULL;
1573 0 : state->name = name;
1574 0 : state->direct_groups = NULL;
1575 0 : state->num_direct_parents = 0;
1576 0 : state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
1577 0 : state->base_iter = 0;
1578 0 : state->search_bases = sdom->group_search_bases;
1579 0 : state->orig_dn = orig_dn;
1580 :
1581 0 : if (!state->search_bases) {
1582 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1583 : "Initgroups lookup request without a group search base\n");
1584 0 : ret = EINVAL;
1585 0 : goto done;
1586 : }
1587 :
1588 0 : ret = sss_hash_create(state, 32, &state->group_hash);
1589 0 : if (ret != EOK) {
1590 0 : talloc_free(req);
1591 0 : return NULL;
1592 : }
1593 :
1594 0 : attr_filter = talloc_array(state, const char *, 2);
1595 0 : if (!attr_filter) {
1596 0 : ret = ENOMEM;
1597 0 : goto done;
1598 : }
1599 :
1600 0 : attr_filter[0] = opts->group_map[SDAP_AT_GROUP_MEMBER].name;
1601 0 : attr_filter[1] = NULL;
1602 :
1603 0 : ret = build_attrs_from_map(state, opts->group_map, SDAP_OPTS_GROUP,
1604 0 : attr_filter, &state->attrs, NULL);
1605 0 : if (ret != EOK) goto done;
1606 :
1607 0 : ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
1608 0 : if (ret != EOK) goto done;
1609 :
1610 0 : use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
1611 : opts->idmap_ctx,
1612 0 : sdom->dom->name,
1613 0 : sdom->dom->domain_id);
1614 :
1615 0 : oc_list = sdap_make_oc_list(state, opts->group_map);
1616 0 : if (oc_list == NULL) {
1617 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
1618 0 : ret = ENOMEM;
1619 0 : goto done;
1620 : }
1621 :
1622 0 : state->base_filter =
1623 0 : talloc_asprintf(state,
1624 : "(&(%s=%s)(%s)(%s=*)",
1625 0 : opts->group_map[SDAP_AT_GROUP_MEMBER].name,
1626 : clean_orig_dn, oc_list,
1627 0 : opts->group_map[SDAP_AT_GROUP_NAME].name);
1628 0 : if (!state->base_filter) {
1629 0 : ret = ENOMEM;
1630 0 : goto done;
1631 : }
1632 :
1633 0 : if (use_id_mapping) {
1634 : /* When mapping IDs or looking for SIDs, we don't want to limit
1635 : * ourselves to groups with a GID value. But there must be a SID to map
1636 : * from.
1637 : */
1638 0 : state->base_filter = talloc_asprintf_append(state->base_filter,
1639 : "(%s=*))",
1640 0 : opts->group_map[SDAP_AT_GROUP_OBJECTSID].name);
1641 : } else {
1642 0 : state->base_filter = talloc_asprintf_append(state->base_filter, ")");
1643 : }
1644 0 : if (!state->base_filter) {
1645 0 : talloc_zfree(req);
1646 0 : return NULL;
1647 : }
1648 :
1649 :
1650 0 : talloc_zfree(clean_orig_dn);
1651 :
1652 0 : ret = sdap_initgr_rfc2307bis_next_base(req);
1653 :
1654 : done:
1655 0 : if (ret != EOK) {
1656 0 : tevent_req_error(req, ret);
1657 0 : tevent_req_post(req, ev);
1658 : }
1659 0 : return req;
1660 : }
1661 :
1662 0 : static errno_t sdap_initgr_rfc2307bis_next_base(struct tevent_req *req)
1663 : {
1664 : struct tevent_req *subreq;
1665 : struct sdap_initgr_rfc2307bis_state *state;
1666 :
1667 0 : state = tevent_req_data(req, struct sdap_initgr_rfc2307bis_state);
1668 :
1669 0 : talloc_zfree(state->filter);
1670 0 : state->filter = sdap_get_id_specific_filter(
1671 : state,
1672 0 : state->base_filter,
1673 0 : state->search_bases[state->base_iter]->filter);
1674 0 : if (!state->filter) {
1675 0 : return ENOMEM;
1676 : }
1677 :
1678 0 : DEBUG(SSSDBG_TRACE_FUNC,
1679 : "Searching for parent groups for user [%s] with base [%s]\n",
1680 : state->orig_dn, state->search_bases[state->base_iter]->basedn);
1681 :
1682 0 : subreq = sdap_get_generic_send(
1683 : state, state->ev, state->opts, state->sh,
1684 0 : state->search_bases[state->base_iter]->basedn,
1685 0 : state->search_bases[state->base_iter]->scope,
1686 0 : state->filter, state->attrs,
1687 0 : state->opts->group_map, SDAP_OPTS_GROUP,
1688 : state->timeout,
1689 : true);
1690 0 : if (!subreq) {
1691 0 : return ENOMEM;
1692 : }
1693 0 : tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_process, req);
1694 :
1695 0 : return EOK;
1696 : }
1697 :
1698 0 : static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq)
1699 : {
1700 : struct tevent_req *req;
1701 : struct sdap_initgr_rfc2307bis_state *state;
1702 : struct sysdb_attrs **ldap_groups;
1703 : size_t count;
1704 : size_t i;
1705 : int ret;
1706 :
1707 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1708 0 : state = tevent_req_data(req, struct sdap_initgr_rfc2307bis_state);
1709 :
1710 0 : ret = sdap_get_generic_recv(subreq, state,
1711 : &count,
1712 : &ldap_groups);
1713 0 : talloc_zfree(subreq);
1714 0 : if (ret) {
1715 0 : tevent_req_error(req, ret);
1716 0 : return;
1717 : }
1718 0 : DEBUG(SSSDBG_TRACE_LIBS,
1719 : "Found %zu parent groups for user [%s]\n", count, state->name);
1720 :
1721 : /* Add this batch of groups to the list */
1722 0 : if (count > 0) {
1723 0 : state->direct_groups =
1724 0 : talloc_realloc(state,
1725 : state->direct_groups,
1726 : struct sysdb_attrs *,
1727 : state->num_direct_parents + count + 1);
1728 0 : if (!state->direct_groups) {
1729 0 : tevent_req_error(req, ENOMEM);
1730 0 : return;
1731 : }
1732 :
1733 : /* Copy the new groups into the list.
1734 : */
1735 0 : for (i = 0; i < count; i++) {
1736 0 : state->direct_groups[state->num_direct_parents + i] =
1737 0 : talloc_steal(state->direct_groups, ldap_groups[i]);
1738 : }
1739 :
1740 0 : state->num_direct_parents += count;
1741 :
1742 0 : state->direct_groups[state->num_direct_parents] = NULL;
1743 : }
1744 :
1745 0 : state->base_iter++;
1746 :
1747 : /* Check for additional search bases, and iterate
1748 : * through again.
1749 : */
1750 0 : if (state->search_bases[state->base_iter] != NULL) {
1751 0 : ret = sdap_initgr_rfc2307bis_next_base(req);
1752 0 : if (ret != EOK) {
1753 0 : tevent_req_error(req, ret);
1754 : }
1755 0 : return;
1756 : }
1757 :
1758 0 : if (state->num_direct_parents == 0) {
1759 : /* Start a transaction to look up the groups in the sysdb
1760 : * and update them with LDAP data
1761 : */
1762 0 : ret = save_rfc2307bis_user_memberships(state);
1763 0 : if (ret != EOK) {
1764 0 : tevent_req_error(req, ret);
1765 : } else {
1766 0 : tevent_req_done(req);
1767 : }
1768 0 : return;
1769 : }
1770 :
1771 0 : subreq = rfc2307bis_nested_groups_send(state, state->ev, state->opts,
1772 : state->sysdb, state->dom,
1773 : state->sh,
1774 : state->search_bases,
1775 : state->direct_groups,
1776 : state->num_direct_parents,
1777 : state->group_hash, 0);
1778 0 : if (!subreq) {
1779 0 : tevent_req_error(req, EIO);
1780 0 : return;
1781 : }
1782 0 : tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_done, req);
1783 : }
1784 :
1785 : static errno_t
1786 : save_rfc2307bis_groups(struct sdap_initgr_rfc2307bis_state *state);
1787 : static errno_t
1788 : save_rfc2307bis_group_memberships(struct sdap_initgr_rfc2307bis_state *state);
1789 :
1790 0 : static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq)
1791 : {
1792 : errno_t ret;
1793 0 : struct tevent_req *req =
1794 0 : tevent_req_callback_data(subreq, struct tevent_req);
1795 0 : struct sdap_initgr_rfc2307bis_state *state =
1796 0 : tevent_req_data(req, struct sdap_initgr_rfc2307bis_state);
1797 0 : bool in_transaction = false;
1798 : errno_t tret;
1799 :
1800 0 : ret = rfc2307bis_nested_groups_recv(subreq);
1801 0 : talloc_zfree(subreq);
1802 0 : if (ret != EOK) {
1803 0 : tevent_req_error(req, ret);
1804 0 : return;
1805 : }
1806 :
1807 0 : ret = sysdb_transaction_start(state->sysdb);
1808 0 : if (ret != EOK) {
1809 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1810 0 : goto fail;
1811 : }
1812 0 : in_transaction = true;
1813 :
1814 : /* save the groups if they are not cached */
1815 0 : ret = save_rfc2307bis_groups(state);
1816 0 : if (ret != EOK) {
1817 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1818 : "Could not save groups memberships [%d]\n", ret);
1819 0 : goto fail;
1820 : }
1821 :
1822 : /* save the group membership */
1823 0 : ret = save_rfc2307bis_group_memberships(state);
1824 0 : if (ret != EOK) {
1825 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1826 : "Could not save group memberships [%d]\n", ret);
1827 0 : goto fail;
1828 : }
1829 :
1830 : /* save the user memberships */
1831 0 : ret = save_rfc2307bis_user_memberships(state);
1832 0 : if (ret != EOK) {
1833 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1834 : "Could not save user memberships [%d]\n", ret);
1835 0 : goto fail;
1836 : }
1837 :
1838 0 : ret = sysdb_transaction_commit(state->sysdb);
1839 0 : if (ret != EOK) {
1840 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
1841 0 : goto fail;
1842 : }
1843 0 : in_transaction = false;
1844 :
1845 0 : tevent_req_done(req);
1846 0 : return;
1847 :
1848 : fail:
1849 0 : if (in_transaction) {
1850 0 : tret = sysdb_transaction_cancel(state->sysdb);
1851 0 : if (tret != EOK) {
1852 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
1853 : }
1854 : }
1855 0 : tevent_req_error(req, ret);
1856 0 : return;
1857 : }
1858 :
1859 0 : static int sdap_initgr_rfc2307bis_recv(struct tevent_req *req)
1860 : {
1861 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1862 0 : return EOK;
1863 : }
1864 :
1865 : struct rfc2307bis_group_memberships_state {
1866 : struct sysdb_ctx *sysdb;
1867 : struct sdap_options *opts;
1868 : struct sss_domain_info *dom;
1869 :
1870 : hash_table_t *group_hash;
1871 :
1872 : struct membership_diff *memberships;
1873 :
1874 : int ret;
1875 : };
1876 :
1877 : static errno_t
1878 0 : save_rfc2307bis_groups(struct sdap_initgr_rfc2307bis_state *state)
1879 : {
1880 0 : struct sysdb_attrs **groups = NULL;
1881 : unsigned long count;
1882 : hash_value_t *values;
1883 : int hret, i;
1884 : errno_t ret;
1885 : TALLOC_CTX *tmp_ctx;
1886 : struct sdap_nested_group *gr;
1887 :
1888 0 : tmp_ctx = talloc_new(NULL);
1889 0 : if (!tmp_ctx) return ENOMEM;
1890 :
1891 0 : hret = hash_values(state->group_hash, &count, &values);
1892 0 : if (hret != HASH_SUCCESS) {
1893 0 : ret = EIO;
1894 0 : goto done;
1895 : }
1896 :
1897 0 : groups = talloc_array(tmp_ctx, struct sysdb_attrs *, count);
1898 0 : if (!groups) {
1899 0 : ret = ENOMEM;
1900 0 : goto done;
1901 : }
1902 :
1903 0 : for (i = 0; i < count; i++) {
1904 0 : gr = talloc_get_type(values[i].ptr,
1905 : struct sdap_nested_group);
1906 0 : groups[i] = gr->group;
1907 : }
1908 0 : talloc_zfree(values);
1909 :
1910 0 : ret = sdap_nested_groups_store(state->sysdb, state->dom, state->opts,
1911 : groups, count);
1912 0 : if (ret != EOK) {
1913 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not save groups [%d]: %s\n",
1914 : ret, strerror(ret));
1915 0 : goto done;
1916 : }
1917 :
1918 0 : ret = EOK;
1919 : done:
1920 0 : talloc_free(tmp_ctx);
1921 0 : return ret;
1922 : }
1923 :
1924 : static bool rfc2307bis_group_memberships_build(hash_entry_t *item, void *user_data);
1925 :
1926 : static errno_t
1927 0 : save_rfc2307bis_group_memberships(struct sdap_initgr_rfc2307bis_state *state)
1928 : {
1929 : errno_t ret, tret;
1930 : int hret;
1931 : TALLOC_CTX *tmp_ctx;
1932 : struct rfc2307bis_group_memberships_state *membership_state;
1933 : struct membership_diff *iter;
1934 : struct membership_diff *iter_start;
1935 : struct membership_diff *iter_tmp;
1936 0 : bool in_transaction = false;
1937 : int num_added;
1938 : int i;
1939 : int grp_count;
1940 0 : char **add = NULL;
1941 :
1942 0 : tmp_ctx = talloc_new(NULL);
1943 0 : if (!tmp_ctx) return ENOMEM;
1944 :
1945 0 : membership_state = talloc_zero(tmp_ctx,
1946 : struct rfc2307bis_group_memberships_state);
1947 0 : if (!membership_state) {
1948 0 : ret = ENOMEM;
1949 0 : goto done;
1950 : }
1951 :
1952 0 : membership_state->sysdb = state->sysdb;
1953 0 : membership_state->dom = state->dom;
1954 0 : membership_state->opts = state->opts;
1955 0 : membership_state->group_hash = state->group_hash;
1956 :
1957 0 : hret = hash_iterate(state->group_hash,
1958 : rfc2307bis_group_memberships_build,
1959 : membership_state);
1960 0 : if (hret != HASH_SUCCESS) {
1961 0 : ret = membership_state->ret;
1962 0 : goto done;
1963 : }
1964 :
1965 0 : ret = sysdb_transaction_start(state->sysdb);
1966 0 : if (ret != EOK) {
1967 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1968 0 : goto done;
1969 : }
1970 0 : in_transaction = true;
1971 :
1972 0 : iter_start = membership_state->memberships;
1973 :
1974 0 : DLIST_FOR_EACH(iter, membership_state->memberships) {
1975 : /* Create a copy of iter->add array but do not include groups outside
1976 : * nesting limit. This array must be NULL terminated.
1977 : */
1978 0 : for (grp_count = 0; iter->add[grp_count]; grp_count++);
1979 0 : add = talloc_zero_array(tmp_ctx, char *, grp_count + 1);
1980 0 : if (add == NULL) {
1981 0 : ret = ENOMEM;
1982 0 : goto done;
1983 : }
1984 :
1985 0 : num_added = 0;
1986 0 : for (i = 0; i < grp_count; i++) {
1987 0 : DLIST_FOR_EACH(iter_tmp, iter_start) {
1988 0 : if (!strcmp(iter_tmp->name,iter->add[i])) {
1989 0 : add[num_added] = iter->add[i];
1990 0 : num_added++;
1991 0 : break;
1992 : }
1993 : }
1994 : }
1995 :
1996 0 : if (num_added == 0) {
1997 0 : add = NULL;
1998 : } else {
1999 0 : add[num_added] = NULL;
2000 : }
2001 0 : ret = sysdb_update_members(state->dom, iter->name,
2002 : SYSDB_MEMBER_GROUP,
2003 : (const char *const *) add,
2004 0 : (const char *const *) iter->del);
2005 0 : if (ret != EOK) {
2006 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Failed to update memberships\n");
2007 0 : goto done;
2008 : }
2009 : }
2010 :
2011 0 : ret = sysdb_transaction_commit(state->sysdb);
2012 0 : if (ret != EOK) {
2013 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
2014 0 : goto done;
2015 : }
2016 0 : in_transaction = false;
2017 :
2018 0 : ret = EOK;
2019 : done:
2020 0 : if (in_transaction) {
2021 0 : tret = sysdb_transaction_cancel(state->sysdb);
2022 0 : if (tret != EOK) {
2023 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
2024 : }
2025 : }
2026 0 : talloc_free(tmp_ctx);
2027 0 : return ret;
2028 : }
2029 :
2030 : static bool
2031 0 : rfc2307bis_group_memberships_build(hash_entry_t *item, void *user_data)
2032 : {
2033 0 : struct rfc2307bis_group_memberships_state *mstate = talloc_get_type(
2034 : user_data, struct rfc2307bis_group_memberships_state);
2035 : struct sdap_nested_group *group;
2036 : char *group_name;
2037 : TALLOC_CTX *tmp_ctx;
2038 : errno_t ret;
2039 : char **sysdb_parents_names_list;
2040 0 : char **ldap_parents_names_list = NULL;
2041 :
2042 : struct membership_diff *mdiff;
2043 :
2044 0 : group_name = (char *) item->key.str;
2045 0 : group = (struct sdap_nested_group *) item->value.ptr;
2046 :
2047 0 : tmp_ctx = talloc_new(NULL);
2048 0 : if (!tmp_ctx) {
2049 0 : ret = ENOMEM;
2050 0 : goto done;
2051 : }
2052 :
2053 0 : ret = sysdb_get_direct_parents(tmp_ctx, mstate->dom, SYSDB_MEMBER_GROUP,
2054 : group_name, &sysdb_parents_names_list);
2055 0 : if (ret) {
2056 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2057 : "Could not get direct sysdb parents for %s: %d [%s]\n",
2058 : group_name, ret, strerror(ret));
2059 0 : goto done;
2060 : }
2061 :
2062 0 : if (group->parents_count > 0) {
2063 0 : ret = sysdb_attrs_primary_name_list(mstate->sysdb, tmp_ctx,
2064 : group->ldap_parents, group->parents_count,
2065 0 : mstate->opts->group_map[SDAP_AT_GROUP_NAME].name,
2066 : &ldap_parents_names_list);
2067 0 : if (ret != EOK) {
2068 0 : goto done;
2069 : }
2070 : }
2071 :
2072 0 : ret = build_membership_diff(tmp_ctx, group_name, ldap_parents_names_list,
2073 : sysdb_parents_names_list, &mdiff);
2074 0 : if (ret != EOK) {
2075 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2076 : "Could not build membership diff for %s [%d]: %s\n",
2077 : group_name, ret, strerror(ret));
2078 0 : goto done;
2079 : }
2080 :
2081 0 : talloc_steal(mstate, mdiff);
2082 0 : DLIST_ADD(mstate->memberships, mdiff);
2083 0 : ret = EOK;
2084 : done:
2085 0 : talloc_free(tmp_ctx);
2086 0 : mstate->ret = ret;
2087 0 : return ret == EOK ? true : false;
2088 : }
2089 :
2090 0 : errno_t save_rfc2307bis_user_memberships(
2091 : struct sdap_initgr_rfc2307bis_state *state)
2092 : {
2093 : errno_t ret, tret;
2094 : char **ldap_grouplist;
2095 : char **sysdb_parent_name_list;
2096 : char **add_groups;
2097 : char **del_groups;
2098 0 : bool in_transaction = false;
2099 : size_t c;
2100 : char *tmp_str;
2101 :
2102 0 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
2103 0 : if(!tmp_ctx) {
2104 0 : return ENOMEM;
2105 : }
2106 :
2107 0 : DEBUG(SSSDBG_TRACE_LIBS, "Save parent groups to sysdb\n");
2108 0 : ret = sysdb_transaction_start(state->sysdb);
2109 0 : if (ret != EOK) {
2110 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
2111 0 : goto error;
2112 : }
2113 0 : in_transaction = true;
2114 :
2115 0 : ret = sysdb_get_direct_parents(tmp_ctx, state->dom, SYSDB_MEMBER_USER,
2116 : state->name, &sysdb_parent_name_list);
2117 0 : if (ret) {
2118 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2119 : "Could not get direct sysdb parents for %s: %d [%s]\n",
2120 : state->name, ret, strerror(ret));
2121 0 : goto error;
2122 : }
2123 :
2124 0 : if (state->num_direct_parents == 0) {
2125 0 : ldap_grouplist = NULL;
2126 : }
2127 : else {
2128 0 : ret = sysdb_attrs_primary_name_list(
2129 : state->sysdb, tmp_ctx,
2130 : state->direct_groups, state->num_direct_parents,
2131 0 : state->opts->group_map[SDAP_AT_GROUP_NAME].name,
2132 : &ldap_grouplist);
2133 0 : if (ret != EOK) {
2134 0 : goto error;
2135 : }
2136 :
2137 0 : if (IS_SUBDOMAIN(state->dom)) {
2138 0 : for (c = 0; ldap_grouplist[c] != NULL; c++) {
2139 0 : tmp_str = sss_tc_fqname(ldap_grouplist, state->dom->names,
2140 0 : state->dom, ldap_grouplist[c]);
2141 0 : if (tmp_str == NULL) {
2142 0 : DEBUG(SSSDBG_OP_FAILURE, "sss_tc_fqname failed.\n");
2143 0 : ret = ENOMEM;
2144 0 : goto error;
2145 : }
2146 0 : talloc_free(ldap_grouplist[c]);
2147 0 : ldap_grouplist[c] = tmp_str;
2148 : }
2149 : }
2150 : }
2151 :
2152 : /* Find the differences between the sysdb and ldap lists
2153 : * Groups in ldap only must be added to the sysdb;
2154 : * groups in the sysdb only must be removed.
2155 : */
2156 0 : ret = diff_string_lists(tmp_ctx,
2157 : ldap_grouplist, sysdb_parent_name_list,
2158 : &add_groups, &del_groups, NULL);
2159 0 : if (ret != EOK) {
2160 0 : goto error;
2161 : }
2162 :
2163 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Updating memberships for %s\n", state->name);
2164 0 : ret = sysdb_update_members(state->dom, state->name, SYSDB_MEMBER_USER,
2165 : (const char *const *)add_groups,
2166 : (const char *const *)del_groups);
2167 0 : if (ret != EOK) {
2168 0 : goto error;
2169 : }
2170 :
2171 0 : ret = sysdb_transaction_commit(state->sysdb);
2172 0 : if (ret != EOK) {
2173 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
2174 0 : goto error;
2175 : }
2176 0 : in_transaction = false;
2177 :
2178 0 : talloc_free(tmp_ctx);
2179 0 : return EOK;
2180 :
2181 : error:
2182 0 : if (in_transaction) {
2183 0 : tret = sysdb_transaction_cancel(state->sysdb);
2184 0 : if (tret != EOK) {
2185 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
2186 : }
2187 : }
2188 0 : talloc_free(tmp_ctx);
2189 0 : return ret;
2190 : }
2191 :
2192 : struct sdap_rfc2307bis_nested_ctx {
2193 : struct tevent_context *ev;
2194 : struct sdap_options *opts;
2195 : struct sysdb_ctx *sysdb;
2196 : struct sss_domain_info *dom;
2197 : struct sdap_handle *sh;
2198 : int timeout;
2199 : const char *base_filter;
2200 : char *filter;
2201 : const char *orig_dn;
2202 : const char **attrs;
2203 : struct sysdb_attrs **groups;
2204 : size_t num_groups;
2205 :
2206 : size_t nesting_level;
2207 :
2208 : size_t group_iter;
2209 : struct sdap_nested_group **processed_groups;
2210 :
2211 : hash_table_t *group_hash;
2212 : const char *primary_name;
2213 :
2214 : struct sysdb_handle *handle;
2215 :
2216 : size_t base_iter;
2217 : struct sdap_search_base **search_bases;
2218 : };
2219 :
2220 : static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req);
2221 0 : struct tevent_req *rfc2307bis_nested_groups_send(
2222 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2223 : struct sdap_options *opts, struct sysdb_ctx *sysdb,
2224 : struct sss_domain_info *dom, struct sdap_handle *sh,
2225 : struct sdap_search_base **search_bases,
2226 : struct sysdb_attrs **groups, size_t num_groups,
2227 : hash_table_t *group_hash, size_t nesting)
2228 : {
2229 : errno_t ret;
2230 : struct tevent_req *req;
2231 : struct sdap_rfc2307bis_nested_ctx *state;
2232 :
2233 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
2234 : "About to process %zu groups in nesting level %zu\n",
2235 : num_groups, nesting);
2236 :
2237 0 : req = tevent_req_create(mem_ctx, &state,
2238 : struct sdap_rfc2307bis_nested_ctx);
2239 0 : if (!req) return NULL;
2240 :
2241 0 : if ((num_groups == 0) ||
2242 0 : (nesting > dp_opt_get_int(opts->basic, SDAP_NESTING_LEVEL))) {
2243 : /* No parent groups to process or too deep*/
2244 0 : ret = EOK;
2245 0 : goto done;
2246 : }
2247 :
2248 0 : state->ev = ev;
2249 0 : state->opts = opts;
2250 0 : state->sysdb = sysdb;
2251 0 : state->dom = dom;
2252 0 : state->sh = sh;
2253 0 : state->groups = groups;
2254 0 : state->num_groups = num_groups;
2255 0 : state->group_iter = 0;
2256 0 : state->nesting_level = nesting;
2257 0 : state->group_hash = group_hash;
2258 0 : state->filter = NULL;
2259 0 : state->timeout = dp_opt_get_int(state->opts->basic,
2260 : SDAP_SEARCH_TIMEOUT);
2261 0 : state->base_iter = 0;
2262 0 : state->search_bases = search_bases;
2263 0 : if (!state->search_bases) {
2264 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2265 : "Initgroups nested lookup request "
2266 : "without a group search base\n");
2267 0 : ret = EINVAL;
2268 0 : goto done;
2269 : }
2270 :
2271 0 : state->processed_groups = talloc_array(state,
2272 : struct sdap_nested_group *,
2273 : state->num_groups);
2274 0 : if (state->processed_groups == NULL) {
2275 0 : ret = ENOMEM;
2276 0 : goto done;
2277 : }
2278 :
2279 0 : while (state->group_iter < state->num_groups) {
2280 0 : ret = rfc2307bis_nested_groups_step(req);
2281 0 : if (ret == EOK) {
2282 : /* This group had already been looked up. Continue to
2283 : * another group in the same level
2284 : */
2285 0 : state->group_iter++;
2286 0 : continue;
2287 : } else {
2288 0 : goto done;
2289 : }
2290 : }
2291 :
2292 0 : ret = EOK;
2293 :
2294 : done:
2295 0 : if (ret == EOK) {
2296 : /* All parent groups were already processed */
2297 0 : tevent_req_done(req);
2298 0 : tevent_req_post(req, ev);
2299 0 : } else if (ret != EAGAIN) {
2300 0 : tevent_req_error(req, ret);
2301 0 : tevent_req_post(req, ev);
2302 : }
2303 :
2304 : /* EAGAIN means a lookup is in progress */
2305 0 : return req;
2306 : }
2307 :
2308 : static errno_t rfc2307bis_nested_groups_next_base(struct tevent_req *req);
2309 : static void rfc2307bis_nested_groups_process(struct tevent_req *subreq);
2310 0 : static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
2311 : {
2312 : errno_t ret;
2313 0 : TALLOC_CTX *tmp_ctx = NULL;
2314 : const char **attr_filter;
2315 : char *clean_orig_dn;
2316 : hash_key_t key;
2317 : hash_value_t value;
2318 0 : struct sdap_rfc2307bis_nested_ctx *state =
2319 0 : tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
2320 : char *oc_list;
2321 :
2322 0 : tmp_ctx = talloc_new(state);
2323 0 : if (!tmp_ctx) {
2324 0 : ret = ENOMEM;
2325 0 : goto done;
2326 : }
2327 :
2328 0 : ret = sdap_get_group_primary_name(state, state->opts,
2329 0 : state->groups[state->group_iter],
2330 : state->dom, &state->primary_name);
2331 0 : if (ret != EOK) {
2332 0 : goto done;
2333 : }
2334 :
2335 0 : key.type = HASH_KEY_STRING;
2336 0 : key.str = talloc_strdup(state, state->primary_name);
2337 0 : if (!key.str) {
2338 0 : ret = ENOMEM;
2339 0 : goto done;
2340 : }
2341 :
2342 0 : DEBUG(SSSDBG_TRACE_LIBS, "Processing group [%s]\n", state->primary_name);
2343 :
2344 0 : ret = hash_lookup(state->group_hash, &key, &value);
2345 0 : if (ret == HASH_SUCCESS) {
2346 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Group [%s] was already processed, "
2347 : "taking a shortcut\n", state->primary_name);
2348 0 : state->processed_groups[state->group_iter] =
2349 0 : talloc_get_type(value.ptr, struct sdap_nested_group);
2350 0 : talloc_free(key.str);
2351 0 : ret = EOK;
2352 0 : goto done;
2353 : }
2354 :
2355 : /* Need to try to find parent groups for this group. */
2356 0 : state->processed_groups[state->group_iter] =
2357 0 : talloc_zero(state->processed_groups, struct sdap_nested_group);
2358 0 : if (!state->processed_groups[state->group_iter]) {
2359 0 : ret = ENOMEM;
2360 0 : goto done;
2361 : }
2362 :
2363 : /* this steal doesn't change much now, but will be helpful later on
2364 : * if we steal the whole processed_group on the hash table */
2365 0 : state->processed_groups[state->group_iter]->group =
2366 0 : talloc_steal(state->processed_groups[state->group_iter],
2367 : state->groups[state->group_iter]);
2368 :
2369 : /* Get any parent groups for this group */
2370 0 : ret = sysdb_attrs_get_string(state->groups[state->group_iter],
2371 : SYSDB_ORIG_DN,
2372 : &state->orig_dn);
2373 0 : if (ret != EOK) {
2374 0 : goto done;
2375 : }
2376 :
2377 0 : attr_filter = talloc_array(state, const char *, 2);
2378 0 : if (!attr_filter) {
2379 0 : ret = ENOMEM;
2380 0 : goto done;
2381 : }
2382 :
2383 0 : attr_filter[0] = state->opts->group_map[SDAP_AT_GROUP_MEMBER].name;
2384 0 : attr_filter[1] = NULL;
2385 :
2386 0 : ret = build_attrs_from_map(state, state->opts->group_map, SDAP_OPTS_GROUP,
2387 : attr_filter, &state->attrs, NULL);
2388 0 : if (ret != EOK) {
2389 0 : goto done;
2390 : }
2391 :
2392 0 : ret = sss_filter_sanitize(tmp_ctx, state->orig_dn, &clean_orig_dn);
2393 0 : if (ret != EOK) {
2394 0 : goto done;
2395 : }
2396 :
2397 0 : oc_list = sdap_make_oc_list(state, state->opts->group_map);
2398 0 : if (oc_list == NULL) {
2399 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create objectClass list.\n");
2400 0 : ret = ENOMEM;
2401 0 : goto done;
2402 : }
2403 :
2404 0 : state->base_filter = talloc_asprintf(
2405 : state, "(&(%s=%s)(%s)(%s=*))",
2406 0 : state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
2407 : clean_orig_dn, oc_list,
2408 0 : state->opts->group_map[SDAP_AT_GROUP_NAME].name);
2409 0 : if (!state->base_filter) {
2410 0 : ret = ENOMEM;
2411 0 : goto done;
2412 : }
2413 :
2414 0 : ret = rfc2307bis_nested_groups_next_base(req);
2415 0 : if (ret != EOK) goto done;
2416 :
2417 : /* Still processing parent groups */
2418 0 : ret = EAGAIN;
2419 :
2420 : done:
2421 0 : talloc_free(tmp_ctx);
2422 0 : return ret;
2423 : }
2424 :
2425 0 : static errno_t rfc2307bis_nested_groups_next_base(struct tevent_req *req)
2426 : {
2427 : struct tevent_req *subreq;
2428 : struct sdap_rfc2307bis_nested_ctx *state;
2429 :
2430 0 : state = tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
2431 :
2432 0 : talloc_zfree(state->filter);
2433 0 : state->filter = sdap_get_id_specific_filter(
2434 : state, state->base_filter,
2435 0 : state->search_bases[state->base_iter]->filter);
2436 0 : if (!state->filter) {
2437 0 : return ENOMEM;
2438 : }
2439 :
2440 0 : DEBUG(SSSDBG_TRACE_FUNC,
2441 : "Searching for parent groups of group [%s] with base [%s]\n",
2442 : state->orig_dn,
2443 : state->search_bases[state->base_iter]->basedn);
2444 :
2445 0 : subreq = sdap_get_generic_send(
2446 : state, state->ev, state->opts, state->sh,
2447 0 : state->search_bases[state->base_iter]->basedn,
2448 0 : state->search_bases[state->base_iter]->scope,
2449 0 : state->filter, state->attrs,
2450 0 : state->opts->group_map, SDAP_OPTS_GROUP,
2451 : state->timeout,
2452 : true);
2453 0 : if (!subreq) {
2454 0 : return ENOMEM;
2455 : }
2456 0 : tevent_req_set_callback(subreq,
2457 : rfc2307bis_nested_groups_process,
2458 : req);
2459 :
2460 0 : return EOK;
2461 : }
2462 :
2463 : static void
2464 0 : rfc2307bis_nested_groups_iterate(struct tevent_req *req,
2465 : struct sdap_rfc2307bis_nested_ctx *state)
2466 : {
2467 : errno_t ret;
2468 :
2469 0 : state->group_iter++;
2470 0 : while (state->group_iter < state->num_groups) {
2471 0 : ret = rfc2307bis_nested_groups_step(req);
2472 0 : if (ret == EAGAIN) {
2473 : /* Looking up parent groups.. */
2474 0 : return;
2475 0 : } else if (ret != EOK) {
2476 0 : tevent_req_error(req, ret);
2477 0 : return;
2478 : }
2479 :
2480 : /* EOK means this group has already been processed
2481 : * in another nesting level */
2482 0 : state->group_iter++;
2483 : }
2484 :
2485 0 : if (state->group_iter == state->num_groups) {
2486 : /* All groups processed. Done. */
2487 0 : tevent_req_done(req);
2488 : }
2489 : }
2490 :
2491 : static void rfc2307bis_nested_groups_done(struct tevent_req *subreq);
2492 0 : static void rfc2307bis_nested_groups_process(struct tevent_req *subreq)
2493 : {
2494 : errno_t ret;
2495 0 : struct tevent_req *req =
2496 0 : tevent_req_callback_data(subreq, struct tevent_req);
2497 0 : struct sdap_rfc2307bis_nested_ctx *state =
2498 0 : tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
2499 : size_t count;
2500 : size_t i;
2501 : struct sysdb_attrs **ldap_groups;
2502 : struct sdap_nested_group *ngr;
2503 : hash_value_t value;
2504 : hash_key_t key;
2505 : int hret;
2506 :
2507 0 : ret = sdap_get_generic_recv(subreq, state,
2508 : &count,
2509 : &ldap_groups);
2510 0 : talloc_zfree(subreq);
2511 0 : if (ret) {
2512 0 : tevent_req_error(req, ret);
2513 0 : return;
2514 : }
2515 :
2516 0 : DEBUG(SSSDBG_TRACE_LIBS,
2517 : "Found %zu parent groups of [%s]\n", count, state->orig_dn);
2518 0 : ngr = state->processed_groups[state->group_iter];
2519 :
2520 : /* Add this batch of groups to the list */
2521 0 : if (count > 0) {
2522 0 : ngr->ldap_parents =
2523 0 : talloc_realloc(ngr,
2524 : ngr->ldap_parents,
2525 : struct sysdb_attrs *,
2526 : ngr->parents_count + count + 1);
2527 0 : if (!ngr->ldap_parents) {
2528 0 : tevent_req_error(req, ENOMEM);
2529 0 : return;
2530 : }
2531 :
2532 : /* Copy the new groups into the list.
2533 : * They're allocated on 'state' so we need to move them
2534 : * onto ldap_parents so that the data won't disappear when
2535 : * we finish this nesting level.
2536 : */
2537 0 : for (i = 0; i < count; i++) {
2538 0 : ngr->ldap_parents[ngr->parents_count + i] =
2539 0 : talloc_steal(ngr->ldap_parents, ldap_groups[i]);
2540 : }
2541 :
2542 0 : ngr->parents_count += count;
2543 :
2544 0 : ngr->ldap_parents[ngr->parents_count] = NULL;
2545 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
2546 : "Total of %zu direct parents after this iteration\n",
2547 : ngr->parents_count);
2548 : }
2549 :
2550 0 : state->base_iter++;
2551 :
2552 : /* Check for additional search bases, and iterate
2553 : * through again.
2554 : */
2555 0 : if (state->search_bases[state->base_iter] != NULL) {
2556 0 : ret = rfc2307bis_nested_groups_next_base(req);
2557 0 : if (ret != EOK) {
2558 0 : tevent_req_error(req, ret);
2559 : }
2560 0 : return;
2561 : }
2562 :
2563 : /* Reset the base iterator for future lookups */
2564 0 : state->base_iter = 0;
2565 :
2566 : /* Save the group into the hash table */
2567 0 : key.type = HASH_KEY_STRING;
2568 0 : key.str = talloc_strdup(state, state->primary_name);
2569 0 : if (!key.str) {
2570 0 : tevent_req_error(req, ENOMEM);
2571 0 : return;
2572 : }
2573 :
2574 : /* Steal the nested group entry on the group_hash context so it can
2575 : * outlive this request */
2576 0 : talloc_steal(state->group_hash, ngr);
2577 :
2578 0 : value.type = HASH_VALUE_PTR;
2579 0 : value.ptr = ngr;
2580 :
2581 0 : hret = hash_enter(state->group_hash, &key, &value);
2582 0 : if (hret != HASH_SUCCESS) {
2583 0 : talloc_free(key.str);
2584 0 : tevent_req_error(req, EIO);
2585 0 : return;
2586 : }
2587 0 : talloc_free(key.str);
2588 :
2589 0 : if (ngr->parents_count == 0) {
2590 : /* No parent groups for this group in LDAP
2591 : * Move on to the next group
2592 : */
2593 0 : rfc2307bis_nested_groups_iterate(req, state);
2594 0 : return;
2595 : }
2596 :
2597 : /* Otherwise, recurse into the groups */
2598 0 : subreq = rfc2307bis_nested_groups_send(
2599 : state, state->ev, state->opts, state->sysdb,
2600 : state->dom, state->sh,
2601 : state->search_bases,
2602 : ngr->ldap_parents,
2603 : ngr->parents_count,
2604 : state->group_hash,
2605 0 : state->nesting_level+1);
2606 0 : if (!subreq) {
2607 0 : tevent_req_error(req, EIO);
2608 0 : return;
2609 : }
2610 0 : tevent_req_set_callback(subreq, rfc2307bis_nested_groups_done, req);
2611 : }
2612 :
2613 0 : static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req)
2614 : {
2615 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2616 0 : return EOK;
2617 : }
2618 :
2619 0 : static void rfc2307bis_nested_groups_done(struct tevent_req *subreq)
2620 : {
2621 : errno_t ret;
2622 0 : struct tevent_req *req =
2623 0 : tevent_req_callback_data(subreq, struct tevent_req);
2624 0 : struct sdap_rfc2307bis_nested_ctx *state =
2625 0 : tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
2626 :
2627 0 : ret = rfc2307bis_nested_groups_recv(subreq);
2628 0 : talloc_zfree(subreq);
2629 0 : if (ret != EOK) {
2630 0 : DEBUG(SSSDBG_TRACE_FUNC, "rfc2307bis_nested failed [%d][%s]\n",
2631 : ret, strerror(ret));
2632 0 : tevent_req_error(req, ret);
2633 0 : return;
2634 : }
2635 :
2636 0 : rfc2307bis_nested_groups_iterate(req, state);
2637 : }
2638 :
2639 : /* ==Initgr-call-(groups-a-user-is-member-of)============================= */
2640 :
2641 : struct sdap_get_initgr_state {
2642 : struct tevent_context *ev;
2643 : struct sysdb_ctx *sysdb;
2644 : struct sdap_options *opts;
2645 : struct sss_domain_info *dom;
2646 : struct sdap_domain *sdom;
2647 : struct sdap_handle *sh;
2648 : struct sdap_id_ctx *id_ctx;
2649 : struct sdap_id_conn_ctx *conn;
2650 : const char *name;
2651 : const char **grp_attrs;
2652 : const char **user_attrs;
2653 : char *user_base_filter;
2654 : char *filter;
2655 : int timeout;
2656 :
2657 : struct sysdb_attrs *orig_user;
2658 :
2659 : size_t user_base_iter;
2660 : struct sdap_search_base **user_search_bases;
2661 :
2662 : bool use_id_mapping;
2663 : };
2664 :
2665 : static errno_t sdap_get_initgr_next_base(struct tevent_req *req);
2666 : static void sdap_get_initgr_user(struct tevent_req *subreq);
2667 : static void sdap_get_initgr_done(struct tevent_req *subreq);
2668 :
2669 0 : struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
2670 : struct tevent_context *ev,
2671 : struct sdap_domain *sdom,
2672 : struct sdap_handle *sh,
2673 : struct sdap_id_ctx *id_ctx,
2674 : struct sdap_id_conn_ctx *conn,
2675 : const char *name,
2676 : int name_type,
2677 : const char *extra_value,
2678 : const char **grp_attrs)
2679 : {
2680 : struct tevent_req *req;
2681 : struct sdap_get_initgr_state *state;
2682 : int ret;
2683 : char *clean_name;
2684 : bool use_id_mapping;
2685 : const char *search_attr;
2686 :
2687 0 : DEBUG(SSSDBG_TRACE_ALL, "Retrieving info for initgroups call\n");
2688 :
2689 0 : req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state);
2690 0 : if (!req) return NULL;
2691 :
2692 0 : state->ev = ev;
2693 0 : state->opts = id_ctx->opts;
2694 0 : state->dom = sdom->dom;
2695 0 : state->sysdb = sdom->dom->sysdb;
2696 0 : state->sdom = sdom;
2697 0 : state->sh = sh;
2698 0 : state->id_ctx = id_ctx;
2699 0 : state->conn = conn;
2700 0 : state->name = name;
2701 0 : state->grp_attrs = grp_attrs;
2702 0 : state->orig_user = NULL;
2703 0 : state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
2704 0 : state->user_base_iter = 0;
2705 0 : state->user_search_bases = sdom->user_search_bases;
2706 0 : if (!state->user_search_bases) {
2707 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2708 : "Initgroups lookup request without a user search base\n");
2709 0 : ret = EINVAL;
2710 0 : goto done;
2711 : }
2712 :
2713 0 : use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
2714 0 : id_ctx->opts->idmap_ctx,
2715 0 : sdom->dom->name,
2716 0 : sdom->dom->domain_id);
2717 :
2718 0 : ret = sss_filter_sanitize(state, name, &clean_name);
2719 0 : if (ret != EOK) {
2720 0 : talloc_zfree(req);
2721 0 : return NULL;
2722 : }
2723 :
2724 0 : if (extra_value && strcmp(extra_value, EXTRA_NAME_IS_UPN) == 0) {
2725 0 : search_attr = state->opts->user_map[SDAP_AT_USER_PRINC].name;
2726 : } else {
2727 0 : switch (name_type) {
2728 : case BE_FILTER_SECID:
2729 0 : search_attr = state->opts->user_map[SDAP_AT_USER_OBJECTSID].name;
2730 0 : break;
2731 : case BE_FILTER_UUID:
2732 0 : search_attr = state->opts->user_map[SDAP_AT_USER_UUID].name;
2733 0 : break;
2734 : default:
2735 0 : search_attr = state->opts->user_map[SDAP_AT_USER_NAME].name;
2736 : }
2737 : }
2738 :
2739 0 : state->user_base_filter =
2740 0 : talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)",
2741 : search_attr, clean_name,
2742 0 : state->opts->user_map[SDAP_OC_USER].name);
2743 0 : if (!state->user_base_filter) {
2744 0 : talloc_zfree(req);
2745 0 : return NULL;
2746 : }
2747 :
2748 0 : if (use_id_mapping) {
2749 : /* When mapping IDs or looking for SIDs, we don't want to limit
2750 : * ourselves to users with a UID value. But there must be a SID to map
2751 : * from.
2752 : */
2753 0 : state->user_base_filter = talloc_asprintf_append(state->user_base_filter,
2754 : "(%s=*))",
2755 0 : id_ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name);
2756 : } else {
2757 : /* When not ID-mapping, make sure there is a non-NULL UID */
2758 0 : state->user_base_filter = talloc_asprintf_append(state->user_base_filter,
2759 : "(&(%s=*)(!(%s=0))))",
2760 0 : id_ctx->opts->user_map[SDAP_AT_USER_UID].name,
2761 0 : id_ctx->opts->user_map[SDAP_AT_USER_UID].name);
2762 : }
2763 0 : if (!state->user_base_filter) {
2764 0 : talloc_zfree(req);
2765 0 : return NULL;
2766 : }
2767 :
2768 0 : ret = build_attrs_from_map(state,
2769 0 : state->opts->user_map,
2770 0 : state->opts->user_map_cnt,
2771 0 : NULL, &state->user_attrs, NULL);
2772 0 : if (ret) {
2773 0 : talloc_zfree(req);
2774 0 : return NULL;
2775 : }
2776 :
2777 0 : state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
2778 0 : state->opts->idmap_ctx,
2779 0 : state->dom->name,
2780 0 : state->dom->domain_id);
2781 :
2782 0 : ret = sdap_get_initgr_next_base(req);
2783 :
2784 : done:
2785 0 : if (ret != EOK) {
2786 0 : tevent_req_error(req, ret);
2787 0 : tevent_req_post(req, ev);
2788 : }
2789 :
2790 0 : return req;
2791 : }
2792 :
2793 0 : static errno_t sdap_get_initgr_next_base(struct tevent_req *req)
2794 : {
2795 : struct tevent_req *subreq;
2796 : struct sdap_get_initgr_state *state;
2797 :
2798 0 : state = tevent_req_data(req, struct sdap_get_initgr_state);
2799 :
2800 0 : talloc_zfree(state->filter);
2801 0 : state->filter = sdap_get_id_specific_filter(
2802 : state,
2803 0 : state->user_base_filter,
2804 0 : state->user_search_bases[state->user_base_iter]->filter);
2805 0 : if (!state->filter) {
2806 0 : return ENOMEM;
2807 : }
2808 :
2809 0 : DEBUG(SSSDBG_TRACE_FUNC,
2810 : "Searching for users with base [%s]\n",
2811 : state->user_search_bases[state->user_base_iter]->basedn);
2812 :
2813 0 : subreq = sdap_get_generic_send(
2814 : state, state->ev, state->opts, state->sh,
2815 0 : state->user_search_bases[state->user_base_iter]->basedn,
2816 0 : state->user_search_bases[state->user_base_iter]->scope,
2817 0 : state->filter, state->user_attrs,
2818 0 : state->opts->user_map, state->opts->user_map_cnt,
2819 : state->timeout,
2820 : false);
2821 0 : if (!subreq) {
2822 0 : return ENOMEM;
2823 : }
2824 0 : tevent_req_set_callback(subreq, sdap_get_initgr_user, req);
2825 0 : return EOK;
2826 : }
2827 :
2828 0 : static void sdap_get_initgr_user(struct tevent_req *subreq)
2829 : {
2830 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2831 : struct tevent_req);
2832 0 : struct sdap_get_initgr_state *state = tevent_req_data(req,
2833 : struct sdap_get_initgr_state);
2834 : struct sysdb_attrs **usr_attrs;
2835 : size_t count;
2836 : int ret;
2837 : errno_t sret;
2838 : const char *orig_dn;
2839 : const char *cname;
2840 0 : bool in_transaction = false;
2841 : char *expected_basedn;
2842 : size_t expected_basedn_len;
2843 : size_t dn_len;
2844 0 : size_t c = 0;
2845 :
2846 0 : DEBUG(SSSDBG_TRACE_ALL, "Receiving info for the user\n");
2847 :
2848 0 : ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);
2849 0 : talloc_zfree(subreq);
2850 0 : if (ret) {
2851 0 : tevent_req_error(req, ret);
2852 0 : return;
2853 : }
2854 :
2855 0 : if (count == 0) {
2856 : /* No users found in this search */
2857 0 : state->user_base_iter++;
2858 0 : if (state->user_search_bases[state->user_base_iter]) {
2859 : /* There are more search bases to try */
2860 0 : ret = sdap_get_initgr_next_base(req);
2861 0 : if (ret != EOK) {
2862 0 : tevent_req_error(req, ret);
2863 : }
2864 0 : return;
2865 : }
2866 :
2867 : /* fallback to fetch a local user if required */
2868 0 : if ((state->opts->schema_type == SDAP_SCHEMA_RFC2307) &&
2869 0 : (dp_opt_get_bool(state->opts->basic,
2870 : SDAP_RFC2307_FALLBACK_TO_LOCAL_USERS) == true)) {
2871 0 : ret = sdap_fallback_local_user(state, state->name, -1, &usr_attrs);
2872 : } else {
2873 0 : ret = ENOENT;
2874 : }
2875 :
2876 0 : if (ret != EOK) {
2877 0 : tevent_req_error(req, ret);
2878 0 : return;
2879 : }
2880 0 : } else if (count != 1) {
2881 0 : DEBUG(SSSDBG_OP_FAILURE,
2882 : "Expected one user entry and got %zu\n", count);
2883 :
2884 0 : ret = domain_to_basedn(state, state->dom->name, &expected_basedn);
2885 0 : if (ret != EOK) {
2886 0 : DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n");
2887 0 : tevent_req_error(req, ret);
2888 0 : return;
2889 : }
2890 0 : expected_basedn = talloc_asprintf(state, "%s%s",
2891 : "cn=users,", expected_basedn);
2892 0 : if (expected_basedn == NULL) {
2893 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_append failed.\n");
2894 0 : tevent_req_error(req, ENOMEM);
2895 0 : return;
2896 : }
2897 :
2898 0 : DEBUG(SSSDBG_TRACE_ALL, "Expected BaseDN is [%s].\n", expected_basedn);
2899 0 : expected_basedn_len = strlen(expected_basedn);
2900 :
2901 0 : for (c = 0; c < count; c++) {
2902 0 : ret = sysdb_attrs_get_string(usr_attrs[c], SYSDB_ORIG_DN, &orig_dn);
2903 0 : if (ret != EOK) {
2904 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
2905 0 : tevent_req_error(req, ret);
2906 0 : return;
2907 : }
2908 0 : dn_len = strlen(orig_dn);
2909 :
2910 0 : if (dn_len > expected_basedn_len
2911 0 : && strcasecmp(orig_dn + (dn_len - expected_basedn_len),
2912 : expected_basedn) == 0) {
2913 0 : DEBUG(SSSDBG_TRACE_ALL,
2914 : "Found matching dn [%s].\n", orig_dn);
2915 0 : break;
2916 : }
2917 : }
2918 :
2919 0 : if (c == count) {
2920 0 : DEBUG(SSSDBG_OP_FAILURE, "No matching DN found.\n");
2921 0 : tevent_req_error(req, EINVAL);
2922 0 : return;
2923 : }
2924 : }
2925 :
2926 0 : state->orig_user = usr_attrs[c];
2927 :
2928 0 : ret = sysdb_transaction_start(state->sysdb);
2929 0 : if (ret) {
2930 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
2931 0 : goto fail;
2932 : }
2933 0 : in_transaction = true;
2934 :
2935 0 : DEBUG(SSSDBG_TRACE_ALL, "Storing the user\n");
2936 :
2937 0 : ret = sdap_save_user(state, state->opts, state->dom, state->orig_user,
2938 : NULL, 0);
2939 0 : if (ret) {
2940 0 : goto fail;
2941 : }
2942 :
2943 0 : DEBUG(SSSDBG_TRACE_ALL, "Commit change\n");
2944 :
2945 0 : ret = sysdb_transaction_commit(state->sysdb);
2946 0 : if (ret) {
2947 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
2948 0 : goto fail;
2949 : }
2950 0 : in_transaction = false;
2951 :
2952 0 : ret = sysdb_get_real_name(state, state->dom, state->name, &cname);
2953 0 : if (ret != EOK) {
2954 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot canonicalize username\n");
2955 0 : tevent_req_error(req, ret);
2956 0 : return;
2957 : }
2958 :
2959 0 : DEBUG(SSSDBG_TRACE_ALL, "Process user's groups\n");
2960 :
2961 0 : switch (state->opts->schema_type) {
2962 : case SDAP_SCHEMA_RFC2307:
2963 0 : subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,
2964 : state->sysdb, state->dom, state->sh,
2965 : cname);
2966 0 : if (!subreq) {
2967 0 : tevent_req_error(req, ENOMEM);
2968 0 : return;
2969 : }
2970 0 : tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
2971 0 : break;
2972 :
2973 : case SDAP_SCHEMA_RFC2307BIS:
2974 : case SDAP_SCHEMA_AD:
2975 0 : ret = sysdb_attrs_get_string(state->orig_user,
2976 : SYSDB_ORIG_DN,
2977 : &orig_dn);
2978 0 : if (ret != EOK) {
2979 0 : tevent_req_error(req, ret);
2980 0 : return;
2981 : }
2982 :
2983 0 : if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2003
2984 0 : && dp_opt_get_bool(state->opts->basic, SDAP_AD_USE_TOKENGROUPS)) {
2985 : /* Take advantage of AD's tokenGroups mechanism to look up all
2986 : * parent groups in a single request.
2987 : */
2988 0 : subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev,
2989 : state->id_ctx,
2990 : state->conn,
2991 : state->opts,
2992 : state->sysdb,
2993 : state->dom,
2994 : state->sh,
2995 : cname, orig_dn,
2996 : state->timeout,
2997 0 : state->use_id_mapping);
2998 0 : } else if (state->opts->support_matching_rule
2999 0 : && dp_opt_get_bool(state->opts->basic,
3000 : SDAP_AD_MATCHING_RULE_INITGROUPS)) {
3001 : /* Take advantage of AD's extensibleMatch filter to look up
3002 : * all parent groups in a single request.
3003 : */
3004 0 : subreq = sdap_get_ad_match_rule_initgroups_send(state, state->ev,
3005 : state->opts,
3006 : state->sysdb,
3007 : state->dom,
3008 : state->sh,
3009 : cname, orig_dn,
3010 : state->timeout);
3011 : } else {
3012 0 : subreq = sdap_initgr_rfc2307bis_send(
3013 : state, state->ev, state->opts,
3014 : state->sdom, state->sh,
3015 : cname, orig_dn);
3016 : }
3017 0 : if (!subreq) {
3018 0 : tevent_req_error(req, ENOMEM);
3019 0 : return;
3020 : }
3021 :
3022 0 : talloc_steal(subreq, orig_dn);
3023 0 : tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
3024 0 : break;
3025 :
3026 : case SDAP_SCHEMA_IPA_V1:
3027 0 : subreq = sdap_initgr_nested_send(state, state->ev, state->opts,
3028 : state->sysdb, state->dom, state->sh,
3029 : state->orig_user, state->grp_attrs);
3030 0 : if (!subreq) {
3031 0 : tevent_req_error(req, ENOMEM);
3032 0 : return;
3033 : }
3034 0 : tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
3035 0 : return;
3036 :
3037 : default:
3038 0 : tevent_req_error(req, EINVAL);
3039 0 : return;
3040 : }
3041 :
3042 0 : return;
3043 : fail:
3044 0 : if (in_transaction) {
3045 0 : sret = sysdb_transaction_cancel(state->sysdb);
3046 0 : if (sret != EOK) {
3047 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
3048 : }
3049 : }
3050 0 : tevent_req_error(req, ret);
3051 : }
3052 :
3053 : static void sdap_get_initgr_pgid(struct tevent_req *req);
3054 0 : static void sdap_get_initgr_done(struct tevent_req *subreq)
3055 : {
3056 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
3057 : struct tevent_req);
3058 0 : struct sdap_get_initgr_state *state = tevent_req_data(req,
3059 : struct sdap_get_initgr_state);
3060 : int ret;
3061 : TALLOC_CTX *tmp_ctx;
3062 : gid_t primary_gid;
3063 : char *gid;
3064 : char *sid_str;
3065 : char *dom_sid_str;
3066 : char *group_sid_str;
3067 0 : struct sdap_options *opts = state->opts;
3068 :
3069 0 : DEBUG(SSSDBG_TRACE_ALL, "Initgroups done\n");
3070 :
3071 0 : tmp_ctx = talloc_new(NULL);
3072 0 : if (!tmp_ctx) {
3073 0 : tevent_req_error(req, ENOMEM);
3074 0 : return;
3075 : }
3076 :
3077 0 : switch (state->opts->schema_type) {
3078 : case SDAP_SCHEMA_RFC2307:
3079 0 : ret = sdap_initgr_rfc2307_recv(subreq);
3080 0 : break;
3081 :
3082 : case SDAP_SCHEMA_RFC2307BIS:
3083 : case SDAP_SCHEMA_AD:
3084 0 : if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2003
3085 0 : && dp_opt_get_bool(state->opts->basic, SDAP_AD_USE_TOKENGROUPS)) {
3086 :
3087 0 : ret = sdap_ad_tokengroups_initgroups_recv(subreq);
3088 : }
3089 0 : else if (state->opts->support_matching_rule
3090 0 : && dp_opt_get_bool(state->opts->basic,
3091 : SDAP_AD_MATCHING_RULE_INITGROUPS)) {
3092 0 : ret = sdap_get_ad_match_rule_initgroups_recv(subreq);
3093 : } else {
3094 0 : ret = sdap_initgr_rfc2307bis_recv(subreq);
3095 : }
3096 0 : break;
3097 :
3098 : case SDAP_SCHEMA_IPA_V1:
3099 0 : ret = sdap_initgr_nested_recv(subreq);
3100 0 : break;
3101 :
3102 : default:
3103 :
3104 0 : ret = EINVAL;
3105 0 : break;
3106 : }
3107 :
3108 0 : talloc_zfree(subreq);
3109 0 : if (ret) {
3110 0 : DEBUG(SSSDBG_TRACE_ALL, "Error in initgroups: [%d][%s]\n",
3111 : ret, strerror(ret));
3112 0 : goto fail;
3113 : }
3114 :
3115 : /* We also need to update the user's primary group, since
3116 : * the user may not be an explicit member of that group
3117 : */
3118 :
3119 0 : if (state->use_id_mapping) {
3120 0 : DEBUG(SSSDBG_TRACE_LIBS,
3121 : "Mapping primary group to unix ID\n");
3122 :
3123 : /* The primary group ID is just the RID part of the objectSID
3124 : * of the group. Generate the GID by adding this to the domain
3125 : * SID value.
3126 : */
3127 :
3128 : /* Get the user SID so we can extract the domain SID
3129 : * from it.
3130 : */
3131 0 : ret = sdap_attrs_get_sid_str(
3132 : tmp_ctx, opts->idmap_ctx, state->orig_user,
3133 0 : opts->user_map[SDAP_AT_USER_OBJECTSID].sys_name,
3134 : &sid_str);
3135 0 : if (ret != EOK) goto fail;
3136 :
3137 : /* Get the domain SID from the user SID */
3138 0 : ret = sdap_idmap_get_dom_sid_from_object(tmp_ctx, sid_str,
3139 : &dom_sid_str);
3140 0 : if (ret != EOK) {
3141 0 : DEBUG(SSSDBG_MINOR_FAILURE,
3142 : "Could not parse domain SID from [%s]\n", sid_str);
3143 0 : goto fail;
3144 : }
3145 :
3146 0 : ret = sysdb_attrs_get_uint32_t(
3147 : state->orig_user,
3148 0 : opts->user_map[SDAP_AT_USER_PRIMARY_GROUP].sys_name,
3149 : &primary_gid);
3150 0 : if (ret != EOK) {
3151 0 : DEBUG(SSSDBG_MINOR_FAILURE,
3152 : "no primary group ID provided\n");
3153 0 : ret = EINVAL;
3154 0 : goto fail;
3155 : }
3156 :
3157 : /* Add the RID to the end */
3158 0 : group_sid_str = talloc_asprintf(tmp_ctx, "%s-%lu",
3159 : dom_sid_str,
3160 : (unsigned long)primary_gid);
3161 0 : if (!group_sid_str) {
3162 0 : ret = ENOMEM;
3163 0 : goto fail;
3164 : }
3165 :
3166 : /* Convert the SID into a UNIX group ID */
3167 0 : ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, group_sid_str,
3168 : &primary_gid);
3169 0 : if (ret != EOK) goto fail;
3170 : } else {
3171 0 : ret = sysdb_attrs_get_uint32_t(state->orig_user, SYSDB_GIDNUM,
3172 : &primary_gid);
3173 0 : if (ret != EOK) {
3174 0 : DEBUG(SSSDBG_TRACE_FUNC, "Could not find user's primary GID\n");
3175 0 : goto fail;
3176 : }
3177 : }
3178 :
3179 0 : gid = talloc_asprintf(state, "%lu", (unsigned long)primary_gid);
3180 0 : if (gid == NULL) {
3181 0 : ret = ENOMEM;
3182 0 : goto fail;
3183 : }
3184 :
3185 0 : subreq = groups_get_send(req, state->ev, state->id_ctx,
3186 0 : state->id_ctx->opts->sdom, state->conn,
3187 : gid, BE_FILTER_IDNUM, BE_ATTR_ALL, false, false);
3188 0 : if (!subreq) {
3189 0 : ret = ENOMEM;
3190 0 : goto fail;
3191 : }
3192 0 : tevent_req_set_callback(subreq, sdap_get_initgr_pgid, req);
3193 :
3194 0 : talloc_free(tmp_ctx);
3195 0 : return;
3196 :
3197 : fail:
3198 0 : talloc_free(tmp_ctx);
3199 0 : tevent_req_error(req, ret);
3200 0 : return;
3201 : }
3202 :
3203 0 : static void sdap_get_initgr_pgid(struct tevent_req *subreq)
3204 : {
3205 0 : struct tevent_req *req =
3206 0 : tevent_req_callback_data(subreq, struct tevent_req);
3207 : errno_t ret;
3208 :
3209 0 : ret = groups_get_recv(subreq, NULL, NULL);
3210 0 : talloc_zfree(subreq);
3211 0 : if (ret != EOK) {
3212 0 : tevent_req_error(req, ret);
3213 0 : return;
3214 : }
3215 :
3216 0 : tevent_req_done(req);
3217 : }
3218 :
3219 0 : int sdap_get_initgr_recv(struct tevent_req *req)
3220 : {
3221 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
3222 :
3223 0 : return EOK;
3224 : }
3225 :
3226 0 : static errno_t get_sysdb_grouplist_ex(TALLOC_CTX *mem_ctx,
3227 : struct sysdb_ctx *sysdb,
3228 : struct sss_domain_info *domain,
3229 : const char *name,
3230 : char ***grouplist,
3231 : bool get_dn)
3232 : {
3233 : errno_t ret;
3234 : const char *attrs[2];
3235 : struct ldb_message *msg;
3236 : TALLOC_CTX *tmp_ctx;
3237 : struct ldb_message_element *groups;
3238 0 : char **sysdb_grouplist = NULL;
3239 : unsigned int i;
3240 :
3241 0 : attrs[0] = SYSDB_MEMBEROF;
3242 0 : attrs[1] = NULL;
3243 :
3244 0 : tmp_ctx = talloc_new(NULL);
3245 0 : if (!tmp_ctx) return ENOMEM;
3246 :
3247 0 : ret = sysdb_search_user_by_name(tmp_ctx, domain, name,
3248 : attrs, &msg);
3249 0 : if (ret != EOK) {
3250 0 : DEBUG(SSSDBG_MINOR_FAILURE,
3251 : "Error searching user [%s] by name: [%s]\n",
3252 : name, strerror(ret));
3253 0 : goto done;
3254 : }
3255 :
3256 0 : groups = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
3257 0 : if (!groups || groups->num_values == 0) {
3258 : /* No groups for this user in sysdb currently */
3259 0 : sysdb_grouplist = NULL;
3260 : } else {
3261 0 : sysdb_grouplist = talloc_array(tmp_ctx, char *, groups->num_values+1);
3262 0 : if (!sysdb_grouplist) {
3263 0 : ret = ENOMEM;
3264 0 : goto done;
3265 : }
3266 :
3267 0 : if (get_dn) {
3268 : /* Get distinguish name */
3269 0 : for (i=0; i < groups->num_values; i++) {
3270 0 : sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist,
3271 0 : (const char *)groups->values[i].data);
3272 0 : if (sysdb_grouplist[i] == NULL) {
3273 0 : ret = ENOMEM;
3274 0 : goto done;
3275 : }
3276 : }
3277 : } else {
3278 : /* Get a list of the groups by groupname only */
3279 0 : for (i=0; i < groups->num_values; i++) {
3280 0 : ret = sysdb_group_dn_name(sysdb,
3281 : sysdb_grouplist,
3282 0 : (const char *)groups->values[i].data,
3283 0 : &sysdb_grouplist[i]);
3284 0 : if (ret != EOK) {
3285 0 : DEBUG(SSSDBG_MINOR_FAILURE,
3286 : "Could not determine group name from [%s]: [%s]\n",
3287 : (const char *)groups->values[i].data, strerror(ret));
3288 0 : goto done;
3289 : }
3290 : }
3291 : }
3292 :
3293 0 : sysdb_grouplist[groups->num_values] = NULL;
3294 : }
3295 :
3296 0 : *grouplist = talloc_steal(mem_ctx, sysdb_grouplist);
3297 :
3298 : done:
3299 0 : talloc_free(tmp_ctx);
3300 0 : return ret;
3301 : }
3302 :
3303 0 : errno_t get_sysdb_grouplist(TALLOC_CTX *mem_ctx,
3304 : struct sysdb_ctx *sysdb,
3305 : struct sss_domain_info *domain,
3306 : const char *name,
3307 : char ***grouplist)
3308 : {
3309 0 : return get_sysdb_grouplist_ex(mem_ctx, sysdb, domain,
3310 : name, grouplist, false);
3311 : }
3312 :
3313 0 : errno_t get_sysdb_grouplist_dn(TALLOC_CTX *mem_ctx,
3314 : struct sysdb_ctx *sysdb,
3315 : struct sss_domain_info *domain,
3316 : const char *name,
3317 : char ***grouplist)
3318 : {
3319 0 : return get_sysdb_grouplist_ex(mem_ctx, sysdb, domain,
3320 : name, grouplist, true);
3321 : }
|