Line data Source code
1 : /*
2 : SSSD
3 :
4 : Async LDAP Helper routines - retrieving groups
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/ad/ad_common.h"
30 :
31 : /* ==Group-Parsing Routines=============================================== */
32 :
33 0 : static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx,
34 : struct sysdb_ctx *ctx,
35 : struct sss_domain_info *domain,
36 : const char *orig_dn,
37 : char **_localdn,
38 : bool *_is_group)
39 : {
40 : TALLOC_CTX *tmpctx;
41 0 : const char *attrs[] = {SYSDB_OBJECTCLASS, NULL};
42 : struct ldb_dn *base_dn;
43 : char *filter;
44 : struct ldb_message **msgs;
45 : size_t num_msgs;
46 : int ret;
47 : char *sanitized_dn;
48 : const char *objectclass;
49 :
50 0 : tmpctx = talloc_new(NULL);
51 0 : if (!tmpctx) {
52 0 : return ENOMEM;
53 : }
54 :
55 0 : ret = sss_filter_sanitize(tmpctx, orig_dn, &sanitized_dn);
56 0 : if (ret != EOK) {
57 0 : ret = ENOMEM;
58 0 : goto done;
59 : }
60 :
61 0 : filter = talloc_asprintf(tmpctx, "%s=%s", SYSDB_ORIG_DN, sanitized_dn);
62 0 : if (!filter) {
63 0 : ret = ENOMEM;
64 0 : goto done;
65 : }
66 :
67 0 : base_dn = sysdb_domain_dn(tmpctx, domain);
68 0 : if (!base_dn) {
69 0 : ret = ENOMEM;
70 0 : goto done;
71 : }
72 :
73 0 : DEBUG(SSSDBG_TRACE_ALL, "Searching cache for [%s].\n", sanitized_dn);
74 0 : ret = sysdb_search_entry(tmpctx, ctx,
75 : base_dn, LDB_SCOPE_SUBTREE, filter, attrs,
76 : &num_msgs, &msgs);
77 0 : if (ret) {
78 0 : goto done;
79 : }
80 0 : if (num_msgs != 1) {
81 0 : ret = ENOENT;
82 0 : goto done;
83 : }
84 :
85 0 : *_localdn = talloc_strdup(memctx, ldb_dn_get_linearized(msgs[0]->dn));
86 0 : if (!*_localdn) {
87 0 : ret = ENOENT;
88 0 : goto done;
89 : }
90 :
91 0 : if (_is_group != NULL) {
92 0 : objectclass = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OBJECTCLASS,
93 : NULL);
94 0 : if (objectclass == NULL) {
95 0 : DEBUG(SSSDBG_OP_FAILURE, "An antry without a %s?\n",
96 : SYSDB_OBJECTCLASS);
97 0 : ret = EINVAL;
98 0 : goto done;
99 : }
100 :
101 0 : *_is_group = strcmp(SYSDB_GROUP_CLASS, objectclass) == 0;
102 : }
103 :
104 0 : ret = EOK;
105 :
106 : done:
107 0 : talloc_zfree(tmpctx);
108 0 : return ret;
109 : }
110 :
111 : static errno_t
112 0 : sdap_get_members_with_primary_gid(TALLOC_CTX *mem_ctx,
113 : struct sss_domain_info *domain,
114 : gid_t gid, char ***_localdn, size_t *_ndn)
115 : {
116 : static const char *search_attrs[] = { SYSDB_NAME, NULL };
117 : char *filter;
118 : struct ldb_message **msgs;
119 : size_t count;
120 : size_t i;
121 : errno_t ret;
122 : char **localdn;
123 :
124 : /* Don't search if the group is non-posix */
125 0 : if (!gid) return EOK;
126 :
127 0 : filter = talloc_asprintf(mem_ctx, "(%s=%llu)", SYSDB_GIDNUM,
128 : (unsigned long long) gid);
129 0 : if (!filter) {
130 0 : return ENOMEM;
131 : }
132 :
133 0 : ret = sysdb_search_users(mem_ctx, domain, filter,
134 : search_attrs, &count, &msgs);
135 0 : talloc_free(filter);
136 0 : if (ret == ENOENT) {
137 0 : *_localdn = NULL;
138 0 : *_ndn = 0;
139 0 : return EOK;
140 0 : } else if (ret != EOK) {
141 0 : return ret;
142 : }
143 :
144 0 : localdn = talloc_array(mem_ctx, char *, count);
145 0 : if (!localdn) {
146 0 : talloc_free(msgs);
147 0 : return ENOMEM;
148 : }
149 :
150 0 : for (i=0; i < count; i++) {
151 0 : localdn[i] = talloc_strdup(localdn,
152 0 : ldb_dn_get_linearized(msgs[i]->dn));
153 0 : if (!localdn[i]) {
154 0 : talloc_free(localdn);
155 0 : talloc_free(msgs);
156 0 : return ENOMEM;
157 : }
158 : }
159 :
160 0 : talloc_free(msgs);
161 0 : *_localdn = localdn;
162 0 : *_ndn = count;
163 0 : return EOK;
164 : }
165 :
166 : static errno_t
167 0 : sdap_dn_by_primary_gid(TALLOC_CTX *mem_ctx, struct sysdb_attrs *ldap_attrs,
168 : struct sss_domain_info *domain,
169 : struct sdap_options *opts,
170 : char ***_dn_list, size_t *_count)
171 : {
172 : gid_t gid;
173 : errno_t ret;
174 :
175 0 : ret = sysdb_attrs_get_uint32_t(ldap_attrs,
176 0 : opts->group_map[SDAP_AT_GROUP_GID].sys_name,
177 : &gid);
178 0 : if (ret == ENOENT) {
179 : /* Non-posix AD group. Skip. */
180 0 : *_dn_list = NULL;
181 0 : *_count = 0;
182 0 : return EOK;
183 0 : } else if (ret && ret != ENOENT) {
184 0 : return ret;
185 : }
186 :
187 0 : ret = sdap_get_members_with_primary_gid(mem_ctx, domain, gid,
188 : _dn_list, _count);
189 0 : if (ret) return ret;
190 :
191 0 : return EOK;
192 : }
193 :
194 0 : static bool has_member(struct ldb_message_element *member_el,
195 : char *member)
196 : {
197 : struct ldb_val val;
198 :
199 0 : val.data = (uint8_t *) member;
200 0 : val.length = strlen(member);
201 :
202 : /* This is bad complexity, but the this loop should only be invoked in
203 : * the very rare scenario of AD POSIX group that is primary group of
204 : * some users but has user member attributes at the same time
205 : */
206 0 : if (ldb_msg_find_val(member_el, &val) != NULL) {
207 0 : return true;
208 : }
209 :
210 0 : return false;
211 : }
212 :
213 0 : static void link_pgroup_members(struct sysdb_attrs *group_attrs,
214 : struct ldb_message_element *member_el,
215 : char **userdns,
216 : size_t nuserdns)
217 : {
218 : int i, j;
219 :
220 0 : j = 0;
221 0 : for (i=0; i < nuserdns; i++) {
222 0 : if (has_member(member_el, userdns[i])) {
223 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
224 : "Member %s already included, skipping\n", userdns[i]);
225 0 : continue;
226 : }
227 :
228 0 : member_el->values[member_el->num_values + j].data = (uint8_t *) \
229 0 : talloc_steal(group_attrs, userdns[i]);
230 0 : member_el->values[member_el->num_values + j].length = \
231 0 : strlen(userdns[i]);
232 0 : j++;
233 : }
234 0 : member_el->num_values += j;
235 0 : }
236 :
237 0 : static int sdap_fill_memberships(struct sdap_options *opts,
238 : struct sysdb_attrs *group_attrs,
239 : struct sysdb_ctx *ctx,
240 : struct sss_domain_info *domain,
241 : hash_table_t *ghosts,
242 : struct ldb_val *values,
243 : int num_values,
244 : char **userdns,
245 : size_t nuserdns)
246 : {
247 : struct ldb_message_element *el;
248 : int i, j;
249 : int ret;
250 : errno_t hret;
251 : hash_key_t key;
252 : hash_value_t value;
253 : struct sdap_domain *sdom;
254 : struct sysdb_ctx *member_sysdb;
255 : struct sss_domain_info *member_dom;
256 :
257 0 : ret = sysdb_attrs_get_el(group_attrs, SYSDB_MEMBER, &el);
258 0 : if (ret) {
259 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_get_el failed\n");
260 0 : goto done;
261 : }
262 :
263 : /* Just allocate both big enough to contain all members for now */
264 0 : el->values = talloc_realloc(group_attrs, el->values, struct ldb_val,
265 : el->num_values + num_values + nuserdns);
266 0 : if (!el->values) {
267 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No memory to allocate group attrs\n");
268 0 : ret = ENOMEM;
269 0 : goto done;
270 : }
271 :
272 0 : j = el->num_values;
273 0 : for (i = 0; i < num_values; i++) {
274 0 : if (ghosts == NULL) {
275 0 : hret = HASH_ERROR_KEY_NOT_FOUND;
276 : } else {
277 0 : key.type = HASH_KEY_STRING;
278 0 : key.str = (char *)values[i].data;
279 0 : hret = hash_lookup(ghosts, &key, &value);
280 : }
281 :
282 0 : if (hret == HASH_ERROR_KEY_NOT_FOUND) {
283 0 : sdom = sdap_domain_get_by_dn(opts, (char *)values[i].data);
284 0 : if (sdom == NULL) {
285 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Member [%s] is it out of domain "
286 : "scope?\n", (char *)values[i].data);
287 0 : member_sysdb = ctx;
288 0 : member_dom = domain;
289 : } else {
290 0 : member_sysdb = sdom->dom->sysdb;
291 0 : member_dom = sdom->dom;
292 : }
293 :
294 : /* sync search entry with this as origDN */
295 0 : ret = sdap_find_entry_by_origDN(el->values, member_sysdb,
296 0 : member_dom, (char *)values[i].data,
297 0 : (char **)&el->values[j].data,
298 : NULL);
299 0 : if (ret == ENOENT) {
300 : /* member may be outside of the configured search bases
301 : * or out of scope of nesting limit */
302 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Member [%s] was not found in "
303 : "cache. Is it out of scope?\n", (char *)values[i].data);
304 0 : continue;
305 : }
306 0 : if (ret != EOK) {
307 0 : DEBUG(SSSDBG_MINOR_FAILURE,
308 : "'sdap_find_entry_by_origDN' failed for member [%s].\n",
309 : (char *)values[i].data);
310 0 : goto done;
311 : }
312 :
313 0 : DEBUG(SSSDBG_TRACE_LIBS, " member #%d (%s): [%s]\n",
314 : i, (char *)values[i].data,
315 : (char *)el->values[j].data);
316 :
317 0 : el->values[j].length = strlen((char *)el->values[j].data);
318 0 : j++;
319 0 : } else if (hret != HASH_SUCCESS) {
320 0 : DEBUG(SSSDBG_MINOR_FAILURE,
321 : "hash_lookup failed: [%d]: %s\n", hret, strerror(hret));
322 0 : ret = EFAULT;
323 0 : goto done;
324 : }
325 :
326 : /* If the member is in ghost table, it has
327 : * already been processed - just skip it */
328 : }
329 0 : el->num_values = j;
330 :
331 0 : link_pgroup_members(group_attrs, el, userdns, nuserdns);
332 0 : ret = EOK;
333 :
334 : done:
335 0 : return ret;
336 : }
337 :
338 : /* ==Save-Group-Entry===================================================== */
339 :
340 : /* FIXME: support non legacy */
341 : /* FIXME: support storing additional attributes */
342 :
343 : static errno_t
344 0 : sdap_store_group_with_gid(struct sss_domain_info *domain,
345 : const char *name,
346 : gid_t gid,
347 : struct sysdb_attrs *group_attrs,
348 : uint64_t cache_timeout,
349 : bool posix_group,
350 : time_t now)
351 : {
352 : errno_t ret;
353 :
354 : /* make sure that non-posix (empty or explicit gid=0) groups have the
355 : * gidNumber set to zero even if updating existing group */
356 0 : if (!posix_group) {
357 0 : ret = sysdb_attrs_add_uint32(group_attrs, SYSDB_GIDNUM, 0);
358 0 : if (ret) {
359 0 : DEBUG(SSSDBG_OP_FAILURE,
360 : "Could not set explicit GID 0 for %s\n", name);
361 0 : return ret;
362 : }
363 : }
364 :
365 0 : ret = sysdb_store_group(domain, name, gid, group_attrs,
366 : cache_timeout, now);
367 0 : if (ret) {
368 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not store group %s\n", name);
369 0 : return ret;
370 : }
371 :
372 0 : return ret;
373 : }
374 :
375 : static errno_t
376 0 : sdap_process_ghost_members(struct sysdb_attrs *attrs,
377 : struct sdap_options *opts,
378 : hash_table_t *ghosts,
379 : bool populate_members,
380 : bool store_original_member,
381 : struct sysdb_attrs *sysdb_attrs)
382 : {
383 : errno_t ret;
384 : struct ldb_message_element *gh;
385 : struct ldb_message_element *memberel;
386 : struct ldb_message_element *sysdb_memberel;
387 : struct ldb_message_element *ghostel;
388 : size_t cnt;
389 : int i;
390 : int hret;
391 : hash_key_t key;
392 : hash_value_t value;
393 :
394 0 : ret = sysdb_attrs_get_el(attrs, SYSDB_GHOST, &gh);
395 0 : if (ret != EOK) {
396 0 : DEBUG(SSSDBG_MINOR_FAILURE,
397 : "Error reading ghost attributes: [%s]\n",
398 : strerror(ret));
399 0 : return ret;
400 : }
401 :
402 0 : ret = sysdb_attrs_get_el_ext(attrs,
403 0 : opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
404 : false, &memberel);
405 0 : if (ret == ENOENT) {
406 : /* Create a dummy element with no values in order for the loop to just
407 : * fall through and make sure the attrs array is not reallocated.
408 : */
409 0 : memberel = talloc(attrs, struct ldb_message_element);
410 0 : if (memberel == NULL) {
411 0 : return ENOMEM;
412 : }
413 0 : memberel->num_values = 0;
414 0 : memberel->values = NULL;
415 0 : } else if (ret != EOK) {
416 0 : DEBUG(SSSDBG_MINOR_FAILURE,
417 : "Error reading members: [%s]\n", strerror(ret));
418 0 : return ret;
419 : }
420 :
421 0 : if (store_original_member) {
422 0 : DEBUG(SSSDBG_TRACE_FUNC, "The group has %d members\n", memberel->num_values);
423 0 : for (i = 0; i < memberel->num_values; i++) {
424 0 : ret = sysdb_attrs_add_string(sysdb_attrs, SYSDB_ORIG_MEMBER,
425 0 : (const char *) memberel->values[i].data);
426 0 : if (ret) {
427 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not add member [%s]\n",
428 : (const char *) memberel->values[i].data);
429 0 : return ret;
430 : }
431 : }
432 : }
433 :
434 0 : if (populate_members) {
435 0 : ret = sysdb_attrs_get_el(sysdb_attrs, SYSDB_MEMBER, &sysdb_memberel);
436 0 : if (ret != EOK) {
437 0 : DEBUG(SSSDBG_MINOR_FAILURE,
438 : "Error reading group members from group_attrs: [%s]\n",
439 : strerror(ret));
440 0 : return ret;
441 : }
442 0 : sysdb_memberel->values = memberel->values;
443 0 : sysdb_memberel->num_values = memberel->num_values;
444 : }
445 :
446 0 : ret = sysdb_attrs_get_el(sysdb_attrs, SYSDB_GHOST, &ghostel);
447 0 : if (ret != EOK) {
448 0 : DEBUG(SSSDBG_MINOR_FAILURE,
449 : "Error getting ghost element: [%s]\n", strerror(ret));
450 0 : return ret;
451 : }
452 0 : ghostel->values = gh->values;
453 0 : ghostel->num_values = gh->num_values;
454 :
455 0 : cnt = ghostel->num_values + memberel->num_values;
456 0 : DEBUG(SSSDBG_TRACE_FUNC, "Group has %zu members\n", cnt);
457 :
458 : /* Now process RFC2307bis ghost hash table */
459 0 : if (ghosts && cnt > 0) {
460 0 : ghostel->values = talloc_realloc(sysdb_attrs, ghostel->values,
461 : struct ldb_val, cnt);
462 0 : if (ghostel->values == NULL) {
463 0 : return ENOMEM;
464 : }
465 :
466 0 : for (i = 0; i < memberel->num_values; i++) {
467 0 : key.type = HASH_KEY_STRING;
468 0 : key.str = (char *) memberel->values[i].data;
469 0 : hret = hash_lookup(ghosts, &key, &value);
470 0 : if (hret == HASH_ERROR_KEY_NOT_FOUND) {
471 0 : continue;
472 0 : } else if (hret != HASH_SUCCESS) {
473 0 : DEBUG(SSSDBG_MINOR_FAILURE,
474 : "Error checking hash table: [%s]\n",
475 : hash_error_string(hret));
476 0 : return EFAULT;
477 : }
478 :
479 0 : DEBUG(SSSDBG_TRACE_FUNC,
480 : "Adding ghost member for group [%s]\n", (char *) value.ptr);
481 0 : ghostel->values[ghostel->num_values].data = \
482 0 : (uint8_t *) talloc_strdup(ghostel->values, value.ptr);
483 0 : if (ghostel->values[ghostel->num_values].data == NULL) {
484 0 : return ENOMEM;
485 : }
486 0 : ghostel->values[ghostel->num_values].length = strlen(value.ptr);
487 0 : ghostel->num_values++;
488 : }
489 : }
490 :
491 0 : return EOK;
492 : }
493 :
494 0 : static int sdap_save_group(TALLOC_CTX *memctx,
495 : struct sdap_options *opts,
496 : struct sss_domain_info *dom,
497 : struct sysdb_attrs *attrs,
498 : bool populate_members,
499 : bool store_original_member,
500 : hash_table_t *ghosts,
501 : char **_usn_value,
502 : time_t now)
503 : {
504 : struct ldb_message_element *el;
505 : struct sysdb_attrs *group_attrs;
506 0 : const char *group_name = NULL;
507 : gid_t gid;
508 : errno_t ret;
509 0 : char *usn_value = NULL;
510 0 : TALLOC_CTX *tmpctx = NULL;
511 : bool posix_group;
512 : bool use_id_mapping;
513 : bool need_filter;
514 : char *sid_str;
515 : struct sss_domain_info *subdomain;
516 :
517 0 : tmpctx = talloc_new(NULL);
518 0 : if (!tmpctx) {
519 0 : ret = ENOMEM;
520 0 : goto done;
521 : }
522 :
523 0 : group_attrs = sysdb_new_attrs(tmpctx);
524 0 : if (group_attrs == NULL) {
525 0 : ret = ENOMEM;
526 0 : goto done;
527 : }
528 :
529 : /* Always store SID string if available */
530 0 : ret = sdap_attrs_get_sid_str(tmpctx, opts->idmap_ctx, attrs,
531 0 : opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name,
532 : &sid_str);
533 0 : if (ret == EOK) {
534 0 : ret = sysdb_attrs_add_string(group_attrs, SYSDB_SID_STR, sid_str);
535 0 : if (ret != EOK) {
536 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not add SID string: [%s]\n",
537 : sss_strerror(ret));
538 0 : goto done;
539 : }
540 0 : } else if (ret == ENOENT) {
541 0 : DEBUG(SSSDBG_TRACE_ALL, "objectSID: not available for group [%s].\n",
542 : group_name);
543 0 : sid_str = NULL;
544 : } else {
545 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify objectSID: [%s]\n",
546 : sss_strerror(ret));
547 0 : sid_str = NULL;
548 : }
549 :
550 : /* Always store UUID if available */
551 0 : ret = sysdb_handle_original_uuid(
552 0 : opts->group_map[SDAP_AT_GROUP_UUID].def_name,
553 : attrs,
554 0 : opts->group_map[SDAP_AT_GROUP_UUID].sys_name,
555 : group_attrs, SYSDB_UUID);
556 0 : if (ret != EOK) {
557 0 : DEBUG((ret == ENOENT) ? SSSDBG_TRACE_ALL : SSSDBG_MINOR_FAILURE,
558 : "Failed to retrieve UUID [%d][%s].\n", ret, sss_strerror(ret));
559 : }
560 :
561 : /* If this object has a SID available, we will determine the correct
562 : * domain by its SID. */
563 0 : if (sid_str != NULL) {
564 0 : subdomain = sss_get_domain_by_sid_ldap_fallback(get_domains_head(dom),
565 : sid_str);
566 0 : if (subdomain) {
567 0 : dom = subdomain;
568 : } else {
569 0 : DEBUG(SSSDBG_TRACE_FUNC, "SID %s does not belong to any known "
570 : "domain\n", sid_str);
571 : }
572 : }
573 :
574 0 : ret = sdap_get_group_primary_name(tmpctx, opts, attrs, dom, &group_name);
575 0 : if (ret != EOK) {
576 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to get group name\n");
577 0 : goto done;
578 : }
579 0 : DEBUG(SSSDBG_TRACE_FUNC, "Processing group %s\n", group_name);
580 :
581 0 : posix_group = true;
582 0 : ret = sdap_check_ad_group_type(dom, opts, attrs, group_name,
583 : &need_filter);
584 0 : if (ret != EOK) {
585 0 : goto done;
586 : }
587 0 : if (need_filter) {
588 0 : posix_group = false;
589 0 : gid = 0;
590 :
591 0 : ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, false);
592 0 : if (ret != EOK) {
593 0 : DEBUG(SSSDBG_OP_FAILURE,
594 : "Error: Failed to mark group as non-posix!\n");
595 0 : goto done;
596 : }
597 : }
598 :
599 0 : if (posix_group) {
600 0 : use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx,
601 0 : dom->name,
602 : sid_str);
603 0 : if (use_id_mapping) {
604 0 : posix_group = true;
605 :
606 0 : if (sid_str == NULL) {
607 0 : DEBUG(SSSDBG_MINOR_FAILURE, "SID not available, cannot map a " \
608 : "unix ID to group [%s].\n", group_name);
609 0 : ret = ENOENT;
610 0 : goto done;
611 : }
612 :
613 0 : DEBUG(SSSDBG_TRACE_LIBS,
614 : "Mapping group [%s] objectSID [%s] to unix ID\n",
615 : group_name, sid_str);
616 :
617 : /* Convert the SID into a UNIX group ID */
618 0 : ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str, &gid);
619 0 : if (ret == ENOTSUP) {
620 : /* ENOTSUP is returned if built-in SID was provided
621 : * => do not store the group, but return EOK */
622 0 : DEBUG(SSSDBG_TRACE_FUNC, "Skipping built-in object.\n");
623 0 : ret = EOK;
624 0 : goto done;
625 0 : } else if (ret != EOK) {
626 0 : DEBUG(SSSDBG_MINOR_FAILURE,
627 : "Could not convert SID string: [%s]\n",
628 : sss_strerror(ret));
629 0 : goto done;
630 : }
631 :
632 : /* Store the GID in the ldap_attrs so it doesn't get
633 : * treated as a missing attribute from LDAP and removed.
634 : */
635 0 : ret = sdap_replace_id(attrs, SYSDB_GIDNUM, gid);
636 0 : if (ret) {
637 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot set the id-mapped GID\n");
638 0 : goto done;
639 : }
640 : } else {
641 0 : ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix_group);
642 0 : if (ret == ENOENT) {
643 0 : posix_group = true;
644 0 : } else if (ret != EOK) {
645 0 : DEBUG(SSSDBG_MINOR_FAILURE,
646 : "Error reading posix attribute: [%s]\n",
647 : sss_strerror(ret));
648 0 : goto done;
649 : }
650 :
651 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
652 : "This is%s a posix group\n", (posix_group)?"":" not");
653 0 : ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, posix_group);
654 0 : if (ret != EOK) {
655 0 : DEBUG(SSSDBG_MINOR_FAILURE,
656 : "Error setting posix attribute: [%s]\n",
657 : sss_strerror(ret));
658 0 : goto done;
659 : }
660 :
661 0 : ret = sysdb_attrs_get_uint32_t(attrs,
662 0 : opts->group_map[SDAP_AT_GROUP_GID].sys_name,
663 : &gid);
664 0 : if (ret != EOK) {
665 0 : DEBUG(SSSDBG_CRIT_FAILURE,
666 : "no gid provided for [%s] in domain [%s].\n",
667 : group_name, dom->name);
668 0 : ret = EINVAL;
669 0 : goto done;
670 : }
671 : }
672 : }
673 :
674 : /* check that the gid is valid for this domain */
675 0 : if (posix_group) {
676 0 : if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
677 0 : DEBUG(SSSDBG_MINOR_FAILURE,
678 : "Group [%s] filtered out! (id out of range)\n", group_name);
679 0 : ret = EINVAL;
680 0 : goto done;
681 : }
682 : /* Group ID OK */
683 : }
684 :
685 0 : ret = sdap_attrs_add_string(attrs, SYSDB_ORIG_DN, "original DN",
686 : group_name, group_attrs);
687 0 : if (ret != EOK) {
688 0 : DEBUG(SSSDBG_MINOR_FAILURE,
689 : "Error setting original DN: [%s]\n",
690 : sss_strerror(ret));
691 0 : goto done;
692 : }
693 :
694 0 : ret = sdap_attrs_add_string(attrs,
695 : opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name,
696 : "original mod-Timestamp",
697 : group_name, group_attrs);
698 0 : if (ret != EOK) {
699 0 : DEBUG(SSSDBG_MINOR_FAILURE,
700 : "Error setting mod timestamp: [%s]\n",
701 : sss_strerror(ret));
702 0 : goto done;
703 : }
704 :
705 0 : ret = sysdb_attrs_get_el(attrs,
706 0 : opts->group_map[SDAP_AT_GROUP_USN].sys_name, &el);
707 0 : if (ret) {
708 0 : DEBUG(SSSDBG_MINOR_FAILURE,
709 : "Error looking up group USN: [%s]\n",
710 : sss_strerror(ret));
711 0 : goto done;
712 : }
713 0 : if (el->num_values == 0) {
714 0 : DEBUG(SSSDBG_TRACE_FUNC,
715 : "Original USN value is not available for [%s].\n", group_name);
716 : } else {
717 0 : ret = sysdb_attrs_add_string(group_attrs,
718 0 : opts->group_map[SDAP_AT_GROUP_USN].sys_name,
719 0 : (const char*)el->values[0].data);
720 0 : if (ret) {
721 0 : DEBUG(SSSDBG_MINOR_FAILURE,
722 : "Error setting group USN: [%s]\n",
723 : sss_strerror(ret));
724 0 : goto done;
725 : }
726 0 : usn_value = talloc_strdup(tmpctx, (const char*)el->values[0].data);
727 0 : if (!usn_value) {
728 0 : ret = ENOMEM;
729 0 : goto done;
730 : }
731 : }
732 :
733 0 : ret = sdap_process_ghost_members(attrs, opts, ghosts,
734 : populate_members, store_original_member,
735 : group_attrs);
736 0 : if (ret != EOK) {
737 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to save ghost members\n");
738 0 : goto done;
739 : }
740 :
741 0 : ret = sdap_save_all_names(group_name, attrs, dom, group_attrs);
742 0 : if (ret != EOK) {
743 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to save group names\n");
744 0 : goto done;
745 : }
746 0 : DEBUG(SSSDBG_TRACE_FUNC, "Storing info for group %s\n", group_name);
747 :
748 0 : ret = sdap_store_group_with_gid(dom, group_name, gid, group_attrs,
749 0 : dom->group_timeout,
750 : posix_group, now);
751 0 : if (ret) {
752 0 : DEBUG(SSSDBG_MINOR_FAILURE,
753 : "Could not store group with GID: [%s]\n",
754 : sss_strerror(ret));
755 0 : goto done;
756 : }
757 :
758 0 : if (_usn_value) {
759 0 : *_usn_value = talloc_steal(memctx, usn_value);
760 : }
761 :
762 0 : talloc_steal(memctx, group_attrs);
763 0 : ret = EOK;
764 :
765 : done:
766 0 : if (ret) {
767 0 : DEBUG(SSSDBG_MINOR_FAILURE,
768 : "Failed to save group [%s]: [%s]\n",
769 : group_name ? group_name : "Unknown",
770 : sss_strerror(ret));
771 : }
772 0 : talloc_free(tmpctx);
773 0 : return ret;
774 : }
775 :
776 : static errno_t
777 0 : are_sids_from_same_dom(const char *sid1, const char *sid2, bool *_result)
778 : {
779 : size_t len_prefix_sid1;
780 : size_t len_prefix_sid2;
781 : char *rid1, *rid2;
782 : bool result;
783 :
784 0 : rid1 = strrchr(sid1, '-');
785 0 : if (rid1 == NULL) {
786 0 : return EINVAL;
787 : }
788 :
789 0 : rid2 = strrchr(sid2, '-');
790 0 : if (rid2 == NULL) {
791 0 : return EINVAL;
792 : }
793 :
794 0 : len_prefix_sid1 = rid1 - sid1;
795 0 : len_prefix_sid2 = rid2 - sid2;
796 :
797 0 : result = (len_prefix_sid1 == len_prefix_sid2) &&
798 0 : (strncmp(sid1, sid2, len_prefix_sid1) == 0);
799 :
800 0 : *_result = result;
801 :
802 0 : return EOK;
803 : }
804 :
805 : static errno_t
806 0 : retain_extern_members(TALLOC_CTX *mem_ctx,
807 : struct sss_domain_info *dom,
808 : const char *group_name,
809 : const char *group_sid,
810 : char ***_userdns,
811 : size_t *_nuserdns)
812 : {
813 : TALLOC_CTX *tmp_ctx;
814 : const char **sids, **dns;
815 : bool same_domain;
816 : errno_t ret;
817 : size_t i, n;
818 0 : size_t nuserdns = 0;
819 0 : const char **userdns = NULL;
820 :
821 0 : tmp_ctx = talloc_new(NULL);
822 0 : if (tmp_ctx == NULL) {
823 0 : return ENOMEM;
824 : }
825 :
826 0 : ret = sysdb_get_sids_of_members(tmp_ctx, dom, group_name, &sids, &dns, &n);
827 0 : if (ret != EOK) {
828 0 : if (ret != ENOENT) {
829 0 : DEBUG(SSSDBG_TRACE_ALL,
830 : "get_sids_of_members failed: %d [%s]\n",
831 : ret, sss_strerror(ret));
832 : }
833 0 : goto done;
834 : }
835 :
836 0 : for (i=0; i < n; i++) {
837 0 : ret = are_sids_from_same_dom(group_sid, sids[i], &same_domain);
838 0 : if (ret == EOK && !same_domain) {
839 0 : DEBUG(SSSDBG_TRACE_ALL, "extern member: %s\n", dns[i]);
840 0 : nuserdns++;
841 0 : userdns = talloc_realloc(tmp_ctx, userdns, const char*, nuserdns);
842 0 : if (userdns == NULL) {
843 0 : ret = ENOMEM;
844 0 : goto done;
845 : }
846 0 : userdns[nuserdns-1] = talloc_steal(userdns, dns[i]);
847 : }
848 : }
849 0 : *_nuserdns = nuserdns;
850 0 : *_userdns = discard_const(talloc_steal(mem_ctx, userdns));
851 0 : ret = EOK;
852 :
853 : done:
854 0 : talloc_free(tmp_ctx);
855 0 : return ret;
856 : }
857 :
858 : /* ==Save-Group-Memebrs=================================================== */
859 :
860 : /* FIXME: support non legacy */
861 : /* FIXME: support storing additional attributes */
862 :
863 0 : static int sdap_save_grpmem(TALLOC_CTX *memctx,
864 : struct sysdb_ctx *ctx,
865 : struct sdap_options *opts,
866 : struct sss_domain_info *dom,
867 : struct sysdb_attrs *attrs,
868 : hash_table_t *ghosts,
869 : time_t now)
870 : {
871 : struct ldb_message_element *el;
872 0 : struct sysdb_attrs *group_attrs = NULL;
873 : const char *group_sid;
874 : const char *group_name;
875 0 : char **userdns = NULL;
876 0 : size_t nuserdns = 0;
877 : int ret;
878 :
879 0 : ret = sdap_get_group_primary_name(memctx, opts, attrs, dom, &group_name);
880 0 : if (ret != EOK) {
881 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to get group name\n");
882 0 : goto fail;
883 : }
884 0 : DEBUG(SSSDBG_TRACE_FUNC, "Processing group %s\n", group_name);
885 :
886 : /* With AD we also want to merge in parent groups of primary GID as they
887 : * are reported with tokenGroups, too
888 : */
889 0 : if (opts->schema_type == SDAP_SCHEMA_AD) {
890 0 : ret = sdap_dn_by_primary_gid(memctx, attrs, dom, opts,
891 : &userdns, &nuserdns);
892 0 : if (ret != EOK) {
893 0 : DEBUG(SSSDBG_MINOR_FAILURE,
894 : "sdap_dn_by_primary_gid failed: [%d][%s].\n",
895 : ret, strerror(ret));
896 0 : goto fail;
897 : }
898 : }
899 :
900 : /* This is a temporal solution until the IPA provider is able to
901 : * resolve external group membership.
902 : * https://fedorahosted.org/sssd/ticket/2522
903 : */
904 0 : if (opts->schema_type == SDAP_SCHEMA_IPA_V1) {
905 0 : ret = sysdb_attrs_get_string(attrs, SYSDB_SID_STR, &group_sid);
906 0 : if (ret != EOK) {
907 0 : DEBUG(SSSDBG_TRACE_FUNC, "Failed to get group sid\n");
908 0 : group_sid = NULL;
909 : }
910 :
911 0 : if (group_sid != NULL) {
912 0 : ret = retain_extern_members(memctx, dom, group_name, group_sid,
913 : &userdns, &nuserdns);
914 0 : if (ret != EOK) {
915 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
916 : "retain_extern_members failed: %d:[%s].\n",
917 : ret, sss_strerror(ret));
918 : }
919 : }
920 : }
921 :
922 0 : ret = sysdb_attrs_get_el(attrs,
923 0 : opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);
924 0 : if (ret != EOK) {
925 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_get_el failed: [%d][%s].\n",
926 : ret, strerror(ret));
927 0 : goto fail;
928 : }
929 :
930 0 : if (el->num_values == 0 && nuserdns == 0) {
931 0 : DEBUG(SSSDBG_TRACE_FUNC,
932 : "No members for group [%s]\n", group_name);
933 : } else {
934 0 : DEBUG(SSSDBG_TRACE_FUNC,
935 : "Adding member users to group [%s]\n", group_name);
936 :
937 0 : group_attrs = sysdb_new_attrs(memctx);
938 0 : if (!group_attrs) {
939 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_new_attrs failed\n");
940 0 : ret = ENOMEM;
941 0 : goto fail;
942 : }
943 :
944 0 : ret = sdap_fill_memberships(opts, group_attrs, ctx, dom, ghosts,
945 0 : el->values, el->num_values,
946 : userdns, nuserdns);
947 0 : if (ret) {
948 0 : DEBUG(SSSDBG_CRIT_FAILURE,
949 : "sdap_fill_memberships failed with [%d]: %s\n", ret,
950 : strerror(ret));
951 0 : goto fail;
952 : }
953 : }
954 :
955 0 : ret = sysdb_store_group(dom, group_name, 0, group_attrs,
956 0 : dom->group_timeout, now);
957 0 : if (ret) {
958 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_store_group failed: [%d][%s].\n",
959 : ret, strerror(ret));
960 0 : goto fail;
961 : }
962 :
963 0 : return EOK;
964 :
965 : fail:
966 0 : DEBUG(SSSDBG_OP_FAILURE,
967 : "Failed to save members of group %s\n", group_name);
968 0 : return ret;
969 : }
970 :
971 :
972 : /* ==Generic-Function-to-save-multiple-groups============================= */
973 :
974 0 : static int sdap_save_groups(TALLOC_CTX *memctx,
975 : struct sysdb_ctx *sysdb,
976 : struct sss_domain_info *dom,
977 : struct sdap_options *opts,
978 : struct sysdb_attrs **groups,
979 : int num_groups,
980 : bool populate_members,
981 : hash_table_t *ghosts,
982 : bool save_orig_member,
983 : char **_usn_value)
984 : {
985 : TALLOC_CTX *tmpctx;
986 0 : char *higher_usn = NULL;
987 : char *usn_value;
988 : bool twopass;
989 0 : bool has_nesting = false;
990 : int ret;
991 : errno_t sret;
992 : int i;
993 0 : struct sysdb_attrs **saved_groups = NULL;
994 0 : int nsaved_groups = 0;
995 : time_t now;
996 0 : bool in_transaction = false;
997 :
998 0 : switch (opts->schema_type) {
999 : case SDAP_SCHEMA_RFC2307:
1000 0 : twopass = false;
1001 0 : break;
1002 :
1003 : case SDAP_SCHEMA_RFC2307BIS:
1004 : case SDAP_SCHEMA_IPA_V1:
1005 : case SDAP_SCHEMA_AD:
1006 0 : twopass = true;
1007 0 : has_nesting = true;
1008 0 : break;
1009 :
1010 : default:
1011 0 : return EINVAL;
1012 : }
1013 :
1014 0 : tmpctx = talloc_new(memctx);
1015 0 : if (!tmpctx) {
1016 0 : return ENOMEM;
1017 : }
1018 :
1019 0 : ret = sysdb_transaction_start(sysdb);
1020 0 : if (ret) {
1021 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1022 0 : goto done;
1023 : }
1024 0 : in_transaction = true;
1025 :
1026 0 : if (twopass && !populate_members) {
1027 0 : saved_groups = talloc_array(tmpctx, struct sysdb_attrs *,
1028 : num_groups);
1029 0 : if (!saved_groups) {
1030 0 : ret = ENOMEM;
1031 0 : goto done;
1032 : }
1033 : }
1034 :
1035 0 : now = time(NULL);
1036 0 : for (i = 0; i < num_groups; i++) {
1037 0 : usn_value = NULL;
1038 :
1039 : /* if 2 pass savemembers = false */
1040 0 : ret = sdap_save_group(tmpctx, opts, dom, groups[i],
1041 : populate_members,
1042 0 : has_nesting && save_orig_member,
1043 : ghosts, &usn_value, now);
1044 :
1045 : /* Do not fail completely on errors.
1046 : * Just report the failure to save and go on */
1047 0 : if (ret) {
1048 0 : DEBUG(SSSDBG_OP_FAILURE,
1049 : "Failed to store group %d. Ignoring.\n", i);
1050 : } else {
1051 0 : DEBUG(SSSDBG_TRACE_ALL, "Group %d processed!\n", i);
1052 0 : if (twopass && !populate_members) {
1053 0 : saved_groups[nsaved_groups] = groups[i];
1054 0 : nsaved_groups++;
1055 : }
1056 : }
1057 :
1058 0 : if (usn_value) {
1059 0 : if (higher_usn) {
1060 0 : if ((strlen(usn_value) > strlen(higher_usn)) ||
1061 0 : (strcmp(usn_value, higher_usn) > 0)) {
1062 0 : talloc_zfree(higher_usn);
1063 0 : higher_usn = usn_value;
1064 : } else {
1065 0 : talloc_zfree(usn_value);
1066 : }
1067 : } else {
1068 0 : higher_usn = usn_value;
1069 : }
1070 : }
1071 : }
1072 :
1073 0 : if (twopass && !populate_members) {
1074 :
1075 0 : for (i = 0; i < nsaved_groups; i++) {
1076 :
1077 0 : ret = sdap_save_grpmem(tmpctx, sysdb, opts, dom, saved_groups[i],
1078 : ghosts, now);
1079 : /* Do not fail completely on errors.
1080 : * Just report the failure to save and go on */
1081 0 : if (ret) {
1082 0 : DEBUG(SSSDBG_OP_FAILURE,
1083 : "Failed to store group %d members.\n", i);
1084 : } else {
1085 0 : DEBUG(SSSDBG_TRACE_ALL, "Group %d members processed!\n", i);
1086 : }
1087 : }
1088 : }
1089 :
1090 0 : ret = sysdb_transaction_commit(sysdb);
1091 0 : if (ret) {
1092 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
1093 0 : goto done;
1094 : }
1095 0 : in_transaction = false;
1096 :
1097 0 : if (_usn_value) {
1098 0 : *_usn_value = talloc_steal(memctx, higher_usn);
1099 : }
1100 :
1101 : done:
1102 0 : if (in_transaction) {
1103 0 : sret = sysdb_transaction_cancel(sysdb);
1104 0 : if (sret != EOK) {
1105 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
1106 : }
1107 : }
1108 0 : talloc_zfree(tmpctx);
1109 0 : return ret;
1110 : }
1111 :
1112 :
1113 : /* ==Process-Groups======================================================= */
1114 :
1115 : struct sdap_process_group_state {
1116 : struct tevent_context *ev;
1117 : struct sdap_options *opts;
1118 : struct sdap_handle *sh;
1119 : struct sss_domain_info *dom;
1120 : struct sysdb_ctx *sysdb;
1121 :
1122 : struct sysdb_attrs *group;
1123 : struct ldb_message_element* sysdb_dns;
1124 : struct ldb_message_element* ghost_dns;
1125 : char **queued_members;
1126 : int queue_len;
1127 : const char **attrs;
1128 : const char *filter;
1129 : size_t queue_idx;
1130 : size_t count;
1131 : size_t check_count;
1132 :
1133 : bool enumeration;
1134 : };
1135 :
1136 : #define GROUPMEMBER_REQ_PARALLEL 50
1137 : static void sdap_process_group_members(struct tevent_req *subreq);
1138 :
1139 : static int sdap_process_group_members_2307bis(struct tevent_req *req,
1140 : struct sdap_process_group_state *state,
1141 : struct ldb_message_element *memberel);
1142 : static int sdap_process_group_members_2307(struct sdap_process_group_state *state,
1143 : struct ldb_message_element *memberel,
1144 : struct ldb_message_element *ghostel);
1145 :
1146 0 : static errno_t sdap_process_group_create_dns(TALLOC_CTX *mem_ctx,
1147 : size_t num_values,
1148 : struct ldb_message_element **_dns)
1149 : {
1150 : struct ldb_message_element *dns;
1151 :
1152 0 : dns = talloc(mem_ctx, struct ldb_message_element);
1153 0 : if (dns == NULL) {
1154 0 : return ENOMEM;
1155 : }
1156 :
1157 0 : dns->num_values = 0;
1158 0 : dns->values = talloc_array(dns, struct ldb_val,
1159 : num_values);
1160 0 : if (dns->values == NULL) {
1161 0 : talloc_zfree(dns);
1162 0 : return ENOMEM;
1163 : }
1164 :
1165 0 : *_dns = dns;
1166 :
1167 0 : return EOK;
1168 : }
1169 :
1170 0 : struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx,
1171 : struct tevent_context *ev,
1172 : struct sss_domain_info *dom,
1173 : struct sysdb_ctx *sysdb,
1174 : struct sdap_options *opts,
1175 : struct sdap_handle *sh,
1176 : struct sysdb_attrs *group,
1177 : bool enumeration)
1178 : {
1179 : struct ldb_message_element *el;
1180 : struct ldb_message_element *ghostel;
1181 : struct sdap_process_group_state *grp_state;
1182 0 : struct tevent_req *req = NULL;
1183 : const char **attrs;
1184 : char* filter;
1185 : int ret;
1186 :
1187 0 : req = tevent_req_create(memctx, &grp_state,
1188 : struct sdap_process_group_state);
1189 0 : if (!req) return NULL;
1190 :
1191 0 : ret = build_attrs_from_map(grp_state, opts->user_map, opts->user_map_cnt,
1192 : NULL, &attrs, NULL);
1193 0 : if (ret) {
1194 0 : goto done;
1195 : }
1196 :
1197 : /* FIXME: we ignore nested rfc2307bis groups for now */
1198 0 : filter = talloc_asprintf(grp_state, "(objectclass=%s)",
1199 0 : opts->user_map[SDAP_OC_USER].name);
1200 0 : if (!filter) {
1201 0 : talloc_zfree(req);
1202 0 : return NULL;
1203 : }
1204 :
1205 0 : grp_state->ev = ev;
1206 0 : grp_state->opts = opts;
1207 0 : grp_state->dom = dom;
1208 0 : grp_state->sh = sh;
1209 0 : grp_state->sysdb = sysdb;
1210 0 : grp_state->group = group;
1211 0 : grp_state->check_count = 0;
1212 0 : grp_state->queue_idx = 0;
1213 0 : grp_state->queued_members = NULL;
1214 0 : grp_state->queue_len = 0;
1215 0 : grp_state->filter = filter;
1216 0 : grp_state->attrs = attrs;
1217 0 : grp_state->enumeration = enumeration;
1218 :
1219 0 : ret = sysdb_attrs_get_el(group,
1220 0 : opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
1221 : &el);
1222 0 : if (ret) {
1223 0 : goto done;
1224 : }
1225 :
1226 : /* Group without members */
1227 0 : if (el->num_values == 0) {
1228 0 : DEBUG(SSSDBG_OP_FAILURE, "No Members. Done!\n");
1229 0 : ret = EOK;
1230 0 : goto done;
1231 : }
1232 :
1233 0 : ret = sysdb_attrs_get_el(group,
1234 : SYSDB_GHOST,
1235 : &ghostel);
1236 0 : if (ret) {
1237 0 : goto done;
1238 : }
1239 :
1240 0 : if (ghostel->num_values == 0) {
1241 : /* Element was probably newly created, look for "member" again */
1242 0 : ret = sysdb_attrs_get_el(group,
1243 0 : opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
1244 : &el);
1245 0 : if (ret != EOK) {
1246 0 : goto done;
1247 : }
1248 : }
1249 :
1250 :
1251 0 : ret = sdap_process_group_create_dns(grp_state, el->num_values,
1252 0 : &grp_state->sysdb_dns);
1253 0 : if (ret != EOK) {
1254 0 : goto done;
1255 : }
1256 :
1257 0 : ret = sdap_process_group_create_dns(grp_state, el->num_values,
1258 0 : &grp_state->ghost_dns);
1259 0 : if (ret != EOK) {
1260 0 : goto done;
1261 : }
1262 :
1263 0 : switch (opts->schema_type) {
1264 : case SDAP_SCHEMA_RFC2307:
1265 0 : ret = sdap_process_group_members_2307(grp_state, el, ghostel);
1266 0 : break;
1267 :
1268 : case SDAP_SCHEMA_IPA_V1:
1269 : case SDAP_SCHEMA_AD:
1270 : case SDAP_SCHEMA_RFC2307BIS:
1271 : /* Note that this code branch will be used only if
1272 : * ldap_nesting_level = 0 is set in config file
1273 : */
1274 0 : ret = sdap_process_group_members_2307bis(req, grp_state, el);
1275 0 : break;
1276 :
1277 : default:
1278 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1279 : "Unknown schema type %d\n", opts->schema_type);
1280 0 : ret = EINVAL;
1281 0 : break;
1282 : }
1283 :
1284 : done:
1285 : /* We managed to process all the entries */
1286 : /* EBUSY means we need to wait for entries in LDAP */
1287 0 : if (ret == EOK) {
1288 0 : DEBUG(SSSDBG_TRACE_LIBS, "All group members processed\n");
1289 0 : tevent_req_done(req);
1290 0 : tevent_req_post(req, ev);
1291 : }
1292 :
1293 0 : if (ret != EOK && ret != EBUSY) {
1294 0 : tevent_req_error(req, ret);
1295 0 : tevent_req_post(req, ev);
1296 : }
1297 0 : return req;
1298 : }
1299 :
1300 : static int
1301 0 : sdap_process_missing_member_2307bis(struct tevent_req *req,
1302 : char *user_dn,
1303 : unsigned num_users)
1304 : {
1305 0 : struct sdap_process_group_state *grp_state =
1306 0 : tevent_req_data(req, struct sdap_process_group_state);
1307 : struct tevent_req *subreq;
1308 :
1309 : /*
1310 : * Issue at most GROUPMEMBER_REQ_PARALLEL LDAP searches at once.
1311 : * The rest is sent while the results are being processed.
1312 : * We limit the number as of request here, as the Server might
1313 : * enforce limits on the number of pending operations per
1314 : * connection.
1315 : */
1316 0 : if (grp_state->check_count > GROUPMEMBER_REQ_PARALLEL) {
1317 0 : DEBUG(SSSDBG_TRACE_LIBS, " queueing search for: %s\n", user_dn);
1318 0 : if (!grp_state->queued_members) {
1319 0 : DEBUG(SSSDBG_TRACE_LIBS,
1320 : "Allocating queue for %zu members\n",
1321 : num_users - grp_state->check_count);
1322 :
1323 0 : grp_state->queued_members = talloc_array(grp_state, char *,
1324 : num_users - grp_state->check_count + 1);
1325 0 : if (!grp_state->queued_members) {
1326 0 : return ENOMEM;
1327 : }
1328 : }
1329 0 : grp_state->queued_members[grp_state->queue_len] = user_dn;
1330 0 : grp_state->queue_len++;
1331 : } else {
1332 0 : subreq = sdap_get_generic_send(grp_state,
1333 : grp_state->ev,
1334 : grp_state->opts,
1335 : grp_state->sh,
1336 : user_dn,
1337 : LDAP_SCOPE_BASE,
1338 : grp_state->filter,
1339 : grp_state->attrs,
1340 0 : grp_state->opts->user_map,
1341 0 : grp_state->opts->user_map_cnt,
1342 0 : dp_opt_get_int(grp_state->opts->basic,
1343 : SDAP_SEARCH_TIMEOUT),
1344 : false);
1345 0 : if (!subreq) {
1346 0 : return ENOMEM;
1347 : }
1348 0 : tevent_req_set_callback(subreq, sdap_process_group_members, req);
1349 : }
1350 :
1351 0 : grp_state->check_count++;
1352 0 : return EOK;
1353 : }
1354 :
1355 : static int
1356 0 : sdap_process_group_members_2307bis(struct tevent_req *req,
1357 : struct sdap_process_group_state *state,
1358 : struct ldb_message_element *memberel)
1359 : {
1360 : char *member_dn;
1361 : char *strdn;
1362 : int ret;
1363 : int i;
1364 : int nesting_level;
1365 : bool is_group;
1366 :
1367 0 : nesting_level = dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL);
1368 :
1369 0 : for (i=0; i < memberel->num_values; i++) {
1370 0 : member_dn = (char *)memberel->values[i].data;
1371 :
1372 0 : ret = sdap_find_entry_by_origDN(state->sysdb_dns->values,
1373 : state->sysdb,
1374 : state->dom,
1375 : member_dn,
1376 : &strdn,
1377 : &is_group);
1378 :
1379 0 : if (ret == EOK) {
1380 0 : if (nesting_level == 0 && is_group) {
1381 : /* Ignore group members which are groups themselves. */
1382 0 : continue;
1383 : }
1384 :
1385 : /*
1386 : * User already cached in sysdb. Remember the sysdb DN for later
1387 : * use by sdap_save_groups()
1388 : */
1389 0 : DEBUG(SSSDBG_TRACE_LIBS, "sysdbdn: %s\n", strdn);
1390 0 : state->sysdb_dns->values[state->sysdb_dns->num_values].data =
1391 : (uint8_t*) strdn;
1392 0 : state->sysdb_dns->values[state->sysdb_dns->num_values].length =
1393 0 : strlen(strdn);
1394 0 : state->sysdb_dns->num_values++;
1395 0 : } else if (ret == ENOENT) {
1396 0 : if (!state->enumeration) {
1397 : /* The user is not in sysdb, need to add it
1398 : * We don't need to do this if we're in an enumeration,
1399 : * because all real members should all be populated
1400 : * already by the first pass of the enumeration.
1401 : * Also, we don't want to be holding the sysdb
1402 : * transaction while we're performing LDAP lookups.
1403 : */
1404 0 : DEBUG(SSSDBG_TRACE_LIBS,
1405 : "Searching LDAP for missing user entry\n");
1406 0 : ret = sdap_process_missing_member_2307bis(req,
1407 : member_dn,
1408 : memberel->num_values);
1409 0 : if (ret != EOK) {
1410 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1411 : "Error processing missing member #%d (%s):\n",
1412 : i, member_dn);
1413 0 : return ret;
1414 : }
1415 : }
1416 : } else {
1417 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1418 : "Error checking cache for member #%d (%s):\n",
1419 : i, (char *)memberel->values[i].data);
1420 0 : return ret;
1421 : }
1422 : }
1423 :
1424 0 : if (state->queue_len > 0) {
1425 0 : state->queued_members[state->queue_len]=NULL;
1426 : }
1427 :
1428 0 : if (state->check_count == 0) {
1429 : /*
1430 : * All group members are already cached in sysdb, we are done
1431 : * with this group. To avoid redundant sysdb lookups, populate the
1432 : * "member" attribute of the group entry with the sysdb DNs of
1433 : * the members.
1434 : */
1435 0 : ret = EOK;
1436 0 : memberel->values = talloc_steal(state->group, state->sysdb_dns->values);
1437 0 : memberel->num_values = state->sysdb_dns->num_values;
1438 : } else {
1439 0 : state->count = state->check_count;
1440 0 : ret = EBUSY;
1441 : }
1442 :
1443 0 : return ret;
1444 : }
1445 :
1446 : static int
1447 0 : sdap_add_group_member_2307(struct ldb_message_element *sysdb_dns,
1448 : const char *username)
1449 : {
1450 0 : sysdb_dns->values[sysdb_dns->num_values].data =
1451 0 : (uint8_t *) talloc_strdup(sysdb_dns->values, username);
1452 0 : if (sysdb_dns->values[sysdb_dns->num_values].data == NULL) {
1453 0 : return ENOMEM;
1454 : }
1455 0 : sysdb_dns->values[sysdb_dns->num_values].length =
1456 0 : strlen(username);
1457 0 : sysdb_dns->num_values++;
1458 :
1459 0 : return EOK;
1460 : }
1461 :
1462 : static int
1463 0 : sdap_process_missing_member_2307(struct sdap_process_group_state *state,
1464 : char *member_name)
1465 : {
1466 : int ret;
1467 : TALLOC_CTX *tmp_ctx;
1468 : const char *filter;
1469 : const char *username;
1470 : const char *user_dn;
1471 : size_t count;
1472 0 : struct ldb_message **msgs = NULL;
1473 : static const char *attrs[] = { SYSDB_NAME, NULL };
1474 :
1475 0 : tmp_ctx = talloc_new(NULL);
1476 0 : if (!tmp_ctx) return ENOMEM;
1477 :
1478 : /* Check for the alias in the sysdb */
1479 0 : filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME_ALIAS, member_name);
1480 0 : if (!filter) {
1481 0 : ret = ENOMEM;
1482 0 : goto done;
1483 : }
1484 :
1485 0 : ret = sysdb_search_users(tmp_ctx, state->dom, filter,
1486 : attrs, &count, &msgs);
1487 0 : if (ret == EOK && count > 0) {
1488 : /* Entry exists but the group references it with an alias. */
1489 :
1490 0 : if (count != 1) {
1491 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1492 : "More than one entry with this alias?\n");
1493 0 : ret = EIO;
1494 0 : goto done;
1495 : }
1496 :
1497 : /* fill username with primary name */
1498 0 : username = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
1499 0 : if (username == NULL) {
1500 0 : ret = EINVAL;
1501 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Inconsistent sysdb: user "
1502 : "without primary name?\n");
1503 0 : goto done;
1504 : }
1505 0 : user_dn = sysdb_user_strdn(tmp_ctx, state->dom->name, username);
1506 0 : if (user_dn == NULL) {
1507 0 : return ENOMEM;
1508 : }
1509 :
1510 0 : ret = sdap_add_group_member_2307(state->sysdb_dns, user_dn);
1511 0 : if (ret != EOK) {
1512 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not add group member %s\n", username);
1513 : }
1514 0 : } else if (ret == ENOENT || count == 0) {
1515 : /* The entry really does not exist, add a ghost */
1516 0 : DEBUG(SSSDBG_TRACE_FUNC, "Adding a ghost entry\n");
1517 0 : ret = sdap_add_group_member_2307(state->ghost_dns, member_name);
1518 0 : if (ret != EOK) {
1519 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not add group member %s\n", member_name);
1520 : }
1521 : } else {
1522 0 : ret = EIO;
1523 : }
1524 :
1525 : done:
1526 0 : talloc_free(tmp_ctx);
1527 0 : return ret;
1528 : }
1529 :
1530 : static int
1531 0 : sdap_process_group_members_2307(struct sdap_process_group_state *state,
1532 : struct ldb_message_element *memberel,
1533 : struct ldb_message_element *ghostel)
1534 : {
1535 : struct ldb_message *msg;
1536 : char *member_name;
1537 : char *userdn;
1538 : int ret;
1539 : int i;
1540 :
1541 0 : for (i=0; i < memberel->num_values; i++) {
1542 0 : member_name = (char *)memberel->values[i].data;
1543 :
1544 : /* We need to skip over zero-length usernames */
1545 0 : if (member_name[0] == '\0') continue;
1546 :
1547 0 : ret = sysdb_search_user_by_name(state, state->dom, member_name,
1548 : NULL, &msg);
1549 0 : if (ret == EOK) {
1550 : /*
1551 : * User already cached in sysdb. Remember the sysdb DN for later
1552 : * use by sdap_save_groups()
1553 : */
1554 0 : DEBUG(SSSDBG_TRACE_LIBS,
1555 : "Member already cached in sysdb: %s\n", member_name);
1556 :
1557 0 : userdn = sysdb_user_strdn(state->sysdb_dns, state->dom->name, member_name);
1558 0 : if (userdn == NULL) {
1559 0 : return ENOMEM;
1560 : }
1561 :
1562 0 : ret = sdap_add_group_member_2307(state->sysdb_dns, userdn);
1563 0 : if (ret != EOK) {
1564 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1565 : "Could not add member %s into sysdb\n", member_name);
1566 0 : goto done;
1567 : }
1568 0 : } else if (ret == ENOENT) {
1569 : /* The user is not in sysdb, need to add it */
1570 0 : DEBUG(SSSDBG_TRACE_LIBS, "member #%d (%s): not found in sysdb\n",
1571 : i, member_name);
1572 :
1573 0 : ret = sdap_process_missing_member_2307(state, member_name);
1574 0 : if (ret != EOK) {
1575 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1576 : "Error processing missing member #%d (%s):\n",
1577 : i, member_name);
1578 0 : goto done;
1579 : }
1580 : } else {
1581 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1582 : "Error checking cache for member #%d (%s):\n",
1583 : i, (char *) memberel->values[i].data);
1584 0 : goto done;
1585 : }
1586 : }
1587 :
1588 0 : ret = EOK;
1589 0 : talloc_free(memberel->values);
1590 0 : memberel->values = talloc_steal(state->group, state->sysdb_dns->values);
1591 0 : memberel->num_values = state->sysdb_dns->num_values;
1592 0 : talloc_free(ghostel->values);
1593 0 : ghostel->values = talloc_steal(state->group, state->ghost_dns->values);
1594 0 : ghostel->num_values = state->ghost_dns->num_values;
1595 :
1596 : done:
1597 0 : return ret;
1598 : }
1599 :
1600 0 : static void sdap_process_group_members(struct tevent_req *subreq)
1601 : {
1602 : struct sysdb_attrs **usr_attrs;
1603 : size_t count;
1604 : int ret;
1605 0 : struct tevent_req *req =
1606 0 : tevent_req_callback_data(subreq, struct tevent_req);
1607 0 : struct sdap_process_group_state *state =
1608 0 : tevent_req_data(req, struct sdap_process_group_state);
1609 : struct ldb_message_element *el;
1610 : uint8_t* name_string;
1611 :
1612 0 : state->check_count--;
1613 0 : DEBUG(SSSDBG_TRACE_ALL, "Members remaining: %zu\n", state->check_count);
1614 :
1615 0 : ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);
1616 0 : talloc_zfree(subreq);
1617 0 : if (ret) {
1618 0 : goto next;
1619 : }
1620 0 : if (count != 1) {
1621 0 : ret = EINVAL;
1622 0 : DEBUG(SSSDBG_TRACE_LIBS,
1623 : "Expected one user entry and got %zu\n", count);
1624 0 : goto next;
1625 : }
1626 0 : ret = sysdb_attrs_get_el(usr_attrs[0],
1627 0 : state->opts->user_map[SDAP_AT_USER_NAME].sys_name, &el);
1628 0 : if (el->num_values == 0) {
1629 0 : ret = EINVAL;
1630 : }
1631 0 : if (ret) {
1632 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to get the member's name\n");
1633 0 : goto next;
1634 : }
1635 :
1636 0 : name_string = el[0].values[0].data;
1637 0 : state->ghost_dns->values[state->ghost_dns->num_values].data =
1638 0 : talloc_steal(state->ghost_dns->values, name_string);
1639 0 : state->ghost_dns->values[state->ghost_dns->num_values].length =
1640 0 : strlen((char *)name_string);
1641 0 : state->ghost_dns->num_values++;
1642 :
1643 : next:
1644 0 : if (ret) {
1645 0 : DEBUG(SSSDBG_TRACE_FUNC,
1646 : "Error reading group member[%d]: %s. Skipping\n",
1647 : ret, strerror(ret));
1648 0 : state->count--;
1649 : }
1650 : /* Are there more searches for uncached users to submit ? */
1651 0 : if (state->queued_members && state->queued_members[state->queue_idx]) {
1652 0 : subreq = sdap_get_generic_send(state,
1653 : state->ev, state->opts, state->sh,
1654 0 : state->queued_members[state->queue_idx],
1655 : LDAP_SCOPE_BASE,
1656 : state->filter,
1657 : state->attrs,
1658 0 : state->opts->user_map,
1659 0 : state->opts->user_map_cnt,
1660 0 : dp_opt_get_int(state->opts->basic,
1661 : SDAP_SEARCH_TIMEOUT),
1662 : false);
1663 0 : if (!subreq) {
1664 0 : tevent_req_error(req, ENOMEM);
1665 0 : return;
1666 : }
1667 :
1668 0 : tevent_req_set_callback(subreq,
1669 : sdap_process_group_members, req);
1670 0 : state->queue_idx++;
1671 : }
1672 :
1673 0 : if (state->check_count == 0) {
1674 : /*
1675 : * To avoid redundant sysdb lookups, populate the "member" attribute
1676 : * of the group entry with the sysdb DNs of the members.
1677 : */
1678 0 : ret = sysdb_attrs_get_el(state->group,
1679 0 : state->opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
1680 : &el);
1681 0 : if (ret != EOK) {
1682 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1683 : "Failed to get the group member attribute [%d]: %s\n",
1684 : ret, strerror(ret));
1685 0 : tevent_req_error(req, ret);
1686 0 : return;
1687 : }
1688 0 : el->values = talloc_steal(state->group, state->sysdb_dns->values);
1689 0 : el->num_values = state->sysdb_dns->num_values;
1690 :
1691 0 : ret = sysdb_attrs_get_el(state->group, SYSDB_GHOST, &el);
1692 0 : if (ret != EOK) {
1693 0 : tevent_req_error(req, ret);
1694 0 : return;
1695 : }
1696 0 : el->values = talloc_steal(state->group, state->ghost_dns->values);
1697 0 : el->num_values = state->ghost_dns->num_values;
1698 0 : DEBUG(SSSDBG_TRACE_ALL, "Processed Group - Done\n");
1699 0 : tevent_req_done(req);
1700 : }
1701 : }
1702 :
1703 0 : static int sdap_process_group_recv(struct tevent_req *req)
1704 : {
1705 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1706 :
1707 0 : return EOK;
1708 : }
1709 :
1710 :
1711 : /* ==Search-Groups-with-filter============================================ */
1712 :
1713 : struct sdap_get_groups_state {
1714 : struct tevent_context *ev;
1715 : struct sdap_options *opts;
1716 : struct sdap_handle *sh;
1717 : struct sss_domain_info *dom;
1718 : struct sdap_domain *sdom;
1719 : struct sysdb_ctx *sysdb;
1720 : const char **attrs;
1721 : const char *base_filter;
1722 : char *filter;
1723 : int timeout;
1724 : enum sdap_entry_lookup_type lookup_type;
1725 : bool no_members;
1726 :
1727 : char *higher_usn;
1728 : struct sysdb_attrs **groups;
1729 : size_t count;
1730 : size_t check_count;
1731 :
1732 : hash_table_t *user_hash;
1733 : hash_table_t *group_hash;
1734 :
1735 : size_t base_iter;
1736 : struct sdap_search_base **search_bases;
1737 :
1738 : struct sdap_handle *ldap_sh;
1739 : struct sdap_id_op *op;
1740 : };
1741 :
1742 : static errno_t sdap_get_groups_next_base(struct tevent_req *req);
1743 : static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq);
1744 : static void sdap_get_groups_process(struct tevent_req *subreq);
1745 : static void sdap_get_groups_done(struct tevent_req *subreq);
1746 :
1747 0 : struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
1748 : struct tevent_context *ev,
1749 : struct sdap_domain *sdom,
1750 : struct sdap_options *opts,
1751 : struct sdap_handle *sh,
1752 : const char **attrs,
1753 : const char *filter,
1754 : int timeout,
1755 : enum sdap_entry_lookup_type lookup_type,
1756 : bool no_members)
1757 : {
1758 : errno_t ret;
1759 : struct tevent_req *req;
1760 : struct tevent_req *subreq;
1761 : struct sdap_get_groups_state *state;
1762 : struct ad_id_ctx *subdom_id_ctx;
1763 :
1764 0 : req = tevent_req_create(memctx, &state, struct sdap_get_groups_state);
1765 0 : if (!req) return NULL;
1766 :
1767 0 : state->ev = ev;
1768 0 : state->opts = opts;
1769 0 : state->sdom = sdom;
1770 0 : state->dom = sdom->dom;
1771 0 : state->sh = sh;
1772 0 : state->sysdb = sdom->dom->sysdb;
1773 0 : state->attrs = attrs;
1774 0 : state->higher_usn = NULL;
1775 0 : state->groups = NULL;
1776 0 : state->count = 0;
1777 0 : state->timeout = timeout;
1778 0 : state->lookup_type = lookup_type;
1779 0 : state->no_members = no_members;
1780 0 : state->base_filter = filter;
1781 0 : state->base_iter = 0;
1782 0 : state->search_bases = sdom->group_search_bases;
1783 :
1784 0 : if (!state->search_bases) {
1785 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1786 : "Group lookup request without a search base\n");
1787 0 : ret = EINVAL;
1788 0 : goto done;
1789 : }
1790 :
1791 : /* With AD by default the Global Catalog is used for lookup. But the GC
1792 : * group object might not have full group membership data. To make sure we
1793 : * connect to an LDAP server of the group's domain. */
1794 0 : if (state->opts->schema_type == SDAP_SCHEMA_AD && sdom->pvt != NULL) {
1795 0 : subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
1796 0 : state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache);
1797 0 : if (!state->op) {
1798 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
1799 0 : ret = ENOMEM;
1800 0 : goto done;
1801 : }
1802 :
1803 0 : subreq = sdap_id_op_connect_send(state->op, state, &ret);
1804 0 : if (subreq == NULL) {
1805 0 : ret = ENOMEM;
1806 0 : goto done;
1807 : }
1808 :
1809 0 : tevent_req_set_callback(subreq,
1810 : sdap_get_groups_ldap_connect_done,
1811 : req);
1812 0 : return req;
1813 : }
1814 :
1815 0 : ret = sdap_get_groups_next_base(req);
1816 :
1817 : done:
1818 0 : if (ret != EOK) {
1819 0 : tevent_req_error(req, ret);
1820 0 : tevent_req_post(req, ev);
1821 : }
1822 :
1823 0 : return req;
1824 : }
1825 :
1826 0 : static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq)
1827 : {
1828 : struct tevent_req *req;
1829 : struct sdap_get_groups_state *state;
1830 : int ret;
1831 : int dp_error;
1832 :
1833 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1834 0 : state = tevent_req_data(req, struct sdap_get_groups_state);
1835 :
1836 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
1837 0 : talloc_zfree(subreq);
1838 :
1839 0 : if (ret != EOK) {
1840 0 : tevent_req_error(req, ret);
1841 0 : return;
1842 : }
1843 :
1844 0 : state->ldap_sh = sdap_id_op_handle(state->op);
1845 :
1846 0 : ret = sdap_get_groups_next_base(req);
1847 0 : if (ret != EOK) {
1848 0 : tevent_req_error(req, ret);
1849 : }
1850 :
1851 0 : return;
1852 : }
1853 :
1854 0 : static errno_t sdap_get_groups_next_base(struct tevent_req *req)
1855 : {
1856 : struct tevent_req *subreq;
1857 : struct sdap_get_groups_state *state;
1858 0 : bool need_paging = false;
1859 0 : int sizelimit = 0;
1860 :
1861 0 : state = tevent_req_data(req, struct sdap_get_groups_state);
1862 :
1863 0 : talloc_zfree(state->filter);
1864 0 : state->filter = sdap_get_id_specific_filter(state,
1865 : state->base_filter,
1866 0 : state->search_bases[state->base_iter]->filter);
1867 0 : if (!state->filter) {
1868 0 : return ENOMEM;
1869 : }
1870 :
1871 0 : DEBUG(SSSDBG_TRACE_FUNC,
1872 : "Searching for groups with base [%s]\n",
1873 : state->search_bases[state->base_iter]->basedn);
1874 :
1875 0 : switch (state->lookup_type) {
1876 : case SDAP_LOOKUP_SINGLE:
1877 0 : break;
1878 : /* Only requests that can return multiple entries should require
1879 : * the paging control
1880 : */
1881 : case SDAP_LOOKUP_WILDCARD:
1882 0 : sizelimit = dp_opt_get_int(state->opts->basic, SDAP_WILDCARD_LIMIT);
1883 0 : need_paging = true;
1884 0 : break;
1885 : case SDAP_LOOKUP_ENUMERATE:
1886 0 : need_paging = true;
1887 0 : break;
1888 : }
1889 :
1890 0 : subreq = sdap_get_and_parse_generic_send(
1891 : state, state->ev, state->opts,
1892 0 : state->ldap_sh != NULL ? state->ldap_sh : state->sh,
1893 0 : state->search_bases[state->base_iter]->basedn,
1894 0 : state->search_bases[state->base_iter]->scope,
1895 0 : state->filter, state->attrs,
1896 0 : state->opts->group_map, SDAP_OPTS_GROUP,
1897 : 0, NULL, NULL, sizelimit, state->timeout,
1898 : need_paging);
1899 0 : if (!subreq) {
1900 0 : return ENOMEM;
1901 : }
1902 0 : tevent_req_set_callback(subreq, sdap_get_groups_process, req);
1903 :
1904 0 : return EOK;
1905 : }
1906 :
1907 : static void sdap_nested_done(struct tevent_req *req);
1908 : static void sdap_search_group_copy_batch(struct sdap_get_groups_state *state,
1909 : struct sysdb_attrs **groups,
1910 : size_t count);
1911 : static void sdap_ad_match_rule_members_process(struct tevent_req *subreq);
1912 :
1913 0 : static void sdap_get_groups_process(struct tevent_req *subreq)
1914 : {
1915 0 : struct tevent_req *req =
1916 0 : tevent_req_callback_data(subreq, struct tevent_req);
1917 0 : struct sdap_get_groups_state *state =
1918 0 : tevent_req_data(req, struct sdap_get_groups_state);
1919 : int ret;
1920 : int i;
1921 0 : bool next_base = false;
1922 : size_t count;
1923 : struct sysdb_attrs **groups;
1924 : char **groupnamelist;
1925 :
1926 0 : ret = sdap_get_and_parse_generic_recv(subreq, state,
1927 : &count, &groups);
1928 0 : talloc_zfree(subreq);
1929 0 : if (ret) {
1930 0 : tevent_req_error(req, ret);
1931 0 : return;
1932 : }
1933 :
1934 0 : DEBUG(SSSDBG_TRACE_FUNC,
1935 : "Search for groups, returned %zu results.\n", count);
1936 :
1937 0 : if (state->lookup_type == SDAP_LOOKUP_WILDCARD || \
1938 0 : state->lookup_type == SDAP_LOOKUP_ENUMERATE || \
1939 0 : count == 0) {
1940 : /* No users found in this search or looking up multiple entries */
1941 0 : next_base = true;
1942 : }
1943 :
1944 : /* Add this batch of groups to the list */
1945 0 : if (count > 0) {
1946 0 : state->groups =
1947 0 : talloc_realloc(state,
1948 : state->groups,
1949 : struct sysdb_attrs *,
1950 : state->count + count + 1);
1951 0 : if (!state->groups) {
1952 0 : tevent_req_error(req, ENOMEM);
1953 0 : return;
1954 : }
1955 :
1956 0 : sdap_search_group_copy_batch(state, groups, count);
1957 : }
1958 :
1959 0 : if (next_base) {
1960 0 : state->base_iter++;
1961 0 : if (state->search_bases[state->base_iter]) {
1962 : /* There are more search bases to try */
1963 0 : ret = sdap_get_groups_next_base(req);
1964 0 : if (ret != EOK) {
1965 0 : tevent_req_error(req, ret);
1966 : }
1967 0 : return;
1968 : }
1969 : }
1970 :
1971 : /* No more search bases
1972 : * Return ENOENT if no groups were found
1973 : */
1974 0 : if (state->count == 0) {
1975 0 : tevent_req_error(req, ENOENT);
1976 0 : return;
1977 : }
1978 :
1979 0 : if (state->no_members) {
1980 0 : ret = sysdb_attrs_primary_name_list(state->sysdb, state,
1981 : state->groups, state->count,
1982 0 : state->opts->group_map[SDAP_AT_GROUP_NAME].name,
1983 : &groupnamelist);
1984 0 : if (ret != EOK) {
1985 0 : DEBUG(SSSDBG_OP_FAILURE,
1986 : "sysdb_attrs_primary_name_list failed.\n");
1987 0 : tevent_req_error(req, ret);
1988 0 : return;
1989 : }
1990 :
1991 0 : ret = sdap_add_incomplete_groups(state->sysdb, state->dom, state->opts,
1992 : groupnamelist, state->groups,
1993 0 : state->count);
1994 0 : if (ret == EOK) {
1995 0 : DEBUG(SSSDBG_TRACE_LIBS,
1996 : "Writing only group data without members was successful.\n");
1997 0 : tevent_req_done(req);
1998 : } else {
1999 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_add_incomplete_groups failed.\n");
2000 0 : tevent_req_error(req, ret);
2001 : }
2002 0 : return;
2003 : }
2004 :
2005 : /* Check whether we need to do nested searches
2006 : * for RFC2307bis/FreeIPA/ActiveDirectory
2007 : * We don't need to do this for enumeration,
2008 : * because all groups will be picked up anyway.
2009 : *
2010 : * We can also skip this if we're using the
2011 : * LDAP_MATCHING_RULE_IN_CHAIN available in
2012 : * AD 2008 and later
2013 : */
2014 0 : if (state->lookup_type == SDAP_LOOKUP_SINGLE) {
2015 0 : if ((state->opts->schema_type != SDAP_SCHEMA_RFC2307)
2016 0 : && (dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0)
2017 0 : && !dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) {
2018 0 : subreq = sdap_nested_group_send(state, state->ev, state->sdom,
2019 : state->opts, state->sh,
2020 0 : state->groups[0]);
2021 0 : if (!subreq) {
2022 0 : tevent_req_error(req, EIO);
2023 0 : return;
2024 : }
2025 :
2026 0 : tevent_req_set_callback(subreq, sdap_nested_done, req);
2027 0 : return;
2028 : }
2029 : }
2030 :
2031 : /* We have all of the groups. Save them to the sysdb */
2032 0 : state->check_count = state->count;
2033 :
2034 : /* If we're using LDAP_MATCHING_RULE_IN_CHAIN, start a subreq to
2035 : * retrieve the members so we can save them in a single step.
2036 : */
2037 0 : if (state->lookup_type == SDAP_LOOKUP_SINGLE
2038 0 : && (state->opts->schema_type != SDAP_SCHEMA_RFC2307)
2039 0 : && state->opts->support_matching_rule
2040 0 : && dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) {
2041 0 : subreq = sdap_get_ad_match_rule_members_send(
2042 : state, state->ev, state->opts, state->sh,
2043 0 : state->groups[0], state->timeout);
2044 0 : if (!subreq) {
2045 0 : tevent_req_error(req, ENOMEM);
2046 0 : return;
2047 : }
2048 0 : tevent_req_set_callback(subreq,
2049 : sdap_ad_match_rule_members_process,
2050 : req);
2051 0 : return;
2052 : }
2053 :
2054 0 : ret = sysdb_transaction_start(state->sysdb);
2055 0 : if (ret != EOK) {
2056 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to start transaction\n");
2057 0 : tevent_req_error(req, ret);
2058 0 : return;
2059 : }
2060 :
2061 0 : if ((state->lookup_type == SDAP_LOOKUP_ENUMERATE
2062 0 : || state->lookup_type == SDAP_LOOKUP_WILDCARD)
2063 0 : && state->opts->schema_type != SDAP_SCHEMA_RFC2307
2064 0 : && dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0) {
2065 0 : DEBUG(SSSDBG_TRACE_ALL, "Saving groups without members first "
2066 : "to allow unrolling of nested groups.\n");
2067 0 : ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
2068 0 : state->groups, state->count, false,
2069 : NULL, true, NULL);
2070 0 : if (ret) {
2071 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to store groups.\n");
2072 0 : tevent_req_error(req, ret);
2073 0 : return;
2074 : }
2075 : }
2076 :
2077 0 : for (i = 0; i < state->count; i++) {
2078 0 : subreq = sdap_process_group_send(state, state->ev, state->dom,
2079 : state->sysdb, state->opts,
2080 0 : state->sh, state->groups[i],
2081 0 : state->lookup_type == SDAP_LOOKUP_ENUMERATE);
2082 :
2083 0 : if (!subreq) {
2084 0 : tevent_req_error(req, ENOMEM);
2085 0 : return;
2086 : }
2087 0 : tevent_req_set_callback(subreq, sdap_get_groups_done, req);
2088 : }
2089 : }
2090 :
2091 0 : static void sdap_search_group_copy_batch(struct sdap_get_groups_state *state,
2092 : struct sysdb_attrs **groups,
2093 : size_t count)
2094 : {
2095 : size_t copied;
2096 : bool filter;
2097 :
2098 : /* Always copy all objects for wildcard lookups. */
2099 0 : filter = state->lookup_type == SDAP_LOOKUP_SINGLE ? true : false;
2100 :
2101 0 : copied = sdap_steal_objects_in_dom(state->opts,
2102 : state->groups,
2103 : state->count,
2104 : state->dom,
2105 : groups, count, filter);
2106 :
2107 0 : state->count += copied;
2108 0 : state->groups[state->count] = NULL;
2109 0 : }
2110 :
2111 0 : static void sdap_get_groups_done(struct tevent_req *subreq)
2112 : {
2113 0 : struct tevent_req *req =
2114 0 : tevent_req_callback_data(subreq, struct tevent_req);
2115 0 : struct sdap_get_groups_state *state =
2116 0 : tevent_req_data(req, struct sdap_get_groups_state);
2117 :
2118 : int ret;
2119 : errno_t sysret;
2120 :
2121 0 : ret = sdap_process_group_recv(subreq);
2122 0 : talloc_zfree(subreq);
2123 0 : if (ret) {
2124 0 : sysret = sysdb_transaction_cancel(state->sysdb);
2125 0 : if (sysret != EOK) {
2126 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not cancel sysdb transaction\n");
2127 : }
2128 0 : tevent_req_error(req, ret);
2129 0 : return;
2130 : }
2131 :
2132 0 : state->check_count--;
2133 0 : DEBUG(SSSDBG_TRACE_ALL, "Groups remaining: %zu\n", state->check_count);
2134 :
2135 :
2136 0 : if (state->check_count == 0) {
2137 0 : DEBUG(SSSDBG_TRACE_ALL, "All groups processed\n");
2138 :
2139 : /* If ignore_group_members is set for the domain, don't update
2140 : * group memberships in the cache.
2141 : *
2142 : * If enumeration is on, don't overwrite orig_members as they've been
2143 : * saved earlier.
2144 : */
2145 0 : ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
2146 0 : state->groups, state->count,
2147 0 : !state->dom->ignore_group_members, NULL,
2148 0 : state->lookup_type == SDAP_LOOKUP_SINGLE,
2149 : &state->higher_usn);
2150 0 : if (ret) {
2151 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to store groups.\n");
2152 0 : tevent_req_error(req, ret);
2153 0 : return;
2154 : }
2155 0 : DEBUG(SSSDBG_TRACE_ALL, "Saving %zu Groups - Done\n", state->count);
2156 0 : sysret = sysdb_transaction_commit(state->sysdb);
2157 0 : if (sysret != EOK) {
2158 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Couldn't commit transaction\n");
2159 0 : tevent_req_error(req, sysret);
2160 : } else {
2161 0 : tevent_req_done(req);
2162 : }
2163 : }
2164 : }
2165 :
2166 : static errno_t sdap_nested_group_populate_users(TALLOC_CTX *mem_ctx,
2167 : struct sysdb_ctx *sysdb,
2168 : struct sss_domain_info *domain,
2169 : struct sdap_options *opts,
2170 : struct sysdb_attrs **users,
2171 : int num_users,
2172 : hash_table_t **_ghosts);
2173 :
2174 0 : static void sdap_ad_match_rule_members_process(struct tevent_req *subreq)
2175 : {
2176 : errno_t ret;
2177 0 : TALLOC_CTX *tmp_ctx = NULL;
2178 0 : struct tevent_req *req =
2179 0 : tevent_req_callback_data(subreq, struct tevent_req);
2180 0 : struct sdap_get_groups_state *state = tevent_req_data(req,
2181 : struct sdap_get_groups_state);
2182 : struct sysdb_attrs **users;
2183 0 : struct sysdb_attrs *group = state->groups[0];
2184 : struct ldb_message_element *member_el;
2185 : struct ldb_message_element *orig_dn_el;
2186 0 : size_t count = 0;
2187 : size_t i;
2188 : hash_table_t *ghosts;
2189 :
2190 0 : ret = sdap_get_ad_match_rule_members_recv(subreq, state,
2191 : &count, &users);
2192 0 : talloc_zfree(subreq);
2193 0 : if (ret != EOK && ret != ENOENT) {
2194 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2195 : "Could not retrieve members using AD match rule. [%s]\n",
2196 : strerror(ret));
2197 :
2198 0 : goto done;
2199 : }
2200 :
2201 : /* Save the group and users to the cache */
2202 :
2203 : /* Truncate the member attribute of the group.
2204 : * It will be repopulated below, and it may currently
2205 : * be incomplete anyway, thanks to the range extension.
2206 : */
2207 :
2208 0 : ret = sysdb_attrs_get_el(group, SYSDB_MEMBER, &member_el);
2209 0 : if (ret != EOK) {
2210 0 : goto done;
2211 : }
2212 :
2213 0 : member_el->num_values = 0;
2214 0 : talloc_zfree(member_el->values);
2215 :
2216 0 : tmp_ctx = talloc_new(NULL);
2217 0 : if (!tmp_ctx) {
2218 0 : ret = ENOMEM;
2219 0 : goto done;
2220 : }
2221 :
2222 : /* Figure out which users are already cached in the sysdb and
2223 : * which ones need to be added as ghost users.
2224 : */
2225 0 : ret = sdap_nested_group_populate_users(tmp_ctx, state->sysdb, state->dom,
2226 : state->opts, users, count,
2227 : &ghosts);
2228 0 : if (ret != EOK) {
2229 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2230 : "Could not determine which users are ghosts: [%s]\n",
2231 : strerror(ret));
2232 0 : goto done;
2233 : }
2234 :
2235 : /* Add any entries that aren't in the ghost hash table to the
2236 : * member element of the group. This will get converted to a
2237 : * native sysdb representation later in sdap_save_groups().
2238 : */
2239 :
2240 : /* Add all of the users as members
2241 : */
2242 0 : member_el->values = talloc_zero_array(tmp_ctx, struct ldb_val, count);
2243 0 : if (!member_el->values) {
2244 0 : ret = ENOMEM;
2245 0 : goto done;
2246 : }
2247 :
2248 : /* Copy the origDN values of the users into the member element */
2249 0 : for (i = 0; i < count; i++) {
2250 0 : ret = sysdb_attrs_get_el(users[i], SYSDB_ORIG_DN,
2251 : &orig_dn_el);
2252 0 : if (ret != EOK) {
2253 : /* This should never happen. Every entry should have
2254 : * an originalDN.
2255 : */
2256 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2257 : "BUG: Missing originalDN for user?\n");
2258 0 : goto done;
2259 : }
2260 :
2261 : /* These values will have the same lifespan, so instead
2262 : * of copying them, just point at the data.
2263 : */
2264 0 : member_el->values[i].data = orig_dn_el->values[0].data;
2265 0 : member_el->values[i].length = orig_dn_el->values[0].length;
2266 : }
2267 0 : member_el->num_values = count;
2268 :
2269 : /* Now save the group, users and ghosts to the cache */
2270 0 : ret = sdap_save_groups(tmp_ctx, state->sysdb, state->dom,
2271 : state->opts, state->groups, 1,
2272 : false, ghosts, true, NULL);
2273 0 : if (ret != EOK) {
2274 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2275 : "Could not save group to the cache: [%s]\n",
2276 : strerror(ret));
2277 0 : goto done;
2278 : }
2279 :
2280 0 : ret = EOK;
2281 :
2282 : done:
2283 0 : talloc_free(tmp_ctx);
2284 :
2285 0 : if (ret == EOK) {
2286 0 : tevent_req_done(req);
2287 : } else {
2288 0 : tevent_req_error(req, ret);
2289 : }
2290 0 : }
2291 :
2292 0 : int sdap_get_groups_recv(struct tevent_req *req,
2293 : TALLOC_CTX *mem_ctx, char **usn_value)
2294 : {
2295 0 : struct sdap_get_groups_state *state = tevent_req_data(req,
2296 : struct sdap_get_groups_state);
2297 :
2298 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2299 :
2300 0 : if (usn_value) {
2301 0 : *usn_value = talloc_steal(mem_ctx, state->higher_usn);
2302 : }
2303 :
2304 0 : return EOK;
2305 : }
2306 :
2307 0 : static void sdap_nested_done(struct tevent_req *subreq)
2308 : {
2309 : errno_t ret, tret;
2310 : unsigned long user_count;
2311 : unsigned long group_count;
2312 0 : bool in_transaction = false;
2313 0 : struct sysdb_attrs **users = NULL;
2314 0 : struct sysdb_attrs **groups = NULL;
2315 : hash_table_t *ghosts;
2316 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2317 : struct tevent_req);
2318 0 : struct sdap_get_groups_state *state = tevent_req_data(req,
2319 : struct sdap_get_groups_state);
2320 :
2321 0 : ret = sdap_nested_group_recv(state, subreq, &user_count, &users,
2322 : &group_count, &groups);
2323 0 : talloc_zfree(subreq);
2324 0 : if (ret != EOK) {
2325 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Nested group processing failed: [%d][%s]\n",
2326 : ret, strerror(ret));
2327 0 : goto fail;
2328 : }
2329 :
2330 : /* Save all of the users first so that they are in
2331 : * place for the groups to add them.
2332 : */
2333 0 : ret = sysdb_transaction_start(state->sysdb);
2334 0 : if (ret != EOK) {
2335 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
2336 0 : goto fail;
2337 : }
2338 0 : in_transaction = true;
2339 :
2340 0 : ret = sdap_nested_group_populate_users(state, state->sysdb,
2341 : state->dom, state->opts,
2342 : users, user_count, &ghosts);
2343 0 : if (ret != EOK) {
2344 0 : goto fail;
2345 : }
2346 :
2347 0 : ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
2348 : groups, group_count, false, ghosts, true,
2349 : &state->higher_usn);
2350 0 : if (ret != EOK) {
2351 0 : goto fail;
2352 : }
2353 :
2354 0 : ret = sysdb_transaction_commit(state->sysdb);
2355 0 : if (ret != EOK) {
2356 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
2357 0 : goto fail;
2358 : }
2359 0 : in_transaction = false;
2360 :
2361 : /* Processing complete */
2362 0 : tevent_req_done(req);
2363 0 : return;
2364 :
2365 : fail:
2366 0 : if (in_transaction) {
2367 0 : tret = sysdb_transaction_cancel(state->sysdb);
2368 0 : if (tret != EOK) {
2369 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
2370 : }
2371 : }
2372 0 : tevent_req_error(req, ret);
2373 : }
2374 :
2375 0 : static errno_t sdap_nested_group_populate_users(TALLOC_CTX *mem_ctx,
2376 : struct sysdb_ctx *sysdb,
2377 : struct sss_domain_info *domain,
2378 : struct sdap_options *opts,
2379 : struct sysdb_attrs **users,
2380 : int num_users,
2381 : hash_table_t **_ghosts)
2382 : {
2383 : int i;
2384 : errno_t ret, sret;
2385 : struct ldb_message_element *el;
2386 : const char *username;
2387 : char *clean_orig_dn;
2388 : const char *original_dn;
2389 : struct sss_domain_info *user_dom;
2390 : struct sdap_domain *sdap_dom;
2391 :
2392 : TALLOC_CTX *tmp_ctx;
2393 : struct ldb_message **msgs;
2394 : char *filter;
2395 : const char *sysdb_name;
2396 : struct sysdb_attrs *attrs;
2397 : static const char *search_attrs[] = { SYSDB_NAME, NULL };
2398 : hash_table_t *ghosts;
2399 : hash_key_t key;
2400 : hash_value_t value;
2401 : size_t count;
2402 0 : bool in_transaction = false;
2403 :
2404 0 : if (_ghosts == NULL) {
2405 0 : return EINVAL;
2406 : }
2407 :
2408 0 : if (num_users == 0) {
2409 : /* Nothing to do if there are no users */
2410 0 : *_ghosts = NULL;
2411 0 : return EOK;
2412 : }
2413 :
2414 0 : tmp_ctx = talloc_new(NULL);
2415 0 : if (!tmp_ctx) return ENOMEM;
2416 :
2417 0 : ret = sss_hash_create(tmp_ctx, num_users, &ghosts);
2418 0 : if (ret != HASH_SUCCESS) {
2419 0 : ret = ENOMEM;
2420 0 : goto done;
2421 : }
2422 :
2423 0 : ret = sysdb_transaction_start(sysdb);
2424 0 : if (ret) {
2425 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction!\n");
2426 0 : goto done;
2427 : }
2428 0 : in_transaction = true;
2429 :
2430 0 : for (i = 0; i < num_users; i++) {
2431 0 : ret = sysdb_attrs_get_el(users[i], SYSDB_ORIG_DN, &el);
2432 0 : if (el->num_values == 0) {
2433 0 : ret = EINVAL;
2434 : }
2435 0 : if (ret != EOK) {
2436 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2437 : "User entry %d has no originalDN attribute\n", i);
2438 0 : goto done;
2439 : }
2440 0 : original_dn = (const char *) el->values[0].data;
2441 :
2442 0 : ret = sss_filter_sanitize(tmp_ctx, original_dn,
2443 : &clean_orig_dn);
2444 0 : if (ret != EOK) {
2445 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2446 : "Cannot sanitize originalDN [%s]\n", original_dn);
2447 0 : goto done;
2448 : }
2449 :
2450 0 : sdap_dom = sdap_domain_get_by_dn(opts, original_dn);
2451 0 : user_dom = sdap_dom == NULL ? domain : sdap_dom->dom;
2452 :
2453 0 : ret = sdap_get_user_primary_name(tmp_ctx, opts, users[i],
2454 : user_dom, &username);
2455 0 : if (ret != EOK) {
2456 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2457 : "User entry %d has no name attribute. Skipping\n", i);
2458 0 : continue;
2459 : }
2460 :
2461 : /* Check for the specified origDN in the sysdb */
2462 0 : filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
2463 : SYSDB_ORIG_DN,
2464 : clean_orig_dn);
2465 0 : if (!filter) {
2466 0 : ret = ENOMEM;
2467 0 : goto done;
2468 : }
2469 0 : ret = sysdb_search_users(tmp_ctx, domain, filter,
2470 : search_attrs, &count, &msgs);
2471 0 : talloc_zfree(filter);
2472 0 : talloc_zfree(clean_orig_dn);
2473 0 : if (ret != EOK && ret != ENOENT) {
2474 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error checking cache for user entry\n");
2475 0 : goto done;
2476 0 : } else if (ret == EOK) {
2477 : /* The entry is cached but expired. Update the username
2478 : * if needed. */
2479 0 : if (count != 1) {
2480 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2481 : "More than one entry with this origDN? Skipping\n");
2482 0 : continue;
2483 : }
2484 :
2485 0 : sysdb_name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
2486 0 : if (strcmp(sysdb_name, username) == 0) {
2487 : /* Username is correct, continue */
2488 0 : continue;
2489 : }
2490 :
2491 0 : attrs = sysdb_new_attrs(tmp_ctx);
2492 0 : if (!attrs) {
2493 0 : ret = ENOMEM;
2494 0 : goto done;
2495 : }
2496 :
2497 0 : ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, username);
2498 0 : if (ret) goto done;
2499 0 : ret = sysdb_set_entry_attr(user_dom->sysdb, msgs[0]->dn, attrs,
2500 : SYSDB_MOD_REP);
2501 0 : if (ret != EOK) goto done;
2502 : } else {
2503 0 : key.type = HASH_KEY_STRING;
2504 0 : key.str = talloc_steal(ghosts, discard_const(original_dn));
2505 0 : value.type = HASH_VALUE_PTR;
2506 0 : value.ptr = talloc_steal(ghosts, discard_const(username));
2507 0 : ret = hash_enter(ghosts, &key, &value);
2508 0 : if (ret != HASH_SUCCESS) {
2509 0 : talloc_free(key.str);
2510 0 : talloc_free(value.ptr);
2511 0 : ret = ENOMEM;
2512 0 : goto done;
2513 : }
2514 : }
2515 : }
2516 :
2517 0 : ret = sysdb_transaction_commit(sysdb);
2518 0 : if (ret) {
2519 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
2520 0 : goto done;
2521 : }
2522 0 : in_transaction = false;
2523 :
2524 0 : ret = EOK;
2525 : done:
2526 0 : if (in_transaction) {
2527 0 : sret = sysdb_transaction_cancel(sysdb);
2528 0 : if (sret != EOK) {
2529 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
2530 : }
2531 : }
2532 :
2533 0 : if (ret != EOK) {
2534 0 : *_ghosts = NULL;
2535 : } else {
2536 0 : *_ghosts = talloc_steal(mem_ctx, ghosts);
2537 : }
2538 0 : talloc_zfree(tmp_ctx);
2539 0 : return ret;
2540 : }
|