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