Line data Source code
1 : /*
2 : SSSD
3 :
4 : Async LDAP Helper routines - retrieving users
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 : #define REALM_SEPARATOR '@'
32 :
33 0 : static void make_realm_upper_case(const char *upn)
34 : {
35 : char *c;
36 :
37 0 : c = strchr(upn, REALM_SEPARATOR);
38 0 : if (c == NULL) {
39 0 : DEBUG(SSSDBG_TRACE_ALL, "No realm delimiter found in upn [%s].\n", upn);
40 0 : return;
41 : }
42 :
43 0 : while(*(++c) != '\0') {
44 0 : c[0] = toupper(*c);
45 : }
46 :
47 0 : return;
48 : }
49 :
50 : /* ==Save-User-Entry====================================================== */
51 :
52 : static errno_t
53 0 : sdap_get_idmap_primary_gid(struct sdap_options *opts,
54 : struct sysdb_attrs *attrs,
55 : char *sid_str,
56 : char *dom_sid_str,
57 : gid_t *_gid)
58 : {
59 : errno_t ret;
60 0 : TALLOC_CTX *tmpctx = NULL;
61 : gid_t gid, primary_gid;
62 : char *group_sid_str;
63 :
64 0 : tmpctx = talloc_new(NULL);
65 0 : if (!tmpctx) {
66 0 : ret = ENOMEM;
67 0 : goto done;
68 : }
69 :
70 0 : ret = sysdb_attrs_get_uint32_t(attrs,
71 0 : opts->user_map[SDAP_AT_USER_PRIMARY_GROUP].sys_name,
72 : &primary_gid);
73 0 : if (ret != EOK) {
74 0 : DEBUG(SSSDBG_MINOR_FAILURE, "no primary group ID provided\n");
75 0 : ret = EINVAL;
76 0 : goto done;
77 : }
78 :
79 : /* The primary group ID is just the RID part of the objectSID
80 : * of the group. Generate the GID by adding this to the domain
81 : * SID value.
82 : */
83 :
84 : /* First, get the domain SID if we didn't do so above */
85 0 : if (!dom_sid_str) {
86 0 : ret = sdap_idmap_get_dom_sid_from_object(tmpctx, sid_str,
87 : &dom_sid_str);
88 0 : if (ret != EOK) {
89 0 : DEBUG(SSSDBG_MINOR_FAILURE,
90 : "Could not parse domain SID from [%s]\n", sid_str);
91 0 : goto done;
92 : }
93 : }
94 :
95 : /* Add the RID to the end */
96 0 : group_sid_str = talloc_asprintf(tmpctx, "%s-%lu", dom_sid_str,
97 : (unsigned long) primary_gid);
98 0 : if (!group_sid_str) {
99 0 : ret = ENOMEM;
100 0 : goto done;
101 : }
102 :
103 : /* Convert the SID into a UNIX group ID */
104 0 : ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, group_sid_str, &gid);
105 0 : if (ret != EOK) goto done;
106 :
107 0 : ret = EOK;
108 0 : *_gid = gid;
109 : done:
110 0 : talloc_free(tmpctx);
111 0 : return ret;
112 : }
113 :
114 : /* FIXME: support storing additional attributes */
115 0 : int sdap_save_user(TALLOC_CTX *memctx,
116 : struct sdap_options *opts,
117 : struct sss_domain_info *dom,
118 : struct sysdb_attrs *attrs,
119 : char **_usn_value,
120 : time_t now)
121 : {
122 : struct ldb_message_element *el;
123 : int ret;
124 0 : const char *user_name = NULL;
125 0 : const char *fullname = NULL;
126 : const char *pwd;
127 : const char *gecos;
128 : const char *homedir;
129 : const char *shell;
130 0 : const char *orig_dn = NULL;
131 : uid_t uid;
132 : gid_t gid;
133 : struct sysdb_attrs *user_attrs;
134 0 : char *upn = NULL;
135 : size_t i;
136 : int cache_timeout;
137 0 : char *usn_value = NULL;
138 0 : char **missing = NULL;
139 0 : TALLOC_CTX *tmpctx = NULL;
140 : bool use_id_mapping;
141 : char *sid_str;
142 0 : char *dom_sid_str = NULL;
143 : struct sss_domain_info *subdomain;
144 :
145 0 : DEBUG(SSSDBG_TRACE_FUNC, "Save user\n");
146 :
147 0 : tmpctx = talloc_new(NULL);
148 0 : if (!tmpctx) {
149 0 : ret = ENOMEM;
150 0 : goto done;
151 : }
152 :
153 0 : user_attrs = sysdb_new_attrs(tmpctx);
154 0 : if (user_attrs == NULL) {
155 0 : ret = ENOMEM;
156 0 : goto done;
157 : }
158 :
159 : /* Always store SID string if available */
160 0 : ret = sdap_attrs_get_sid_str(tmpctx, opts->idmap_ctx, attrs,
161 0 : opts->user_map[SDAP_AT_USER_OBJECTSID].sys_name,
162 : &sid_str);
163 0 : if (ret == EOK) {
164 0 : ret = sysdb_attrs_add_string(user_attrs, SYSDB_SID_STR, sid_str);
165 0 : if (ret != EOK) {
166 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not add SID string: [%s]\n",
167 : sss_strerror(ret));
168 0 : goto done;
169 : }
170 0 : } else if (ret == ENOENT) {
171 0 : DEBUG(SSSDBG_TRACE_ALL, "objectSID: not available for user\n");
172 0 : sid_str = NULL;
173 : } else {
174 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify objectSID: [%s]\n",
175 : sss_strerror(ret));
176 0 : sid_str = NULL;
177 : }
178 :
179 : /* Always store UUID if available */
180 0 : ret = sysdb_handle_original_uuid(opts->user_map[SDAP_AT_USER_UUID].def_name,
181 : attrs,
182 0 : opts->user_map[SDAP_AT_USER_UUID].sys_name,
183 : user_attrs, SYSDB_UUID);
184 0 : if (ret != EOK) {
185 0 : DEBUG((ret == ENOENT) ? SSSDBG_TRACE_ALL : SSSDBG_MINOR_FAILURE,
186 : "Failed to retrieve UUID [%d][%s].\n", ret, sss_strerror(ret));
187 : }
188 :
189 : /* If this object has a SID available, we will determine the correct
190 : * domain by its SID. */
191 0 : if (sid_str != NULL) {
192 0 : subdomain = find_domain_by_sid(get_domains_head(dom), sid_str);
193 0 : if (subdomain) {
194 0 : dom = subdomain;
195 : } else {
196 0 : DEBUG(SSSDBG_TRACE_FUNC, "SID %s does not belong to any known "
197 : "domain\n", sid_str);
198 : }
199 : }
200 :
201 0 : ret = sdap_get_user_primary_name(memctx, opts, attrs, dom, &user_name);
202 0 : if (ret != EOK) {
203 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to get user name\n");
204 0 : goto done;
205 : }
206 0 : DEBUG(SSSDBG_TRACE_FUNC, "Processing user %s\n", user_name);
207 :
208 0 : if (opts->schema_type == SDAP_SCHEMA_AD) {
209 0 : ret = sysdb_attrs_get_string(attrs,
210 0 : opts->user_map[SDAP_AT_USER_FULLNAME].sys_name, &fullname);
211 0 : if (ret == EOK) {
212 0 : ret = sysdb_attrs_add_string(user_attrs, SYSDB_FULLNAME, fullname);
213 0 : if (ret != EOK) {
214 0 : goto done;
215 : }
216 0 : } else if (ret != ENOENT) {
217 0 : goto done;
218 : }
219 : }
220 :
221 0 : ret = sysdb_attrs_get_el(attrs,
222 0 : opts->user_map[SDAP_AT_USER_PWD].sys_name, &el);
223 0 : if (ret) goto done;
224 0 : if (el->num_values == 0) pwd = NULL;
225 0 : else pwd = (const char *)el->values[0].data;
226 :
227 0 : ret = sysdb_attrs_get_el(attrs,
228 0 : opts->user_map[SDAP_AT_USER_GECOS].sys_name, &el);
229 0 : if (ret) goto done;
230 0 : if (el->num_values == 0) gecos = NULL;
231 0 : else gecos = (const char *)el->values[0].data;
232 :
233 0 : if (!gecos) {
234 : /* Fall back to the user's full name */
235 0 : ret = sysdb_attrs_get_el(
236 : attrs,
237 0 : opts->user_map[SDAP_AT_USER_FULLNAME].sys_name, &el);
238 0 : if (ret) goto done;
239 0 : if (el->num_values > 0) gecos = (const char *)el->values[0].data;
240 : }
241 :
242 0 : ret = sysdb_attrs_get_el(attrs,
243 0 : opts->user_map[SDAP_AT_USER_HOME].sys_name, &el);
244 0 : if (ret) goto done;
245 0 : if (el->num_values == 0) homedir = NULL;
246 0 : else homedir = (const char *)el->values[0].data;
247 :
248 0 : ret = sysdb_attrs_get_el(attrs,
249 0 : opts->user_map[SDAP_AT_USER_SHELL].sys_name, &el);
250 0 : if (ret) goto done;
251 0 : if (el->num_values == 0) shell = NULL;
252 0 : else shell = (const char *)el->values[0].data;
253 :
254 0 : use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx,
255 0 : dom->name,
256 : sid_str);
257 :
258 : /* Retrieve or map the UID as appropriate */
259 0 : if (use_id_mapping) {
260 :
261 0 : if (sid_str == NULL) {
262 0 : DEBUG(SSSDBG_MINOR_FAILURE, "SID not available, cannot map a " \
263 : "unix ID to user [%s].\n", user_name);
264 0 : ret = ENOENT;
265 0 : goto done;
266 : }
267 :
268 0 : DEBUG(SSSDBG_TRACE_LIBS,
269 : "Mapping user [%s] objectSID [%s] to unix ID\n", user_name, sid_str);
270 :
271 : /* Convert the SID into a UNIX user ID */
272 0 : ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str, &uid);
273 0 : if (ret == ENOTSUP) {
274 0 : DEBUG(SSSDBG_TRACE_FUNC, "Skipping built-in object.\n");
275 0 : ret = EOK;
276 0 : goto done;
277 0 : } else if (ret != EOK) {
278 0 : goto done;
279 : }
280 :
281 : /* Store the UID in the ldap_attrs so it doesn't get
282 : * treated as a missing attribute from LDAP and removed.
283 : */
284 0 : ret = sdap_replace_id(attrs, SYSDB_UIDNUM, uid);
285 0 : if (ret) {
286 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot set the id-mapped UID\n");
287 0 : goto done;
288 : }
289 : } else {
290 0 : ret = sysdb_attrs_get_uint32_t(attrs,
291 0 : opts->user_map[SDAP_AT_USER_UID].sys_name,
292 : &uid);
293 0 : if (ret != EOK) {
294 0 : DEBUG(SSSDBG_CRIT_FAILURE,
295 : "no uid provided for [%s] in domain [%s].\n",
296 : user_name, dom->name);
297 0 : ret = EINVAL;
298 0 : goto done;
299 : }
300 : }
301 : /* check that the uid is valid for this domain */
302 0 : if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) {
303 0 : DEBUG(SSSDBG_OP_FAILURE,
304 : "User [%s] filtered out! (uid out of range)\n",
305 : user_name);
306 0 : ret = EINVAL;
307 0 : goto done;
308 : }
309 :
310 0 : if (use_id_mapping) {
311 0 : ret = sdap_get_idmap_primary_gid(opts, attrs, sid_str, dom_sid_str,
312 : &gid);
313 0 : if (ret) {
314 0 : DEBUG(SSSDBG_CRIT_FAILURE,
315 : "Cannot get the GID for [%s] in domain [%s].\n",
316 : user_name, dom->name);
317 0 : goto done;
318 : }
319 :
320 0 : if (IS_SUBDOMAIN(dom)) {
321 : /* For subdomain users, only create the private group as
322 : * the subdomain is an MPG domain.
323 : * But we have to save the GID of the original primary group
324 : * becasuse otherwise this information might be lost because
325 : * typically (Unix and AD) the user is not listed in his primary
326 : * group as a member.
327 : */
328 0 : ret = sysdb_attrs_add_uint32(user_attrs, SYSDB_PRIMARY_GROUP_GIDNUM,
329 : (uint32_t) gid);
330 0 : if (ret != EOK) {
331 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_uint32 failed.\n");
332 0 : goto done;
333 : }
334 :
335 0 : gid = 0;
336 : }
337 :
338 : /* Store the GID in the ldap_attrs so it doesn't get
339 : * treated as a missing attribute from LDAP and removed.
340 : */
341 0 : ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid);
342 0 : if (ret != EOK) goto done;
343 : } else {
344 0 : ret = sysdb_attrs_get_uint32_t(attrs,
345 0 : opts->user_map[SDAP_AT_USER_GID].sys_name,
346 : &gid);
347 0 : if (ret != EOK) {
348 0 : DEBUG(SSSDBG_CRIT_FAILURE,
349 : "no gid provided for [%s] in domain [%s].\n",
350 : user_name, dom->name);
351 0 : ret = EINVAL;
352 0 : goto done;
353 : }
354 : }
355 :
356 : /* check that the gid is valid for this domain */
357 0 : if (IS_SUBDOMAIN(dom) == false &&
358 0 : OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
359 0 : DEBUG(SSSDBG_CRIT_FAILURE,
360 : "User [%s] filtered out! (primary gid out of range)\n",
361 : user_name);
362 0 : ret = EINVAL;
363 0 : goto done;
364 : }
365 :
366 0 : ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
367 0 : if (ret) {
368 0 : goto done;
369 : }
370 0 : if (!el || el->num_values == 0) {
371 0 : DEBUG(SSSDBG_MINOR_FAILURE,
372 : "originalDN is not available for [%s].\n", user_name);
373 : } else {
374 0 : orig_dn = (const char *) el->values[0].data;
375 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Adding originalDN [%s] to attributes "
376 : "of [%s].\n", orig_dn, user_name);
377 :
378 0 : ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_DN, orig_dn);
379 0 : if (ret) {
380 0 : goto done;
381 : }
382 : }
383 :
384 0 : ret = sysdb_attrs_get_el(attrs, SYSDB_MEMBEROF, &el);
385 0 : if (ret) {
386 0 : goto done;
387 : }
388 0 : if (el->num_values == 0) {
389 0 : DEBUG(SSSDBG_TRACE_FUNC,
390 : "Original memberOf is not available for [%s].\n", user_name);
391 : } else {
392 0 : DEBUG(SSSDBG_TRACE_FUNC,
393 : "Adding original memberOf attributes to [%s].\n", user_name);
394 0 : for (i = 0; i < el->num_values; i++) {
395 0 : ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
396 0 : (const char *) el->values[i].data);
397 0 : if (ret) {
398 0 : goto done;
399 : }
400 : }
401 : }
402 :
403 0 : ret = sdap_attrs_add_string(attrs,
404 : opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name,
405 : "original mod-Timestamp",
406 : user_name, user_attrs);
407 0 : if (ret != EOK) {
408 0 : goto done;
409 : }
410 :
411 0 : ret = sysdb_attrs_get_el(attrs,
412 0 : opts->user_map[SDAP_AT_USER_USN].sys_name, &el);
413 0 : if (ret) {
414 0 : goto done;
415 : }
416 0 : if (el->num_values == 0) {
417 0 : DEBUG(SSSDBG_TRACE_FUNC,
418 : "Original USN value is not available for [%s].\n", user_name);
419 : } else {
420 0 : ret = sysdb_attrs_add_string(user_attrs,
421 0 : opts->user_map[SDAP_AT_USER_USN].sys_name,
422 0 : (const char*)el->values[0].data);
423 0 : if (ret) {
424 0 : goto done;
425 : }
426 0 : usn_value = talloc_strdup(tmpctx, (const char*)el->values[0].data);
427 0 : if (!usn_value) {
428 0 : ret = ENOMEM;
429 0 : goto done;
430 : }
431 : }
432 :
433 0 : ret = sysdb_attrs_get_el(attrs,
434 0 : opts->user_map[SDAP_AT_USER_PRINC].sys_name, &el);
435 0 : if (ret) {
436 0 : goto done;
437 : }
438 0 : if (el->num_values == 0) {
439 0 : DEBUG(SSSDBG_TRACE_FUNC,
440 : "User principal is not available for [%s].\n", user_name);
441 : } else {
442 0 : upn = talloc_strdup(user_attrs, (const char*) el->values[0].data);
443 0 : if (!upn) {
444 0 : ret = ENOMEM;
445 0 : goto done;
446 : }
447 0 : if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
448 0 : make_realm_upper_case(upn);
449 : }
450 0 : DEBUG(SSSDBG_TRACE_FUNC,
451 : "Adding user principal [%s] to attributes of [%s].\n",
452 : upn, user_name);
453 0 : ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);
454 0 : if (ret) {
455 0 : goto done;
456 : }
457 : }
458 :
459 0 : for (i = SDAP_FIRST_EXTRA_USER_AT; i < opts->user_map_cnt; i++) {
460 0 : ret = sdap_attrs_add_list(attrs, opts->user_map[i].sys_name,
461 : NULL, user_name, user_attrs);
462 0 : if (ret) {
463 0 : goto done;
464 : }
465 : }
466 :
467 0 : cache_timeout = dom->user_timeout;
468 :
469 0 : ret = sdap_save_all_names(user_name, attrs, dom, user_attrs);
470 0 : if (ret != EOK) {
471 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to save user names\n");
472 0 : goto done;
473 : }
474 :
475 : /* Make sure that any attributes we requested from LDAP that we
476 : * did not receive are also removed from the sysdb
477 : */
478 0 : ret = list_missing_attrs(user_attrs, opts->user_map, opts->user_map_cnt,
479 : attrs, &missing);
480 0 : if (ret != EOK) {
481 0 : goto done;
482 : }
483 :
484 0 : DEBUG(SSSDBG_TRACE_FUNC, "Storing info for user %s\n", user_name);
485 :
486 0 : ret = sysdb_store_user(dom, user_name, pwd, uid, gid,
487 : gecos, homedir, shell, orig_dn,
488 : user_attrs, missing, cache_timeout, now);
489 0 : if (ret) goto done;
490 :
491 0 : if (_usn_value) {
492 0 : *_usn_value = talloc_steal(memctx, usn_value);
493 : }
494 :
495 0 : talloc_steal(memctx, user_attrs);
496 0 : ret = EOK;
497 :
498 : done:
499 0 : if (ret) {
500 0 : DEBUG(SSSDBG_CRIT_FAILURE,
501 : "Failed to save user [%s]\n",
502 : user_name ? user_name : "Unknown");
503 : }
504 0 : talloc_free(tmpctx);
505 0 : return ret;
506 : }
507 :
508 :
509 : /* ==Generic-Function-to-save-multiple-users============================= */
510 :
511 0 : int sdap_save_users(TALLOC_CTX *memctx,
512 : struct sysdb_ctx *sysdb,
513 : struct sss_domain_info *dom,
514 : struct sdap_options *opts,
515 : struct sysdb_attrs **users,
516 : int num_users,
517 : char **_usn_value)
518 : {
519 : TALLOC_CTX *tmpctx;
520 0 : char *higher_usn = NULL;
521 : char *usn_value;
522 : int ret;
523 : errno_t sret;
524 : int i;
525 : time_t now;
526 0 : bool in_transaction = false;
527 :
528 0 : if (num_users == 0) {
529 : /* Nothing to do if there are no users */
530 0 : return EOK;
531 : }
532 :
533 0 : tmpctx = talloc_new(memctx);
534 0 : if (!tmpctx) {
535 0 : return ENOMEM;
536 : }
537 :
538 0 : ret = sysdb_transaction_start(sysdb);
539 0 : if (ret) {
540 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
541 0 : goto done;
542 : }
543 0 : in_transaction = true;
544 :
545 0 : now = time(NULL);
546 0 : for (i = 0; i < num_users; i++) {
547 0 : usn_value = NULL;
548 :
549 0 : ret = sdap_save_user(tmpctx, opts, dom, users[i], &usn_value, now);
550 :
551 : /* Do not fail completely on errors.
552 : * Just report the failure to save and go on */
553 0 : if (ret) {
554 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to store user %d. Ignoring.\n", i);
555 : } else {
556 0 : DEBUG(SSSDBG_TRACE_ALL, "User %d processed!\n", i);
557 : }
558 :
559 0 : if (usn_value) {
560 0 : if (higher_usn) {
561 0 : if ((strlen(usn_value) > strlen(higher_usn)) ||
562 0 : (strcmp(usn_value, higher_usn) > 0)) {
563 0 : talloc_zfree(higher_usn);
564 0 : higher_usn = usn_value;
565 : } else {
566 0 : talloc_zfree(usn_value);
567 : }
568 : } else {
569 0 : higher_usn = usn_value;
570 : }
571 : }
572 : }
573 :
574 0 : ret = sysdb_transaction_commit(sysdb);
575 0 : if (ret) {
576 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
577 0 : goto done;
578 : }
579 0 : in_transaction = false;
580 :
581 0 : if (_usn_value) {
582 0 : *_usn_value = talloc_steal(memctx, higher_usn);
583 : }
584 :
585 : done:
586 0 : if (in_transaction) {
587 0 : sret = sysdb_transaction_cancel(sysdb);
588 0 : if (sret != EOK) {
589 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
590 : }
591 : }
592 0 : talloc_zfree(tmpctx);
593 0 : return ret;
594 : }
595 :
596 :
597 : /* ==Search-Users-with-filter============================================= */
598 :
599 : struct sdap_search_user_state {
600 : struct tevent_context *ev;
601 : struct sdap_options *opts;
602 : struct sdap_handle *sh;
603 : struct sss_domain_info *dom;
604 :
605 : const char **attrs;
606 : const char *base_filter;
607 : const char *filter;
608 : int timeout;
609 : enum sdap_entry_lookup_type lookup_type;
610 :
611 : char *higher_usn;
612 : struct sysdb_attrs **users;
613 : size_t count;
614 :
615 : size_t base_iter;
616 : struct sdap_search_base **search_bases;
617 : };
618 :
619 : static errno_t sdap_search_user_next_base(struct tevent_req *req);
620 : static void sdap_search_user_copy_batch(struct sdap_search_user_state *state,
621 : struct sysdb_attrs **users,
622 : size_t count);
623 : static void sdap_search_user_process(struct tevent_req *subreq);
624 :
625 0 : struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
626 : struct tevent_context *ev,
627 : struct sss_domain_info *dom,
628 : struct sdap_options *opts,
629 : struct sdap_search_base **search_bases,
630 : struct sdap_handle *sh,
631 : const char **attrs,
632 : const char *filter,
633 : int timeout,
634 : enum sdap_entry_lookup_type lookup_type)
635 : {
636 : errno_t ret;
637 : struct tevent_req *req;
638 : struct sdap_search_user_state *state;
639 :
640 0 : req = tevent_req_create(memctx, &state, struct sdap_search_user_state);
641 0 : if (req == NULL) return NULL;
642 :
643 0 : state->ev = ev;
644 0 : state->opts = opts;
645 0 : state->dom = dom;
646 0 : state->sh = sh;
647 0 : state->attrs = attrs;
648 0 : state->higher_usn = NULL;
649 0 : state->users = NULL;
650 0 : state->count = 0;
651 0 : state->timeout = timeout;
652 0 : state->base_filter = filter;
653 0 : state->base_iter = 0;
654 0 : state->search_bases = search_bases;
655 0 : state->lookup_type = lookup_type;
656 :
657 0 : if (!state->search_bases) {
658 0 : DEBUG(SSSDBG_CRIT_FAILURE,
659 : "User lookup request without a search base\n");
660 0 : ret = EINVAL;
661 0 : goto done;
662 : }
663 :
664 0 : ret = sdap_search_user_next_base(req);
665 :
666 : done:
667 0 : if (ret != EOK) {
668 0 : tevent_req_error(req, ret);
669 0 : tevent_req_post(req, state->ev);
670 : }
671 :
672 0 : return req;
673 : }
674 :
675 0 : static errno_t sdap_search_user_next_base(struct tevent_req *req)
676 : {
677 : struct tevent_req *subreq;
678 : struct sdap_search_user_state *state;
679 0 : bool need_paging = false;
680 0 : int sizelimit = 0;
681 :
682 0 : state = tevent_req_data(req, struct sdap_search_user_state);
683 :
684 0 : talloc_zfree(state->filter);
685 0 : state->filter = sdap_get_id_specific_filter(state,
686 : state->base_filter,
687 0 : state->search_bases[state->base_iter]->filter);
688 0 : if (state->filter == NULL) {
689 0 : return ENOMEM;
690 : }
691 :
692 0 : DEBUG(SSSDBG_TRACE_FUNC,
693 : "Searching for users with base [%s]\n",
694 : state->search_bases[state->base_iter]->basedn);
695 :
696 0 : switch (state->lookup_type) {
697 : case SDAP_LOOKUP_SINGLE:
698 0 : break;
699 : /* Only requests that can return multiple entries should require
700 : * the paging control
701 : */
702 : case SDAP_LOOKUP_WILDCARD:
703 0 : sizelimit = dp_opt_get_int(state->opts->basic, SDAP_WILDCARD_LIMIT);
704 0 : need_paging = true;
705 0 : break;
706 : case SDAP_LOOKUP_ENUMERATE:
707 0 : need_paging = true;
708 0 : break;
709 : }
710 :
711 0 : subreq = sdap_get_and_parse_generic_send(
712 : state, state->ev, state->opts, state->sh,
713 0 : state->search_bases[state->base_iter]->basedn,
714 0 : state->search_bases[state->base_iter]->scope,
715 : state->filter, state->attrs,
716 0 : state->opts->user_map, state->opts->user_map_cnt,
717 : 0, NULL, NULL, sizelimit, state->timeout,
718 : need_paging);
719 0 : if (subreq == NULL) {
720 0 : return ENOMEM;
721 : }
722 0 : tevent_req_set_callback(subreq, sdap_search_user_process, req);
723 :
724 0 : return EOK;
725 : }
726 :
727 0 : static void sdap_search_user_process(struct tevent_req *subreq)
728 : {
729 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
730 : struct tevent_req);
731 0 : struct sdap_search_user_state *state = tevent_req_data(req,
732 : struct sdap_search_user_state);
733 : int ret;
734 : size_t count;
735 : struct sysdb_attrs **users;
736 0 : bool next_base = false;
737 :
738 0 : ret = sdap_get_and_parse_generic_recv(subreq, state,
739 : &count, &users);
740 0 : talloc_zfree(subreq);
741 0 : if (ret) {
742 0 : tevent_req_error(req, ret);
743 0 : return;
744 : }
745 :
746 0 : DEBUG(SSSDBG_TRACE_FUNC,
747 : "Search for users, returned %zu results.\n", count);
748 :
749 0 : if (state->lookup_type == SDAP_LOOKUP_WILDCARD || \
750 0 : state->lookup_type == SDAP_LOOKUP_ENUMERATE || \
751 0 : count == 0) {
752 : /* No users found in this search or looking up multiple entries */
753 0 : next_base = true;
754 : }
755 :
756 : /* Add this batch of users to the list */
757 0 : if (count > 0) {
758 0 : state->users =
759 0 : talloc_realloc(state,
760 : state->users,
761 : struct sysdb_attrs *,
762 : state->count + count + 1);
763 0 : if (!state->users) {
764 0 : tevent_req_error(req, ENOMEM);
765 0 : return;
766 : }
767 :
768 0 : sdap_search_user_copy_batch(state, users, count);
769 : }
770 :
771 0 : if (next_base) {
772 0 : state->base_iter++;
773 0 : if (state->search_bases[state->base_iter]) {
774 : /* There are more search bases to try */
775 0 : ret = sdap_search_user_next_base(req);
776 0 : if (ret != EOK) {
777 0 : tevent_req_error(req, ret);
778 : }
779 0 : return;
780 : }
781 : }
782 :
783 : /* No more search bases
784 : * Return ENOENT if no users were found
785 : */
786 0 : if (state->count == 0) {
787 0 : tevent_req_error(req, ENOENT);
788 0 : return;
789 : }
790 :
791 0 : DEBUG(SSSDBG_TRACE_ALL, "Retrieved total %zu users\n", state->count);
792 0 : tevent_req_done(req);
793 : }
794 :
795 0 : static void sdap_search_user_copy_batch(struct sdap_search_user_state *state,
796 : struct sysdb_attrs **users,
797 : size_t count)
798 : {
799 : size_t copied;
800 : bool filter;
801 :
802 : /* Always copy all objects for wildcard lookups. */
803 0 : filter = state->lookup_type == SDAP_LOOKUP_SINGLE ? true : false;
804 :
805 0 : copied = sdap_steal_objects_in_dom(state->opts,
806 : state->users,
807 : state->count,
808 : state->dom,
809 : users, count, filter);
810 :
811 0 : state->count += copied;
812 0 : state->users[state->count] = NULL;
813 0 : }
814 :
815 0 : int sdap_search_user_recv(TALLOC_CTX *memctx, struct tevent_req *req,
816 : char **higher_usn, struct sysdb_attrs ***users,
817 : size_t *count)
818 : {
819 0 : struct sdap_search_user_state *state = tevent_req_data(req,
820 : struct sdap_search_user_state);
821 :
822 0 : if (higher_usn) {
823 0 : *higher_usn = talloc_steal(memctx, state->higher_usn);
824 : }
825 :
826 0 : if (users) {
827 0 : *users = talloc_steal(memctx, state->users);
828 : }
829 :
830 0 : if (count) {
831 0 : *count = state->count;
832 : }
833 :
834 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
835 :
836 0 : return EOK;
837 : }
838 :
839 : /* ==Search-And-Save-Users-with-filter============================================= */
840 : struct sdap_get_users_state {
841 : struct sysdb_ctx *sysdb;
842 : struct sdap_options *opts;
843 : struct sss_domain_info *dom;
844 :
845 : char *higher_usn;
846 : struct sysdb_attrs **users;
847 : size_t count;
848 : };
849 :
850 : static void sdap_get_users_done(struct tevent_req *subreq);
851 :
852 0 : struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
853 : struct tevent_context *ev,
854 : struct sss_domain_info *dom,
855 : struct sysdb_ctx *sysdb,
856 : struct sdap_options *opts,
857 : struct sdap_search_base **search_bases,
858 : struct sdap_handle *sh,
859 : const char **attrs,
860 : const char *filter,
861 : int timeout,
862 : enum sdap_entry_lookup_type lookup_type)
863 : {
864 : errno_t ret;
865 : struct tevent_req *req;
866 : struct tevent_req *subreq;
867 : struct sdap_get_users_state *state;
868 :
869 0 : req = tevent_req_create(memctx, &state, struct sdap_get_users_state);
870 0 : if (!req) return NULL;
871 :
872 0 : state->sysdb = sysdb;
873 0 : state->opts = opts;
874 0 : state->dom = dom;
875 :
876 0 : subreq = sdap_search_user_send(state, ev, dom, opts, search_bases,
877 : sh, attrs, filter, timeout, lookup_type);
878 0 : if (subreq == NULL) {
879 0 : ret = ENOMEM;
880 0 : goto done;
881 : }
882 0 : tevent_req_set_callback(subreq, sdap_get_users_done, req);
883 :
884 0 : ret = EOK;
885 : done:
886 0 : if (ret != EOK) {
887 0 : tevent_req_error(req, ret);
888 0 : tevent_req_post(req, ev);
889 : }
890 :
891 0 : return req;
892 : }
893 :
894 0 : static void sdap_get_users_done(struct tevent_req *subreq)
895 : {
896 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
897 : struct tevent_req);
898 0 : struct sdap_get_users_state *state = tevent_req_data(req,
899 : struct sdap_get_users_state);
900 : int ret;
901 :
902 0 : ret = sdap_search_user_recv(state, subreq, &state->higher_usn,
903 : &state->users, &state->count);
904 0 : if (ret) {
905 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to retrieve users\n");
906 0 : tevent_req_error(req, ret);
907 0 : return;
908 : }
909 :
910 0 : ret = sdap_save_users(state, state->sysdb,
911 : state->dom, state->opts,
912 0 : state->users, state->count,
913 : &state->higher_usn);
914 0 : if (ret) {
915 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to store users.\n");
916 0 : tevent_req_error(req, ret);
917 0 : return;
918 : }
919 :
920 0 : DEBUG(SSSDBG_TRACE_ALL, "Saving %zu Users - Done\n", state->count);
921 :
922 0 : tevent_req_done(req);
923 : }
924 :
925 0 : int sdap_get_users_recv(struct tevent_req *req,
926 : TALLOC_CTX *mem_ctx, char **usn_value)
927 : {
928 0 : struct sdap_get_users_state *state = tevent_req_data(req,
929 : struct sdap_get_users_state);
930 :
931 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
932 :
933 0 : if (usn_value) {
934 0 : *usn_value = talloc_steal(mem_ctx, state->higher_usn);
935 : }
936 :
937 0 : return EOK;
938 : }
939 :
940 : /* ==Fetch-Fallback-local-user============================================ */
941 :
942 0 : errno_t sdap_fallback_local_user(TALLOC_CTX *memctx,
943 : const char *name, uid_t uid,
944 : struct sysdb_attrs ***reply)
945 : {
946 : struct sysdb_attrs **ua;
947 : struct sysdb_attrs *user;
948 : struct passwd *pwd;
949 : int ret;
950 :
951 0 : if (name) {
952 0 : pwd = getpwnam(name);
953 : } else {
954 0 : pwd = getpwuid(uid);
955 : }
956 :
957 0 : if (!pwd) {
958 0 : return errno ? errno : ENOENT;
959 : }
960 :
961 0 : ua = talloc_array(memctx, struct sysdb_attrs *, 2);
962 0 : if (!ua) {
963 0 : ret = ENOMEM;
964 0 : goto done;
965 : }
966 0 : ua[1] = NULL;
967 :
968 0 : user = sysdb_new_attrs(ua);
969 0 : if (!user) {
970 0 : ret = ENOMEM;
971 0 : goto done;
972 : }
973 0 : ua[0] = user;
974 :
975 0 : ret = sysdb_attrs_add_string(user, SYSDB_NAME, pwd->pw_name);
976 0 : if (ret != EOK) {
977 0 : goto done;
978 : }
979 :
980 0 : if (pwd->pw_passwd) {
981 0 : ret = sysdb_attrs_add_string(user, SYSDB_PWD, pwd->pw_passwd);
982 0 : if (ret != EOK) {
983 0 : goto done;
984 : }
985 : }
986 :
987 0 : ret = sysdb_attrs_add_long(user, SYSDB_UIDNUM, (long)pwd->pw_uid);
988 0 : if (ret != EOK) {
989 0 : goto done;
990 : }
991 :
992 0 : ret = sysdb_attrs_add_long(user, SYSDB_GIDNUM, (long)pwd->pw_gid);
993 0 : if (ret != EOK) {
994 0 : goto done;
995 : }
996 :
997 0 : if (pwd->pw_gecos) {
998 0 : ret = sysdb_attrs_add_string(user, SYSDB_GECOS, pwd->pw_gecos);
999 0 : if (ret != EOK) {
1000 0 : goto done;
1001 : }
1002 : }
1003 :
1004 0 : if (pwd->pw_dir) {
1005 0 : ret = sysdb_attrs_add_string(user, SYSDB_HOMEDIR, pwd->pw_dir);
1006 0 : if (ret != EOK) {
1007 0 : goto done;
1008 : }
1009 : }
1010 :
1011 0 : if (pwd->pw_shell) {
1012 0 : ret = sysdb_attrs_add_string(user, SYSDB_SHELL, pwd->pw_shell);
1013 0 : if (ret != EOK) {
1014 0 : goto done;
1015 : }
1016 : }
1017 :
1018 : done:
1019 0 : if (ret != EOK) {
1020 0 : talloc_free(ua);
1021 : } else {
1022 0 : *reply = ua;
1023 : }
1024 :
1025 0 : return ret;
1026 : }
|