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