Line data Source code
1 : /*
2 : SSSD
3 :
4 : System Database
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "util/util.h"
23 : #include "db/sysdb_private.h"
24 : #include "db/sysdb_services.h"
25 : #include "db/sysdb_autofs.h"
26 : #include "util/crypto/sss_crypto.h"
27 : #include "util/cert.h"
28 : #include <time.h>
29 :
30 1452 : int add_string(struct ldb_message *msg, int flags,
31 : const char *attr, const char *value)
32 : {
33 : int ret;
34 :
35 1452 : ret = ldb_msg_add_empty(msg, attr, flags, NULL);
36 1452 : if (ret == LDB_SUCCESS) {
37 1452 : ret = ldb_msg_add_string(msg, attr, value);
38 1452 : if (ret == LDB_SUCCESS) return EOK;
39 : }
40 0 : return ENOMEM;
41 : }
42 :
43 931 : int add_ulong(struct ldb_message *msg, int flags,
44 : const char *attr, unsigned long value)
45 : {
46 : int ret;
47 :
48 931 : ret = ldb_msg_add_empty(msg, attr, flags, NULL);
49 931 : if (ret == LDB_SUCCESS) {
50 931 : ret = ldb_msg_add_fmt(msg, attr, "%lu", value);
51 931 : if (ret == LDB_SUCCESS) return EOK;
52 : }
53 0 : return ENOMEM;
54 : }
55 :
56 24 : static uint32_t get_attr_as_uint32(struct ldb_message *msg, const char *attr)
57 : {
58 24 : const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr);
59 : long long int l;
60 :
61 24 : if (!v || !v->data) {
62 0 : return 0;
63 : }
64 :
65 24 : errno = 0;
66 24 : l = strtoll((const char *)v->data, NULL, 10);
67 24 : if (errno) {
68 0 : return (uint32_t)-1;
69 : }
70 :
71 24 : if (l < 0 || l > ((uint32_t)(-1))) {
72 0 : return (uint32_t)-1;
73 : }
74 :
75 24 : return l;
76 : }
77 :
78 : /*
79 : * The wrapper around ldb_modify that uses LDB_CONTROL_PERMISSIVE_MODIFY_OID
80 : * so that on adds entries that already exist are skipped and similarly
81 : * entries that are missing are ignored on deletes
82 : *
83 : * Please note this function returns LDB error codes, not sysdb error
84 : * codes on purpose, see usage in callers!
85 : */
86 35 : int sss_ldb_modify_permissive(struct ldb_context *ldb,
87 : struct ldb_message *msg)
88 : {
89 : struct ldb_request *req;
90 35 : int ret = EOK;
91 :
92 35 : ret = ldb_build_mod_req(&req, ldb, ldb,
93 : msg,
94 : NULL,
95 : NULL,
96 : ldb_op_default_callback,
97 : NULL);
98 :
99 35 : if (ret != LDB_SUCCESS) return ret;
100 :
101 35 : ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID,
102 : false, NULL);
103 35 : if (ret != LDB_SUCCESS) {
104 0 : talloc_free(req);
105 0 : return ret;
106 : }
107 :
108 35 : ret = ldb_request(ldb, req);
109 35 : if (ret == LDB_SUCCESS) {
110 35 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
111 : }
112 :
113 35 : talloc_free(req);
114 :
115 : /* Please note this function returns LDB error codes, not sysdb error
116 : * codes on purpose, see usage in callers!
117 : */
118 35 : return ret;
119 : }
120 :
121 : #define ERROR_OUT(v, r, l) do { v = r; goto l; } while(0)
122 :
123 :
124 : /* =Remove-Entry-From-Sysdb=============================================== */
125 :
126 299 : int sysdb_delete_entry(struct sysdb_ctx *sysdb,
127 : struct ldb_dn *dn,
128 : bool ignore_not_found)
129 : {
130 : int ret;
131 :
132 299 : ret = ldb_delete(sysdb->ldb, dn);
133 299 : switch (ret) {
134 : case LDB_SUCCESS:
135 299 : return EOK;
136 : case LDB_ERR_NO_SUCH_OBJECT:
137 0 : if (ignore_not_found) {
138 0 : return EOK;
139 : }
140 : /* fall through */
141 : default:
142 0 : DEBUG(SSSDBG_CRIT_FAILURE, "LDB Error: %s(%d)\nError Message: [%s]\n",
143 : ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb));
144 0 : return sysdb_error_to_errno(ret);
145 : }
146 : }
147 :
148 : /* =Remove-Subentries-From-Sysdb=========================================== */
149 :
150 6 : int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
151 : struct ldb_dn *dn,
152 : bool ignore_not_found)
153 : {
154 6 : const char *no_attrs[] = { NULL };
155 : struct ldb_message **msgs;
156 : size_t msgs_count;
157 : int ret;
158 : int i;
159 : TALLOC_CTX *tmp_ctx;
160 :
161 6 : tmp_ctx = talloc_new(NULL);
162 6 : if (!tmp_ctx) {
163 0 : return ENOMEM;
164 : }
165 :
166 6 : ret = ldb_transaction_start(sysdb->ldb);
167 6 : if (ret) {
168 0 : ret = sysdb_error_to_errno(ret);
169 0 : goto done;
170 : }
171 :
172 6 : ret = sysdb_search_entry(tmp_ctx, sysdb, dn,
173 : LDB_SCOPE_SUBTREE, "(distinguishedName=*)",
174 : no_attrs, &msgs_count, &msgs);
175 6 : if (ret) {
176 0 : if (ignore_not_found && ret == ENOENT) {
177 0 : ret = EOK;
178 : }
179 0 : if (ret) {
180 0 : DEBUG(SSSDBG_TRACE_FUNC, "Search error: %d (%s)\n",
181 : ret, strerror(ret));
182 : }
183 0 : goto done;
184 : }
185 :
186 6 : DEBUG(SSSDBG_TRACE_ALL, "Found [%zu] items to delete.\n", msgs_count);
187 :
188 6 : qsort(msgs, msgs_count,
189 : sizeof(struct ldb_message *), compare_ldb_dn_comp_num);
190 :
191 30 : for (i = 0; i < msgs_count; i++) {
192 24 : DEBUG(SSSDBG_TRACE_ALL, "Trying to delete [%s].\n",
193 : ldb_dn_get_linearized(msgs[i]->dn));
194 :
195 24 : ret = sysdb_delete_entry(sysdb, msgs[i]->dn, false);
196 24 : if (ret) {
197 0 : goto done;
198 : }
199 : }
200 :
201 : done:
202 6 : if (ret == EOK) {
203 6 : ret = ldb_transaction_commit(sysdb->ldb);
204 6 : ret = sysdb_error_to_errno(ret);
205 : } else {
206 0 : ldb_transaction_cancel(sysdb->ldb);
207 : }
208 6 : talloc_free(tmp_ctx);
209 6 : return ret;
210 : }
211 :
212 :
213 : /* =Search-Entry========================================================== */
214 :
215 2038 : int sysdb_search_entry(TALLOC_CTX *mem_ctx,
216 : struct sysdb_ctx *sysdb,
217 : struct ldb_dn *base_dn,
218 : enum ldb_scope scope,
219 : const char *filter,
220 : const char **attrs,
221 : size_t *_msgs_count,
222 : struct ldb_message ***_msgs)
223 : {
224 : TALLOC_CTX *tmp_ctx;
225 : struct ldb_result *res;
226 : int ret;
227 :
228 2038 : tmp_ctx = talloc_new(NULL);
229 2038 : if (tmp_ctx == NULL) {
230 0 : ret = ENOMEM;
231 0 : goto done;
232 : }
233 :
234 2038 : ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
235 : base_dn, scope, attrs,
236 : filter?"%s":NULL, filter);
237 2038 : if (ret != EOK) {
238 0 : ret = sysdb_error_to_errno(ret);
239 0 : goto done;
240 : }
241 :
242 2038 : *_msgs_count = res->count;
243 2038 : *_msgs = talloc_steal(mem_ctx, res->msgs);
244 :
245 2038 : if (res->count == 0) {
246 970 : ret = ENOENT;
247 970 : goto done;
248 : }
249 :
250 : done:
251 2038 : talloc_zfree(tmp_ctx);
252 2038 : return ret;
253 : }
254 :
255 : /* =Search-Entry-by-SID-string============================================ */
256 :
257 8 : int sysdb_search_entry_by_sid_str(TALLOC_CTX *mem_ctx,
258 : struct sss_domain_info *domain,
259 : const char *search_base,
260 : const char *filter_str,
261 : const char *sid_str,
262 : const char **attrs,
263 : struct ldb_message **msg)
264 : {
265 : TALLOC_CTX *tmp_ctx;
266 8 : const char *def_attrs[] = { SYSDB_NAME, SYSDB_SID_STR, NULL };
267 8 : struct ldb_message **msgs = NULL;
268 : struct ldb_dn *basedn;
269 8 : size_t msgs_count = 0;
270 : char *filter;
271 : int ret;
272 :
273 8 : tmp_ctx = talloc_new(NULL);
274 8 : if (!tmp_ctx) {
275 0 : return ENOMEM;
276 : }
277 :
278 8 : basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
279 : search_base, domain->name);
280 8 : if (!basedn) {
281 0 : ret = ENOMEM;
282 0 : goto done;
283 : }
284 :
285 8 : filter = talloc_asprintf(tmp_ctx, filter_str, sid_str);
286 8 : if (!filter) {
287 0 : ret = ENOMEM;
288 0 : goto done;
289 : }
290 :
291 8 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_SUBTREE,
292 : filter, attrs?attrs:def_attrs, &msgs_count,
293 : &msgs);
294 8 : if (ret) {
295 5 : goto done;
296 : }
297 :
298 3 : *msg = talloc_steal(mem_ctx, msgs[0]);
299 :
300 : done:
301 8 : if (ret == ENOENT) {
302 5 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
303 : }
304 3 : else if (ret) {
305 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
306 : }
307 :
308 8 : talloc_zfree(tmp_ctx);
309 8 : return ret;
310 : }
311 :
312 : /* =Search-User-by-[UID/SID/NAME]============================================= */
313 :
314 : enum sysdb_obj_type {
315 : SYSDB_UNKNOWN = 0,
316 : SYSDB_USER,
317 : SYSDB_GROUP
318 : };
319 :
320 575 : static int sysdb_search_by_name(TALLOC_CTX *mem_ctx,
321 : struct sss_domain_info *domain,
322 : const char *name,
323 : enum sysdb_obj_type type,
324 : const char **attrs,
325 : struct ldb_message **msg)
326 : {
327 : TALLOC_CTX *tmp_ctx;
328 575 : const char *def_attrs[] = { SYSDB_NAME, NULL, NULL };
329 575 : const char *base_tmpl = NULL;
330 575 : const char *filter_tmpl = NULL;
331 575 : struct ldb_message **msgs = NULL;
332 : struct ldb_dn *basedn;
333 575 : size_t msgs_count = 0;
334 : char *sanitized_name;
335 : char *lc_sanitized_name;
336 : char *filter;
337 : int ret;
338 :
339 575 : switch (type) {
340 : case SYSDB_USER:
341 352 : def_attrs[1] = SYSDB_UIDNUM;
342 352 : base_tmpl = SYSDB_TMPL_USER_BASE;
343 352 : filter_tmpl = SYSDB_PWNAM_FILTER;
344 352 : break;
345 : case SYSDB_GROUP:
346 223 : def_attrs[1] = SYSDB_GIDNUM;
347 223 : base_tmpl = SYSDB_TMPL_GROUP_BASE;
348 223 : filter_tmpl = SYSDB_GRNAM_FILTER;
349 223 : break;
350 : default:
351 0 : return EINVAL;
352 : }
353 :
354 575 : tmp_ctx = talloc_new(NULL);
355 575 : if (!tmp_ctx) {
356 0 : return ENOMEM;
357 : }
358 :
359 575 : basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
360 : base_tmpl, domain->name);
361 575 : if (!basedn) {
362 0 : ret = ENOMEM;
363 0 : goto done;
364 : }
365 :
366 575 : ret = sss_filter_sanitize_for_dom(tmp_ctx, name, domain, &sanitized_name,
367 : &lc_sanitized_name);
368 575 : if (ret != EOK) {
369 0 : goto done;
370 : }
371 :
372 575 : filter = talloc_asprintf(tmp_ctx, filter_tmpl, lc_sanitized_name,
373 : sanitized_name, sanitized_name);
374 575 : if (!filter) {
375 0 : ret = ENOMEM;
376 0 : goto done;
377 : }
378 :
379 575 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_SUBTREE,
380 : filter, attrs?attrs:def_attrs,
381 : &msgs_count, &msgs);
382 575 : if (ret) {
383 382 : goto done;
384 : }
385 :
386 193 : *msg = talloc_steal(mem_ctx, msgs[0]);
387 :
388 : done:
389 575 : if (ret == ENOENT) {
390 382 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
391 : }
392 193 : else if (ret) {
393 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
394 : }
395 575 : talloc_zfree(tmp_ctx);
396 575 : return ret;
397 : }
398 :
399 352 : int sysdb_search_user_by_name(TALLOC_CTX *mem_ctx,
400 : struct sss_domain_info *domain,
401 : const char *name,
402 : const char **attrs,
403 : struct ldb_message **msg)
404 : {
405 352 : return sysdb_search_by_name(mem_ctx, domain, name, SYSDB_USER, attrs, msg);
406 : }
407 :
408 192 : int sysdb_search_user_by_uid(TALLOC_CTX *mem_ctx,
409 : struct sss_domain_info *domain,
410 : uid_t uid,
411 : const char **attrs,
412 : struct ldb_message **msg)
413 : {
414 : TALLOC_CTX *tmp_ctx;
415 192 : const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL };
416 192 : struct ldb_message **msgs = NULL;
417 : struct ldb_dn *basedn;
418 192 : size_t msgs_count = 0;
419 : char *filter;
420 : int ret;
421 :
422 192 : tmp_ctx = talloc_new(NULL);
423 192 : if (!tmp_ctx) {
424 0 : return ENOMEM;
425 : }
426 :
427 192 : basedn = sysdb_user_base_dn(tmp_ctx, domain);
428 192 : if (!basedn) {
429 0 : ret = ENOMEM;
430 0 : goto done;
431 : }
432 :
433 192 : filter = talloc_asprintf(tmp_ctx, SYSDB_PWUID_FILTER, (unsigned long)uid);
434 192 : if (!filter) {
435 0 : ret = ENOMEM;
436 0 : goto done;
437 : }
438 :
439 : /* Use SUBTREE scope here, not ONELEVEL
440 : * There is a bug in LDB that makes ONELEVEL searches extremely
441 : * slow (it ignores indexing)
442 : */
443 192 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn,
444 : LDB_SCOPE_SUBTREE, filter,
445 : attrs?attrs:def_attrs, &msgs_count, &msgs);
446 192 : if (ret) {
447 169 : goto done;
448 : }
449 :
450 23 : *msg = talloc_steal(mem_ctx, msgs[0]);
451 :
452 : done:
453 192 : if (ret == ENOENT) {
454 169 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
455 : }
456 23 : else if (ret) {
457 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
458 : }
459 :
460 192 : talloc_zfree(tmp_ctx);
461 192 : return ret;
462 : }
463 :
464 5 : int sysdb_search_user_by_sid_str(TALLOC_CTX *mem_ctx,
465 : struct sss_domain_info *domain,
466 : const char *sid_str,
467 : const char **attrs,
468 : struct ldb_message **msg)
469 : {
470 :
471 5 : return sysdb_search_entry_by_sid_str(mem_ctx, domain,
472 : SYSDB_TMPL_USER_BASE,
473 : SYSDB_PWSID_FILTER,
474 : sid_str, attrs, msg);
475 : }
476 :
477 40 : int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx,
478 : struct sss_domain_info *domain,
479 : const char *upn,
480 : const char **attrs,
481 : struct ldb_result **out_res)
482 : {
483 : TALLOC_CTX *tmp_ctx;
484 : struct ldb_result *res;
485 : struct ldb_dn *base_dn;
486 : int ret;
487 40 : const char *def_attrs[] = { SYSDB_NAME, SYSDB_UPN, SYSDB_CANONICAL_UPN,
488 : NULL };
489 :
490 40 : tmp_ctx = talloc_new(NULL);
491 40 : if (tmp_ctx == NULL) {
492 0 : ret = ENOMEM;
493 0 : goto done;
494 : }
495 :
496 40 : base_dn = sysdb_base_dn(domain->sysdb, tmp_ctx);
497 40 : if (base_dn == NULL) {
498 0 : ret = ENOMEM;
499 0 : goto done;
500 : }
501 :
502 40 : ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
503 : base_dn, LDB_SCOPE_SUBTREE, attrs ? attrs : def_attrs,
504 : SYSDB_PWUPN_FILTER, upn, upn);
505 40 : if (ret != EOK) {
506 0 : ret = sysdb_error_to_errno(ret);
507 0 : goto done;
508 : }
509 :
510 40 : if (res->count == 0) {
511 : /* set result anyway */
512 25 : *out_res = talloc_steal(mem_ctx, res);
513 25 : ret = ENOENT;
514 25 : goto done;
515 15 : } else if (res->count > 1) {
516 1 : DEBUG(SSSDBG_OP_FAILURE,
517 : "Search for upn [%s] returns more than one result.\n", upn);
518 1 : ret = EINVAL;
519 1 : goto done;
520 : }
521 :
522 14 : *out_res = talloc_steal(mem_ctx, res);
523 14 : ret = EOK;
524 :
525 : done:
526 40 : talloc_zfree(tmp_ctx);
527 40 : return ret;
528 : }
529 :
530 17 : int sysdb_search_user_by_upn(TALLOC_CTX *mem_ctx,
531 : struct sss_domain_info *domain,
532 : const char *upn,
533 : const char **attrs,
534 : struct ldb_message **msg)
535 : {
536 : TALLOC_CTX *tmp_ctx;
537 : struct ldb_result *res;
538 : errno_t ret;
539 :
540 17 : tmp_ctx = talloc_new(NULL);
541 17 : if (tmp_ctx == NULL) {
542 0 : ret = ENOMEM;
543 0 : goto done;
544 : }
545 :
546 17 : ret = sysdb_search_user_by_upn_res(tmp_ctx, domain, upn, attrs, &res);
547 17 : if (ret == ENOENT) {
548 8 : DEBUG(SSSDBG_TRACE_FUNC, "No entry with upn [%s] found.\n", upn);
549 8 : goto done;
550 9 : } else if (ret != EOK) {
551 1 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
552 1 : goto done;
553 : }
554 :
555 8 : *msg = talloc_steal(mem_ctx, res->msgs[0]);
556 :
557 8 : ret = EOK;
558 :
559 : done:
560 17 : talloc_zfree(tmp_ctx);
561 17 : return ret;
562 : }
563 :
564 : /* =Search-Group-by-[GID/SID/NAME]============================================ */
565 :
566 223 : int sysdb_search_group_by_name(TALLOC_CTX *mem_ctx,
567 : struct sss_domain_info *domain,
568 : const char *name,
569 : const char **attrs,
570 : struct ldb_message **msg)
571 : {
572 223 : return sysdb_search_by_name(mem_ctx, domain, name, SYSDB_GROUP, attrs, msg);
573 : }
574 :
575 843 : int sysdb_search_group_by_gid(TALLOC_CTX *mem_ctx,
576 : struct sss_domain_info *domain,
577 : gid_t gid,
578 : const char **attrs,
579 : struct ldb_message **msg)
580 : {
581 : TALLOC_CTX *tmp_ctx;
582 843 : const char *def_attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL };
583 843 : struct ldb_message **msgs = NULL;
584 : struct ldb_dn *basedn;
585 843 : size_t msgs_count = 0;
586 : char *filter;
587 : int ret;
588 :
589 843 : tmp_ctx = talloc_new(NULL);
590 843 : if (!tmp_ctx) {
591 0 : return ENOMEM;
592 : }
593 :
594 843 : basedn = sysdb_group_base_dn(tmp_ctx, domain);
595 843 : if (!basedn) {
596 0 : ret = ENOMEM;
597 0 : goto done;
598 : }
599 :
600 843 : filter = talloc_asprintf(tmp_ctx, SYSDB_GRGID_FILTER, (unsigned long)gid);
601 843 : if (!filter) {
602 0 : ret = ENOMEM;
603 0 : goto done;
604 : }
605 :
606 : /* Use SUBTREE scope here, not ONELEVEL
607 : * There is a bug in LDB that makes ONELEVEL searches extremely
608 : * slow (it ignores indexing)
609 : */
610 843 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_SUBTREE,
611 : filter, attrs?attrs:def_attrs,
612 : &msgs_count, &msgs);
613 843 : if (ret) {
614 149 : goto done;
615 : }
616 :
617 694 : *msg = talloc_steal(mem_ctx, msgs[0]);
618 :
619 : done:
620 843 : if (ret == ENOENT) {
621 149 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
622 : }
623 694 : else if (ret) {
624 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
625 : }
626 :
627 843 : talloc_zfree(tmp_ctx);
628 843 : return ret;
629 : }
630 :
631 3 : int sysdb_search_group_by_sid_str(TALLOC_CTX *mem_ctx,
632 : struct sss_domain_info *domain,
633 : const char *sid_str,
634 : const char **attrs,
635 : struct ldb_message **msg)
636 : {
637 :
638 3 : return sysdb_search_entry_by_sid_str(mem_ctx, domain,
639 : SYSDB_TMPL_GROUP_BASE,
640 : SYSDB_GRSID_FILTER,
641 : sid_str, attrs, msg);
642 : }
643 :
644 : /* =Search-Group-by-Name============================================ */
645 :
646 16 : int sysdb_search_netgroup_by_name(TALLOC_CTX *mem_ctx,
647 : struct sss_domain_info *domain,
648 : const char *name,
649 : const char **attrs,
650 : struct ldb_message **msg)
651 : {
652 : TALLOC_CTX *tmp_ctx;
653 : static const char *def_attrs[] = { SYSDB_NAME, NULL };
654 16 : struct ldb_message **msgs = NULL;
655 : struct ldb_dn *basedn;
656 16 : size_t msgs_count = 0;
657 : int ret;
658 :
659 16 : tmp_ctx = talloc_new(NULL);
660 16 : if (!tmp_ctx) {
661 0 : return ENOMEM;
662 : }
663 :
664 16 : basedn = sysdb_netgroup_dn(tmp_ctx, domain, name);
665 16 : if (!basedn) {
666 0 : ret = ENOMEM;
667 0 : goto done;
668 : }
669 :
670 16 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_BASE,
671 : NULL, attrs?attrs:def_attrs, &msgs_count,
672 : &msgs);
673 16 : if (ret) {
674 1 : goto done;
675 : }
676 :
677 15 : *msg = talloc_steal(mem_ctx, msgs[0]);
678 :
679 : done:
680 16 : if (ret == ENOENT) {
681 1 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
682 : }
683 15 : else if (ret) {
684 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
685 : }
686 16 : talloc_zfree(tmp_ctx);
687 16 : return ret;
688 : }
689 :
690 : /* =Replace-Attributes-On-Entry=========================================== */
691 :
692 506 : int sysdb_set_entry_attr(struct sysdb_ctx *sysdb,
693 : struct ldb_dn *entry_dn,
694 : struct sysdb_attrs *attrs,
695 : int mod_op)
696 : {
697 : struct ldb_message *msg;
698 : int i, ret;
699 : int lret;
700 : TALLOC_CTX *tmp_ctx;
701 :
702 506 : tmp_ctx = talloc_new(NULL);
703 506 : if (!tmp_ctx) {
704 0 : return ENOMEM;
705 : }
706 :
707 506 : if (!entry_dn || attrs->num == 0) {
708 0 : ret = EINVAL;
709 0 : goto done;
710 : }
711 :
712 506 : msg = ldb_msg_new(tmp_ctx);
713 506 : if (!msg) {
714 0 : ret = ENOMEM;
715 0 : goto done;
716 : }
717 :
718 506 : msg->dn = entry_dn;
719 :
720 506 : msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num);
721 506 : if (!msg->elements) {
722 0 : ret = ENOMEM;
723 0 : goto done;
724 : }
725 :
726 1952 : for (i = 0; i < attrs->num; i++) {
727 1446 : msg->elements[i] = attrs->a[i];
728 1446 : msg->elements[i].flags = mod_op;
729 : }
730 :
731 506 : msg->num_elements = attrs->num;
732 :
733 506 : lret = ldb_modify(sysdb->ldb, msg);
734 506 : if (lret != LDB_SUCCESS) {
735 0 : DEBUG(SSSDBG_MINOR_FAILURE,
736 : "ldb_modify failed: [%s](%d)[%s]\n",
737 : ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb));
738 : }
739 :
740 506 : ret = sysdb_error_to_errno(lret);
741 :
742 : done:
743 506 : if (ret == ENOENT) {
744 0 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
745 : }
746 506 : else if (ret) {
747 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
748 : }
749 506 : talloc_zfree(tmp_ctx);
750 506 : return ret;
751 : }
752 :
753 :
754 : /* =Replace-Attributes-On-User============================================ */
755 :
756 268 : int sysdb_set_user_attr(struct sss_domain_info *domain,
757 : const char *name,
758 : struct sysdb_attrs *attrs,
759 : int mod_op)
760 : {
761 : struct ldb_dn *dn;
762 : TALLOC_CTX *tmp_ctx;
763 : errno_t ret;
764 :
765 268 : tmp_ctx = talloc_new(NULL);
766 268 : if (!tmp_ctx) {
767 0 : return ENOMEM;
768 : }
769 :
770 268 : dn = sysdb_user_dn(tmp_ctx, domain, name);
771 268 : if (!dn) {
772 0 : ret = ENOMEM;
773 0 : goto done;
774 : }
775 :
776 268 : ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
777 268 : if (ret != EOK) {
778 0 : goto done;
779 : }
780 :
781 268 : ret = EOK;
782 : done:
783 268 : talloc_zfree(tmp_ctx);
784 268 : return ret;
785 : }
786 :
787 :
788 : /* =Replace-Attributes-On-Group=========================================== */
789 :
790 223 : int sysdb_set_group_attr(struct sss_domain_info *domain,
791 : const char *name,
792 : struct sysdb_attrs *attrs,
793 : int mod_op)
794 : {
795 : struct ldb_dn *dn;
796 : TALLOC_CTX *tmp_ctx;
797 : errno_t ret;
798 :
799 223 : tmp_ctx = talloc_new(NULL);
800 223 : if (!tmp_ctx) {
801 0 : ret = ENOMEM;
802 0 : goto done;
803 : }
804 :
805 223 : dn = sysdb_group_dn(tmp_ctx, domain, name);
806 223 : if (!dn) {
807 0 : ret = ENOMEM;
808 0 : goto done;
809 : }
810 :
811 223 : ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
812 223 : if (ret) {
813 0 : goto done;
814 : }
815 :
816 223 : ret = EOK;
817 : done:
818 223 : talloc_free(tmp_ctx);
819 223 : return ret;
820 : }
821 :
822 : /* =Replace-Attributes-On-Netgroup=========================================== */
823 :
824 11 : int sysdb_set_netgroup_attr(struct sss_domain_info *domain,
825 : const char *name,
826 : struct sysdb_attrs *attrs,
827 : int mod_op)
828 : {
829 : errno_t ret;
830 : struct ldb_dn *dn;
831 : TALLOC_CTX *tmp_ctx;
832 :
833 11 : tmp_ctx = talloc_new(NULL);
834 11 : if (!tmp_ctx) {
835 0 : return ENOMEM;
836 : }
837 :
838 11 : dn = sysdb_netgroup_dn(tmp_ctx, domain, name);
839 11 : if (!dn) {
840 0 : ret = ENOMEM;
841 0 : goto done;
842 : }
843 :
844 11 : ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
845 :
846 : done:
847 11 : talloc_free(tmp_ctx);
848 11 : return ret;
849 : }
850 :
851 : /* =Get-New-ID============================================================ */
852 :
853 26 : int sysdb_get_new_id(struct sss_domain_info *domain,
854 : uint32_t *_id)
855 : {
856 : TALLOC_CTX *tmp_ctx;
857 26 : const char *attrs_1[] = { SYSDB_NEXTID, NULL };
858 26 : const char *attrs_2[] = { SYSDB_UIDNUM, SYSDB_GIDNUM, NULL };
859 : struct ldb_dn *base_dn;
860 : char *filter;
861 26 : uint32_t new_id = 0;
862 : struct ldb_message **msgs;
863 : size_t count;
864 : struct ldb_message *msg;
865 : uint32_t id;
866 : int ret;
867 : int i;
868 :
869 26 : tmp_ctx = talloc_new(NULL);
870 26 : if (!tmp_ctx) {
871 0 : return ENOMEM;
872 : }
873 :
874 26 : base_dn = sysdb_domain_dn(tmp_ctx, domain);
875 26 : if (!base_dn) {
876 0 : talloc_zfree(tmp_ctx);
877 0 : return ENOMEM;
878 : }
879 :
880 26 : ret = ldb_transaction_start(domain->sysdb->ldb);
881 26 : if (ret) {
882 0 : talloc_zfree(tmp_ctx);
883 0 : ret = sysdb_error_to_errno(ret);
884 0 : return ret;
885 : }
886 :
887 26 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, base_dn, LDB_SCOPE_BASE,
888 : SYSDB_NEXTID_FILTER, attrs_1, &count, &msgs);
889 26 : switch (ret) {
890 : case EOK:
891 24 : new_id = get_attr_as_uint32(msgs[0], SYSDB_NEXTID);
892 24 : if (new_id == (uint32_t)(-1)) {
893 0 : DEBUG(SSSDBG_CRIT_FAILURE,
894 : "Invalid Next ID in domain %s\n", domain->name);
895 0 : ret = ERANGE;
896 0 : goto done;
897 : }
898 :
899 24 : if (new_id < domain->id_min) {
900 0 : new_id = domain->id_min;
901 : }
902 :
903 24 : if ((domain->id_max != 0) && (new_id > domain->id_max)) {
904 0 : DEBUG(SSSDBG_FATAL_FAILURE,
905 : "Failed to allocate new id, out of range (%u/%u)\n",
906 : new_id, domain->id_max);
907 0 : ret = ERANGE;
908 0 : goto done;
909 : }
910 24 : break;
911 :
912 : case ENOENT:
913 : /* looks like the domain is not initialized yet, use min_id */
914 2 : new_id = domain->id_min;
915 2 : break;
916 :
917 : default:
918 0 : goto done;
919 : }
920 26 : talloc_zfree(msgs);
921 26 : count = 0;
922 :
923 : /* verify the id is actually really free.
924 : * search all entries with id >= new_id and < max_id */
925 26 : if (domain->id_max) {
926 0 : filter = talloc_asprintf(tmp_ctx,
927 : "(|(&(%s>=%u)(%s<=%u))(&(%s>=%u)(%s<=%u)))",
928 : SYSDB_UIDNUM, new_id,
929 : SYSDB_UIDNUM, domain->id_max,
930 : SYSDB_GIDNUM, new_id,
931 : SYSDB_GIDNUM, domain->id_max);
932 : }
933 : else {
934 26 : filter = talloc_asprintf(tmp_ctx,
935 : "(|(%s>=%u)(%s>=%u))",
936 : SYSDB_UIDNUM, new_id,
937 : SYSDB_GIDNUM, new_id);
938 : }
939 26 : if (!filter) {
940 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: Out of memory\n");
941 0 : ret = ENOMEM;
942 0 : goto done;
943 : }
944 :
945 26 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, base_dn, LDB_SCOPE_SUBTREE,
946 : filter, attrs_2, &count, &msgs);
947 26 : switch (ret) {
948 : /* if anything was found, find the maximum and increment past it */
949 : case EOK:
950 0 : for (i = 0; i < count; i++) {
951 0 : id = get_attr_as_uint32(msgs[i], SYSDB_UIDNUM);
952 0 : if (id != (uint32_t)(-1)) {
953 0 : if (id > new_id) new_id = id;
954 : }
955 0 : id = get_attr_as_uint32(msgs[i], SYSDB_GIDNUM);
956 0 : if (id != (uint32_t)(-1)) {
957 0 : if (id > new_id) new_id = id;
958 : }
959 : }
960 :
961 0 : new_id++;
962 :
963 : /* check again we are not falling out of range */
964 0 : if ((domain->id_max != 0) && (new_id > domain->id_max)) {
965 0 : DEBUG(SSSDBG_FATAL_FAILURE,
966 : "Failed to allocate new id, out of range (%u/%u)\n",
967 : new_id, domain->id_max);
968 0 : ret = ERANGE;
969 0 : goto done;
970 : }
971 0 : break;
972 :
973 : case ENOENT:
974 26 : break;
975 :
976 : default:
977 0 : goto done;
978 : }
979 :
980 26 : talloc_zfree(msgs);
981 26 : count = 0;
982 :
983 : /* finally store the new next id */
984 26 : msg = ldb_msg_new(tmp_ctx);
985 26 : if (!msg) {
986 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: Out of memory\n");
987 0 : ret = ENOMEM;
988 0 : goto done;
989 : }
990 26 : msg->dn = base_dn;
991 :
992 26 : ret = add_ulong(msg, LDB_FLAG_MOD_REPLACE,
993 26 : SYSDB_NEXTID, new_id + 1);
994 26 : if (ret) {
995 0 : goto done;
996 : }
997 :
998 26 : ret = ldb_modify(domain->sysdb->ldb, msg);
999 26 : if (ret != LDB_SUCCESS) {
1000 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1001 : "ldb_modify failed: [%s](%d)[%s]\n",
1002 : ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
1003 : }
1004 26 : ret = sysdb_error_to_errno(ret);
1005 :
1006 26 : *_id = new_id;
1007 :
1008 : done:
1009 26 : if (ret == EOK) {
1010 26 : ret = ldb_transaction_commit(domain->sysdb->ldb);
1011 26 : ret = sysdb_error_to_errno(ret);
1012 : } else {
1013 0 : ldb_transaction_cancel(domain->sysdb->ldb);
1014 : }
1015 26 : if (ret) {
1016 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1017 : }
1018 26 : talloc_zfree(tmp_ctx);
1019 26 : return ret;
1020 : }
1021 :
1022 :
1023 : /* =Add-Basic-User-NO-CHECKS============================================== */
1024 :
1025 181 : int sysdb_add_basic_user(struct sss_domain_info *domain,
1026 : const char *name,
1027 : uid_t uid, gid_t gid,
1028 : const char *gecos,
1029 : const char *homedir,
1030 : const char *shell)
1031 : {
1032 : struct ldb_message *msg;
1033 : int ret;
1034 : TALLOC_CTX *tmp_ctx;
1035 :
1036 181 : tmp_ctx = talloc_new(NULL);
1037 181 : if (!tmp_ctx) {
1038 0 : return ENOMEM;
1039 : }
1040 :
1041 181 : msg = ldb_msg_new(tmp_ctx);
1042 181 : if (!msg) {
1043 0 : ret = ENOMEM;
1044 0 : goto done;
1045 : }
1046 :
1047 : /* user dn */
1048 181 : msg->dn = sysdb_user_dn(msg, domain, name);
1049 181 : if (!msg->dn) {
1050 0 : ERROR_OUT(ret, ENOMEM, done);
1051 : }
1052 :
1053 181 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS);
1054 181 : if (ret) goto done;
1055 :
1056 181 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name);
1057 181 : if (ret) goto done;
1058 :
1059 181 : ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_UIDNUM, (unsigned long)uid);
1060 181 : if (ret) goto done;
1061 :
1062 181 : ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_GIDNUM, (unsigned long)gid);
1063 181 : if (ret) goto done;
1064 :
1065 : /* We set gecos to be the same as fullname on user creation,
1066 : * But we will not enforce coherency after that, it's up to
1067 : * admins to decide if they want to keep it in sync if they change
1068 : * one of the 2 */
1069 181 : if (gecos && *gecos) {
1070 160 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_FULLNAME, gecos);
1071 160 : if (ret) goto done;
1072 160 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_GECOS, gecos);
1073 160 : if (ret) goto done;
1074 : }
1075 :
1076 181 : if (homedir && *homedir) {
1077 158 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_HOMEDIR, homedir);
1078 158 : if (ret) goto done;
1079 : }
1080 :
1081 181 : if (shell && *shell) {
1082 158 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_SHELL, shell);
1083 158 : if (ret) goto done;
1084 : }
1085 :
1086 : /* creation time */
1087 181 : ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME,
1088 181 : (unsigned long)time(NULL));
1089 181 : if (ret) goto done;
1090 :
1091 181 : ret = ldb_add(domain->sysdb->ldb, msg);
1092 181 : ret = sysdb_error_to_errno(ret);
1093 :
1094 : done:
1095 181 : if (ret) {
1096 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1097 : }
1098 181 : talloc_zfree(tmp_ctx);
1099 181 : return ret;
1100 : }
1101 :
1102 : static errno_t
1103 35 : sysdb_remove_ghost_from_group(struct sss_domain_info *dom,
1104 : struct ldb_message *group,
1105 : struct ldb_message_element *alias_el,
1106 : const char *name,
1107 : const char *orig_dn,
1108 : const char *userdn)
1109 : {
1110 : TALLOC_CTX *tmp_ctx;
1111 : struct ldb_message *msg;
1112 : struct ldb_message_element *orig_members;
1113 35 : bool add_member = false;
1114 35 : errno_t ret = EOK;
1115 : int i;
1116 :
1117 35 : tmp_ctx = talloc_new(NULL);
1118 35 : if (!tmp_ctx) {
1119 0 : return ENOENT;
1120 : }
1121 :
1122 35 : msg = ldb_msg_new(tmp_ctx);
1123 35 : if (!msg) {
1124 0 : ERROR_OUT(ret, ENOMEM, done);
1125 : }
1126 :
1127 35 : msg->dn = group->dn;
1128 :
1129 35 : if (orig_dn == NULL) {
1130 : /* We have no way of telling which groups this user belongs to.
1131 : * Add it to all that reference it in the ghost attribute */
1132 35 : add_member = true;
1133 : } else {
1134 0 : add_member = false;
1135 0 : orig_members = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER);
1136 0 : if (orig_members) {
1137 0 : for (i = 0; i < orig_members->num_values; i++) {
1138 0 : if (strcmp((const char *) orig_members->values[i].data,
1139 : orig_dn) == 0) {
1140 : /* This is a direct member. Add the member attribute */
1141 0 : add_member = true;
1142 : }
1143 : }
1144 : } else {
1145 : /* Nothing to compare the originalDN with. Let's rely on the
1146 : * memberof plugin to do the right thing during initgroups..
1147 : */
1148 0 : add_member = true;
1149 : }
1150 : }
1151 :
1152 35 : if (add_member) {
1153 35 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_MEMBER, userdn);
1154 35 : if (ret) goto done;
1155 : }
1156 :
1157 35 : ret = add_string(msg, LDB_FLAG_MOD_DELETE, SYSDB_GHOST, name);
1158 35 : if (ret) goto done;
1159 :
1160 : /* Delete aliases from the ghost attribute as well */
1161 35 : for (i = 0; i < alias_el->num_values; i++) {
1162 0 : if (strcmp((const char *)alias_el->values[i].data, name) == 0) {
1163 0 : continue;
1164 : }
1165 0 : ret = ldb_msg_add_string(msg, SYSDB_GHOST,
1166 0 : (char *) alias_el->values[i].data);
1167 0 : if (ret != LDB_SUCCESS) {
1168 0 : ERROR_OUT(ret, EINVAL, done);
1169 : }
1170 : }
1171 :
1172 :
1173 35 : ret = sss_ldb_modify_permissive(dom->sysdb->ldb, msg);
1174 35 : if (ret != LDB_SUCCESS) {
1175 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1176 : "sss_ldb_modify_permissive failed: [%s](%d)[%s]\n",
1177 : ldb_strerror(ret), ret, ldb_errstring(dom->sysdb->ldb));
1178 : }
1179 :
1180 35 : ret = sysdb_error_to_errno(ret);
1181 35 : if (ret != EOK) {
1182 0 : goto done;
1183 : }
1184 :
1185 35 : talloc_zfree(msg);
1186 :
1187 :
1188 : done:
1189 35 : talloc_free(tmp_ctx);
1190 35 : return ret;
1191 : }
1192 :
1193 : static errno_t
1194 156 : sysdb_remove_ghostattr_from_groups(struct sss_domain_info *domain,
1195 : const char *orig_dn,
1196 : struct sysdb_attrs *attrs,
1197 : const char *name)
1198 : {
1199 : TALLOC_CTX *tmp_ctx;
1200 : struct ldb_message **groups;
1201 : struct ldb_message_element *alias_el;
1202 : struct ldb_dn *tmpdn;
1203 156 : const char *group_attrs[] = {SYSDB_NAME, SYSDB_GHOST, SYSDB_ORIG_MEMBER, NULL};
1204 : const char *userdn;
1205 : char *sanitized_name;
1206 : char *filter;
1207 156 : errno_t ret = EOK;
1208 156 : size_t group_count = 0;
1209 : int i;
1210 :
1211 156 : tmp_ctx = talloc_new(NULL);
1212 156 : if (!tmp_ctx) {
1213 0 : return ENOENT;
1214 : }
1215 :
1216 156 : ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name);
1217 156 : if (ret != EOK) {
1218 0 : goto done;
1219 : }
1220 :
1221 156 : filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)",
1222 : SYSDB_GHOST, sanitized_name);
1223 156 : if (!filter) {
1224 0 : ret = ENOMEM;
1225 0 : goto done;
1226 : }
1227 156 : ret = sysdb_attrs_get_el(attrs, SYSDB_NAME_ALIAS, &alias_el);
1228 156 : if (ret != EOK) {
1229 0 : goto done;
1230 : }
1231 :
1232 158 : for (i = 0; i < alias_el->num_values; i++) {
1233 2 : if (strcmp((const char *)alias_el->values[i].data, name) == 0) {
1234 0 : continue;
1235 : }
1236 2 : filter = talloc_asprintf_append(filter, "(%s=%s)",
1237 2 : SYSDB_GHOST, alias_el->values[i].data);
1238 2 : if (filter == NULL) {
1239 0 : ret = ENOMEM;
1240 0 : goto done;
1241 : }
1242 : }
1243 :
1244 156 : filter = talloc_asprintf_append(filter, ")");
1245 156 : if (filter == NULL) {
1246 0 : ret = ENOMEM;
1247 0 : goto done;
1248 : }
1249 :
1250 156 : tmpdn = sysdb_user_dn(tmp_ctx, domain, name);
1251 156 : if (!tmpdn) {
1252 0 : ERROR_OUT(ret, ENOMEM, done);
1253 : }
1254 :
1255 156 : userdn = ldb_dn_get_linearized(tmpdn);
1256 156 : if (!userdn) {
1257 0 : ERROR_OUT(ret, EINVAL, done);
1258 : }
1259 :
1260 : /* To cover cross-domain group-membership we must search in all
1261 : * sub-domains. */
1262 156 : tmpdn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, SYSDB_BASE);
1263 156 : if (!tmpdn) {
1264 0 : ret = ENOMEM;
1265 0 : goto done;
1266 : }
1267 :
1268 : /* We need to find all groups that contain this object as a ghost user
1269 : * and replace the ghost user by actual member record in direct parents.
1270 : * Note that this object can be referred to either by its name or any
1271 : * of its aliases
1272 : */
1273 156 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, tmpdn, LDB_SCOPE_SUBTREE,
1274 : filter, group_attrs, &group_count, &groups);
1275 156 : if (ret != EOK && ret != ENOENT) {
1276 0 : goto done;
1277 : }
1278 :
1279 191 : for (i = 0; i < group_count; i++) {
1280 35 : sysdb_remove_ghost_from_group(domain, groups[i], alias_el, name,
1281 : orig_dn, userdn);
1282 : }
1283 :
1284 156 : ret = EOK;
1285 :
1286 : done:
1287 156 : talloc_free(tmp_ctx);
1288 156 : return ret;
1289 : }
1290 :
1291 : /* =Add-User-Function===================================================== */
1292 :
1293 184 : int sysdb_add_user(struct sss_domain_info *domain,
1294 : const char *name,
1295 : uid_t uid, gid_t gid,
1296 : const char *gecos,
1297 : const char *homedir,
1298 : const char *shell,
1299 : const char *orig_dn,
1300 : struct sysdb_attrs *attrs,
1301 : int cache_timeout,
1302 : time_t now)
1303 : {
1304 : TALLOC_CTX *tmp_ctx;
1305 : struct ldb_message *msg;
1306 : struct sysdb_attrs *id_attrs;
1307 : uint32_t id;
1308 : int ret;
1309 :
1310 184 : if (domain->mpg) {
1311 61 : if (gid != 0) {
1312 0 : DEBUG(SSSDBG_FATAL_FAILURE,
1313 : "Cannot add user with arbitrary GID in MPG domain!\n");
1314 0 : return EINVAL;
1315 : }
1316 61 : gid = uid;
1317 : }
1318 :
1319 190 : if (domain->id_max != 0 && uid != 0 &&
1320 12 : (uid < domain->id_min || uid > domain->id_max)) {
1321 0 : DEBUG(SSSDBG_OP_FAILURE,
1322 : "Supplied uid [%"SPRIuid"] is not in the allowed range "
1323 : "[%d-%d].\n", uid, domain->id_min, domain->id_max);
1324 0 : return ERANGE;
1325 : }
1326 :
1327 186 : if (domain->id_max != 0 && gid != 0 &&
1328 4 : (gid < domain->id_min || gid > domain->id_max)) {
1329 0 : DEBUG(SSSDBG_OP_FAILURE,
1330 : "Supplied gid [%"SPRIgid"] is not in the allowed range "
1331 : "[%d-%d].\n", gid, domain->id_min, domain->id_max);
1332 0 : return ERANGE;
1333 : }
1334 :
1335 184 : tmp_ctx = talloc_new(NULL);
1336 184 : if (!tmp_ctx) {
1337 0 : return ENOMEM;
1338 : }
1339 :
1340 184 : ret = ldb_transaction_start(domain->sysdb->ldb);
1341 184 : if (ret) {
1342 0 : ret = sysdb_error_to_errno(ret);
1343 0 : talloc_free(tmp_ctx);
1344 0 : return ret;
1345 : }
1346 :
1347 184 : if (domain->mpg) {
1348 : /* In MPG domains you can't have groups with the same name as users,
1349 : * search if a group with the same name exists.
1350 : * Don't worry about users, if we try to add a user with the same
1351 : * name the operation will fail */
1352 :
1353 61 : ret = sysdb_search_group_by_name(tmp_ctx, domain, name, NULL, &msg);
1354 61 : if (ret != ENOENT) {
1355 0 : if (ret == EOK) ret = EEXIST;
1356 0 : goto done;
1357 : }
1358 : }
1359 :
1360 : /* check no other user with the same uid exist */
1361 184 : if (uid != 0) {
1362 171 : ret = sysdb_search_user_by_uid(tmp_ctx, domain, uid, NULL, &msg);
1363 171 : if (ret != ENOENT) {
1364 4 : if (ret == EOK) ret = EEXIST;
1365 4 : goto done;
1366 : }
1367 : }
1368 :
1369 : /* try to add the user */
1370 180 : ret = sysdb_add_basic_user(domain, name, uid, gid, gecos, homedir, shell);
1371 180 : if (ret) goto done;
1372 :
1373 180 : if (uid == 0) {
1374 13 : ret = sysdb_get_new_id(domain, &id);
1375 13 : if (ret) goto done;
1376 :
1377 13 : id_attrs = sysdb_new_attrs(tmp_ctx);
1378 13 : if (!id_attrs) {
1379 0 : ret = ENOMEM;
1380 0 : goto done;
1381 : }
1382 13 : ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_UIDNUM, id);
1383 13 : if (ret) goto done;
1384 :
1385 13 : if (domain->mpg) {
1386 13 : ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_GIDNUM, id);
1387 13 : if (ret) goto done;
1388 : }
1389 :
1390 13 : ret = sysdb_set_user_attr(domain, name, id_attrs, SYSDB_MOD_REP);
1391 : /* continue on success, to commit additional attrs */
1392 13 : if (ret) goto done;
1393 : }
1394 :
1395 180 : if (!attrs) {
1396 87 : attrs = sysdb_new_attrs(tmp_ctx);
1397 87 : if (!attrs) {
1398 0 : ret = ENOMEM;
1399 0 : goto done;
1400 : }
1401 : }
1402 :
1403 180 : if (!now) {
1404 98 : now = time(NULL);
1405 : }
1406 :
1407 180 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
1408 180 : if (ret) goto done;
1409 :
1410 341 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
1411 : ((cache_timeout) ?
1412 161 : (now + cache_timeout) : 0));
1413 180 : if (ret) goto done;
1414 :
1415 180 : ret = sysdb_set_user_attr(domain, name, attrs, SYSDB_MOD_REP);
1416 180 : if (ret) goto done;
1417 :
1418 180 : if (domain->enumerate == false) {
1419 : /* If we're not enumerating, previous getgr{nam,gid} calls might
1420 : * have stored ghost users into the cache, so we need to link them
1421 : * with the newly-created user entry
1422 : */
1423 156 : ret = sysdb_remove_ghostattr_from_groups(domain, orig_dn, attrs,
1424 : name);
1425 156 : if (ret) goto done;
1426 : }
1427 :
1428 180 : ret = EOK;
1429 :
1430 : done:
1431 184 : if (ret == EOK) {
1432 180 : ret = ldb_transaction_commit(domain->sysdb->ldb);
1433 180 : ret = sysdb_error_to_errno(ret);
1434 : } else {
1435 4 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1436 4 : ldb_transaction_cancel(domain->sysdb->ldb);
1437 : }
1438 184 : talloc_zfree(tmp_ctx);
1439 184 : return ret;
1440 : }
1441 :
1442 : /* =Add-Basic-Group-NO-CHECKS============================================= */
1443 :
1444 170 : int sysdb_add_basic_group(struct sss_domain_info *domain,
1445 : const char *name, gid_t gid)
1446 : {
1447 : struct ldb_message *msg;
1448 : int ret;
1449 : TALLOC_CTX *tmp_ctx;
1450 :
1451 170 : tmp_ctx = talloc_new(NULL);
1452 170 : if (!tmp_ctx) {
1453 0 : return ENOMEM;
1454 : }
1455 :
1456 170 : msg = ldb_msg_new(tmp_ctx);
1457 170 : if (!msg) {
1458 0 : ret = ENOMEM;
1459 0 : goto done;
1460 : }
1461 :
1462 : /* group dn */
1463 170 : msg->dn = sysdb_group_dn(msg, domain, name);
1464 170 : if (!msg->dn) {
1465 0 : ERROR_OUT(ret, ENOMEM, done);
1466 : }
1467 :
1468 170 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS);
1469 170 : if (ret) goto done;
1470 :
1471 170 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name);
1472 170 : if (ret) goto done;
1473 :
1474 170 : ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_GIDNUM, (unsigned long)gid);
1475 170 : if (ret) goto done;
1476 :
1477 : /* creation time */
1478 170 : ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME,
1479 170 : (unsigned long)time(NULL));
1480 170 : if (ret) goto done;
1481 :
1482 170 : ret = ldb_add(domain->sysdb->ldb, msg);
1483 170 : ret = sysdb_error_to_errno(ret);
1484 :
1485 : done:
1486 170 : if (ret) {
1487 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1488 : }
1489 170 : talloc_zfree(tmp_ctx);
1490 170 : return ret;
1491 : }
1492 :
1493 :
1494 : /* =Add-Group-Function==================================================== */
1495 :
1496 157 : int sysdb_add_group(struct sss_domain_info *domain,
1497 : const char *name, gid_t gid,
1498 : struct sysdb_attrs *attrs,
1499 : int cache_timeout,
1500 : time_t now)
1501 : {
1502 : TALLOC_CTX *tmp_ctx;
1503 : struct ldb_message *msg;
1504 : uint32_t id;
1505 : int ret;
1506 : bool posix;
1507 :
1508 159 : if (domain->id_max != 0 && gid != 0 &&
1509 4 : (gid < domain->id_min || gid > domain->id_max)) {
1510 0 : DEBUG(SSSDBG_OP_FAILURE,
1511 : "Supplied gid [%"SPRIgid"] is not in the allowed range "
1512 : "[%d-%d].\n", gid, domain->id_min, domain->id_max);
1513 0 : return ERANGE;
1514 : }
1515 :
1516 157 : tmp_ctx = talloc_new(NULL);
1517 157 : if (!tmp_ctx) {
1518 0 : return ENOMEM;
1519 : }
1520 :
1521 157 : ret = ldb_transaction_start(domain->sysdb->ldb);
1522 157 : if (ret) {
1523 0 : ret = sysdb_error_to_errno(ret);
1524 0 : talloc_free(tmp_ctx);
1525 0 : return ret;
1526 : }
1527 :
1528 157 : if (domain->mpg) {
1529 : /* In MPG domains you can't have groups with the same name as users,
1530 : * search if a group with the same name exists.
1531 : * Don't worry about users, if we try to add a user with the same
1532 : * name the operation will fail */
1533 :
1534 116 : ret = sysdb_search_user_by_name(tmp_ctx, domain, name, NULL, &msg);
1535 116 : if (ret != ENOENT) {
1536 0 : if (ret == EOK) {
1537 0 : DEBUG(SSSDBG_TRACE_LIBS, "MPG domain contains a user "
1538 : "with the same name - %s.\n", name);
1539 0 : ret = EEXIST;
1540 : } else {
1541 0 : DEBUG(SSSDBG_TRACE_LIBS,
1542 : "sysdb_search_user_by_name failed for user %s.\n", name);
1543 : }
1544 0 : goto done;
1545 : }
1546 : }
1547 :
1548 : /* check no other groups with the same gid exist */
1549 157 : if (gid != 0) {
1550 145 : ret = sysdb_search_group_by_gid(tmp_ctx, domain, gid, NULL, &msg);
1551 145 : if (ret != ENOENT) {
1552 2 : if (ret == EOK) {
1553 2 : DEBUG(SSSDBG_TRACE_LIBS,
1554 : "Group with the same gid exists: [%"SPRIgid"].\n", gid);
1555 2 : ret = EEXIST;
1556 : } else {
1557 0 : DEBUG(SSSDBG_TRACE_LIBS,
1558 : "sysdb_search_group_by_gid failed for gid: "
1559 : "[%"SPRIgid"].\n", gid);
1560 : }
1561 2 : goto done;
1562 : }
1563 : }
1564 :
1565 : /* try to add the group */
1566 155 : ret = sysdb_add_basic_group(domain, name, gid);
1567 155 : if (ret) {
1568 0 : DEBUG(SSSDBG_TRACE_LIBS,
1569 : "sysdb_add_basic_group failed for: %s with gid: "
1570 : "[%"SPRIgid"].\n", name, gid);
1571 0 : goto done;
1572 : }
1573 :
1574 155 : if (!attrs) {
1575 34 : attrs = sysdb_new_attrs(tmp_ctx);
1576 34 : if (!attrs) {
1577 0 : DEBUG(SSSDBG_TRACE_LIBS, "sysdb_new_attrs failed.\n");
1578 0 : ret = ENOMEM;
1579 0 : goto done;
1580 : }
1581 : }
1582 :
1583 155 : ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix);
1584 155 : if (ret == ENOENT) {
1585 155 : posix = true;
1586 155 : ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, true);
1587 155 : if (ret) {
1588 0 : DEBUG(SSSDBG_TRACE_LIBS, "Failed to add posix attribute.\n");
1589 0 : goto done;
1590 : }
1591 0 : } else if (ret != EOK) {
1592 0 : DEBUG(SSSDBG_TRACE_LIBS, "Failed to get posix attribute.\n");
1593 0 : goto done;
1594 : }
1595 :
1596 155 : if (posix && gid == 0) {
1597 12 : ret = sysdb_get_new_id(domain, &id);
1598 12 : if (ret) {
1599 0 : DEBUG(SSSDBG_TRACE_LIBS, "sysdb_get_new_id failed.\n");
1600 0 : goto done;
1601 : }
1602 :
1603 12 : ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, id);
1604 12 : if (ret) {
1605 0 : DEBUG(SSSDBG_TRACE_LIBS, "Failed to add new gid.\n");
1606 0 : goto done;
1607 : }
1608 : }
1609 :
1610 155 : if (!now) {
1611 34 : now = time(NULL);
1612 : }
1613 :
1614 155 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
1615 155 : if (ret) {
1616 0 : DEBUG(SSSDBG_TRACE_LIBS, "Failed to add sysdb-last-update.\n");
1617 0 : goto done;
1618 : }
1619 :
1620 286 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
1621 : ((cache_timeout) ?
1622 131 : (now + cache_timeout) : 0));
1623 155 : if (ret) {
1624 0 : DEBUG(SSSDBG_TRACE_LIBS, "Failed to add sysdb-cache-expire.\n");
1625 0 : goto done;
1626 : }
1627 :
1628 155 : ret = sysdb_set_group_attr(domain, name, attrs, SYSDB_MOD_REP);
1629 155 : if (ret) {
1630 0 : DEBUG(SSSDBG_TRACE_LIBS, "sysdb_set_group_attr failed.\n");
1631 0 : goto done;
1632 : }
1633 :
1634 : done:
1635 157 : if (ret == EOK) {
1636 155 : ret = ldb_transaction_commit(domain->sysdb->ldb);
1637 155 : ret = sysdb_error_to_errno(ret);
1638 : } else {
1639 2 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1640 2 : ldb_transaction_cancel(domain->sysdb->ldb);
1641 : }
1642 157 : talloc_zfree(tmp_ctx);
1643 157 : return ret;
1644 : }
1645 :
1646 15 : int sysdb_add_incomplete_group(struct sss_domain_info *domain,
1647 : const char *name,
1648 : gid_t gid,
1649 : const char *original_dn,
1650 : const char *sid_str,
1651 : const char *uuid,
1652 : bool posix,
1653 : time_t now)
1654 : {
1655 : TALLOC_CTX *tmp_ctx;
1656 : int ret;
1657 : struct sysdb_attrs *attrs;
1658 :
1659 15 : tmp_ctx = talloc_new(NULL);
1660 15 : if (!tmp_ctx) {
1661 0 : return ENOMEM;
1662 : }
1663 :
1664 : /* try to add the group */
1665 15 : ret = sysdb_add_basic_group(domain, name, gid);
1666 15 : if (ret) goto done;
1667 :
1668 15 : attrs = sysdb_new_attrs(tmp_ctx);
1669 15 : if (!attrs) {
1670 0 : ret = ENOMEM;
1671 0 : goto done;
1672 : }
1673 :
1674 15 : if (!now) {
1675 15 : now = time(NULL);
1676 : }
1677 :
1678 15 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
1679 15 : if (ret) goto done;
1680 :
1681 15 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
1682 : now-1);
1683 15 : if (ret) goto done;
1684 :
1685 15 : ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, posix);
1686 15 : if (ret) goto done;
1687 :
1688 15 : if (original_dn) {
1689 3 : ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, original_dn);
1690 3 : if (ret) goto done;
1691 : }
1692 :
1693 15 : if (sid_str) {
1694 1 : ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, sid_str);
1695 1 : if (ret) goto done;
1696 : }
1697 :
1698 15 : if (uuid) {
1699 0 : ret = sysdb_attrs_add_string(attrs, SYSDB_UUID, uuid);
1700 0 : if (ret) goto done;
1701 : }
1702 :
1703 15 : ret = sysdb_set_group_attr(domain, name, attrs, SYSDB_MOD_REP);
1704 :
1705 : done:
1706 15 : if (ret != EOK) {
1707 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1708 : }
1709 15 : talloc_zfree(tmp_ctx);
1710 15 : return ret;
1711 : }
1712 :
1713 : /* =Add-Or-Remove-Group-Memeber=========================================== */
1714 :
1715 : /* mod_op must be either SYSDB_MOD_ADD or SYSDB_MOD_DEL */
1716 78 : int sysdb_mod_group_member(struct sss_domain_info *domain,
1717 : struct ldb_dn *member_dn,
1718 : struct ldb_dn *group_dn,
1719 : int mod_op)
1720 : {
1721 : struct ldb_message *msg;
1722 : const char *dn;
1723 : int ret;
1724 :
1725 78 : msg = ldb_msg_new(NULL);
1726 78 : if (!msg) {
1727 0 : ERROR_OUT(ret, ENOMEM, fail);
1728 : }
1729 :
1730 78 : msg->dn = group_dn;
1731 78 : ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, mod_op, NULL);
1732 78 : if (ret != LDB_SUCCESS) {
1733 0 : ERROR_OUT(ret, ENOMEM, fail);
1734 : }
1735 :
1736 78 : dn = ldb_dn_get_linearized(member_dn);
1737 78 : if (!dn) {
1738 0 : ERROR_OUT(ret, EINVAL, fail);
1739 : }
1740 :
1741 78 : ret = ldb_msg_add_string(msg, SYSDB_MEMBER, dn);
1742 78 : if (ret != LDB_SUCCESS) {
1743 0 : ERROR_OUT(ret, EINVAL, fail);
1744 : }
1745 :
1746 78 : ret = ldb_modify(domain->sysdb->ldb, msg);
1747 78 : if (ret != LDB_SUCCESS) {
1748 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1749 : "ldb_modify failed: [%s](%d)[%s]\n",
1750 : ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
1751 : }
1752 78 : ret = sysdb_error_to_errno(ret);
1753 :
1754 : fail:
1755 78 : if (ret) {
1756 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1757 : }
1758 78 : talloc_zfree(msg);
1759 78 : return ret;
1760 : }
1761 :
1762 : /* =Add-Basic-Netgroup-NO-CHECKS============================================= */
1763 :
1764 11 : int sysdb_add_basic_netgroup(struct sss_domain_info *domain,
1765 : const char *name, const char *description)
1766 : {
1767 : struct ldb_message *msg;
1768 : int ret;
1769 :
1770 11 : msg = ldb_msg_new(NULL);
1771 11 : if (!msg) {
1772 0 : return ENOMEM;
1773 : }
1774 :
1775 : /* netgroup dn */
1776 11 : msg->dn = sysdb_netgroup_dn(msg, domain, name);
1777 11 : if (!msg->dn) {
1778 0 : ERROR_OUT(ret, ENOMEM, done);
1779 : }
1780 :
1781 11 : ret = add_string(msg, LDB_FLAG_MOD_ADD,
1782 : SYSDB_OBJECTCLASS, SYSDB_NETGROUP_CLASS);
1783 11 : if (ret) goto done;
1784 :
1785 11 : ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name);
1786 11 : if (ret) goto done;
1787 :
1788 11 : if (description && *description) {
1789 11 : ret = add_string(msg, LDB_FLAG_MOD_ADD,
1790 : SYSDB_DESCRIPTION, description);
1791 11 : if (ret) goto done;
1792 : }
1793 :
1794 : /* creation time */
1795 11 : ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME,
1796 11 : (unsigned long) time(NULL));
1797 11 : if (ret) goto done;
1798 :
1799 11 : ret = ldb_add(domain->sysdb->ldb, msg);
1800 11 : ret = sysdb_error_to_errno(ret);
1801 :
1802 : done:
1803 11 : if (ret) {
1804 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1805 : }
1806 11 : talloc_zfree(msg);
1807 11 : return ret;
1808 : }
1809 :
1810 :
1811 : /* =Add-Netgroup-Function==================================================== */
1812 :
1813 1 : int sysdb_add_netgroup(struct sss_domain_info *domain,
1814 : const char *name,
1815 : const char *description,
1816 : struct sysdb_attrs *attrs,
1817 : char **missing,
1818 : int cache_timeout,
1819 : time_t now)
1820 : {
1821 : TALLOC_CTX *tmp_ctx;
1822 : int ret;
1823 :
1824 1 : tmp_ctx = talloc_new(NULL);
1825 1 : if (!tmp_ctx) {
1826 0 : return ENOMEM;
1827 : }
1828 :
1829 1 : ret = ldb_transaction_start(domain->sysdb->ldb);
1830 1 : if (ret) {
1831 0 : ret = sysdb_error_to_errno(ret);
1832 0 : talloc_free(tmp_ctx);
1833 0 : return ret;
1834 : }
1835 :
1836 : /* try to add the netgroup */
1837 1 : ret = sysdb_add_basic_netgroup(domain, name, description);
1838 1 : if (ret && ret != EEXIST) goto done;
1839 :
1840 1 : if (!attrs) {
1841 1 : attrs = sysdb_new_attrs(tmp_ctx);
1842 1 : if (!attrs) {
1843 0 : ret = ENOMEM;
1844 0 : goto done;
1845 : }
1846 : }
1847 :
1848 1 : if (!now) {
1849 1 : now = time(NULL);
1850 : }
1851 :
1852 1 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
1853 1 : if (ret) goto done;
1854 :
1855 2 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
1856 : ((cache_timeout) ?
1857 1 : (now + cache_timeout) : 0));
1858 1 : if (ret) goto done;
1859 :
1860 1 : ret = sysdb_set_netgroup_attr(domain, name, attrs, SYSDB_MOD_REP);
1861 :
1862 1 : if (missing) {
1863 0 : ret = sysdb_remove_attrs(domain, name,
1864 : SYSDB_MEMBER_NETGROUP,
1865 : missing);
1866 0 : if (ret != EOK) {
1867 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not remove missing attributes\n");
1868 : }
1869 : }
1870 :
1871 : done:
1872 1 : if (ret == EOK) {
1873 1 : ret = ldb_transaction_commit(domain->sysdb->ldb);
1874 1 : ret = sysdb_error_to_errno(ret);
1875 : }
1876 :
1877 1 : if (ret != EOK) {
1878 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
1879 0 : ldb_transaction_cancel(domain->sysdb->ldb);
1880 : }
1881 1 : talloc_zfree(tmp_ctx);
1882 1 : return ret;
1883 : }
1884 :
1885 : /* =Store-Users-(Native/Legacy)-(replaces-existing-data)================== */
1886 :
1887 : /* if one of the basic attributes is empty ("") as opposed to NULL,
1888 : * this will just remove it */
1889 :
1890 104 : int sysdb_store_user(struct sss_domain_info *domain,
1891 : const char *name,
1892 : const char *pwd,
1893 : uid_t uid, gid_t gid,
1894 : const char *gecos,
1895 : const char *homedir,
1896 : const char *shell,
1897 : const char *orig_dn,
1898 : struct sysdb_attrs *attrs,
1899 : char **remove_attrs,
1900 : uint64_t cache_timeout,
1901 : time_t now)
1902 : {
1903 : TALLOC_CTX *tmp_ctx;
1904 : struct ldb_message *msg;
1905 : int ret;
1906 104 : errno_t sret = EOK;
1907 104 : bool in_transaction = false;
1908 :
1909 104 : tmp_ctx = talloc_new(NULL);
1910 104 : if (!tmp_ctx) {
1911 0 : return ENOMEM;
1912 : }
1913 :
1914 104 : if (!attrs) {
1915 83 : attrs = sysdb_new_attrs(tmp_ctx);
1916 83 : if (!attrs) {
1917 0 : ret = ENOMEM;
1918 0 : goto fail;
1919 : }
1920 : }
1921 :
1922 104 : if (pwd && (domain->legacy_passwords || !*pwd)) {
1923 0 : ret = sysdb_attrs_add_string(attrs, SYSDB_PWD, pwd);
1924 0 : if (ret) goto fail;
1925 : }
1926 :
1927 104 : ret = sysdb_transaction_start(domain->sysdb);
1928 104 : if (ret != EOK) {
1929 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
1930 0 : goto fail;
1931 : }
1932 :
1933 104 : in_transaction = true;
1934 :
1935 104 : ret = sysdb_search_user_by_name(tmp_ctx, domain, name, NULL, &msg);
1936 104 : if (ret && ret != ENOENT) {
1937 0 : goto fail;
1938 : }
1939 :
1940 : /* get transaction timestamp */
1941 104 : if (!now) {
1942 73 : now = time(NULL);
1943 : }
1944 :
1945 104 : if (ret == ENOENT) {
1946 : /* users doesn't exist, turn into adding a user */
1947 79 : ret = sysdb_add_user(domain, name, uid, gid, gecos, homedir,
1948 : shell, orig_dn, attrs, cache_timeout, now);
1949 79 : if (ret == EEXIST) {
1950 : /* This may be a user rename. If there is a user with the
1951 : * same UID, remove it and try to add the basic user again
1952 : */
1953 3 : ret = sysdb_delete_user(domain, NULL, uid);
1954 3 : if (ret == ENOENT) {
1955 : /* Not found by UID, return the original EEXIST,
1956 : * this may be a conflict in MPG domain or something
1957 : * else */
1958 0 : ret = EEXIST;
1959 0 : goto fail;
1960 3 : } else if (ret != EOK) {
1961 0 : goto fail;
1962 : }
1963 3 : DEBUG(SSSDBG_MINOR_FAILURE,
1964 : "A user with the same UID [%llu] was removed from the "
1965 : "cache\n", (unsigned long long) uid);
1966 3 : ret = sysdb_add_user(domain, name, uid, gid, gecos, homedir,
1967 : shell, orig_dn, attrs, cache_timeout, now);
1968 : }
1969 :
1970 : /* Handle the result of sysdb_add_user */
1971 79 : if (ret == EOK) {
1972 79 : goto done;
1973 : } else {
1974 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not add user\n");
1975 0 : goto fail;
1976 : }
1977 : }
1978 :
1979 : /* the user exists, let's just replace attributes when set */
1980 25 : if (uid) {
1981 25 : ret = sysdb_attrs_add_uint32(attrs, SYSDB_UIDNUM, uid);
1982 25 : if (ret) goto fail;
1983 : }
1984 :
1985 25 : if (gid) {
1986 5 : ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid);
1987 5 : if (ret) goto fail;
1988 : }
1989 :
1990 25 : if (uid && !gid && domain->mpg) {
1991 20 : ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, uid);
1992 20 : if (ret) goto fail;
1993 : }
1994 :
1995 25 : if (gecos) {
1996 25 : ret = sysdb_attrs_add_string(attrs, SYSDB_GECOS, gecos);
1997 25 : if (ret) goto fail;
1998 : }
1999 :
2000 25 : if (homedir) {
2001 25 : ret = sysdb_attrs_add_string(attrs, SYSDB_HOMEDIR, homedir);
2002 25 : if (ret) goto fail;
2003 : }
2004 :
2005 25 : if (shell) {
2006 25 : ret = sysdb_attrs_add_string(attrs, SYSDB_SHELL, shell);
2007 25 : if (ret) goto fail;
2008 : }
2009 :
2010 25 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
2011 25 : if (ret) goto fail;
2012 :
2013 49 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
2014 : ((cache_timeout) ?
2015 24 : (now + cache_timeout) : 0));
2016 25 : if (ret) goto fail;
2017 :
2018 25 : ret = sysdb_set_user_attr(domain, name, attrs, SYSDB_MOD_REP);
2019 25 : if (ret != EOK) goto fail;
2020 :
2021 25 : if (remove_attrs) {
2022 0 : ret = sysdb_remove_attrs(domain, name,
2023 : SYSDB_MEMBER_USER,
2024 : remove_attrs);
2025 0 : if (ret != EOK) {
2026 0 : DEBUG(SSSDBG_CONF_SETTINGS,
2027 : "Could not remove missing attributes\n");
2028 : }
2029 : }
2030 :
2031 : done:
2032 104 : ret = sysdb_transaction_commit(domain->sysdb);
2033 104 : if (ret != EOK) {
2034 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
2035 0 : goto fail;
2036 : }
2037 :
2038 104 : in_transaction = false;
2039 :
2040 : fail:
2041 104 : if (in_transaction) {
2042 0 : sret = sysdb_transaction_cancel(domain->sysdb);
2043 0 : if (sret != EOK) {
2044 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
2045 : }
2046 : }
2047 :
2048 104 : if (ret) {
2049 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
2050 : }
2051 104 : talloc_zfree(tmp_ctx);
2052 104 : return ret;
2053 : }
2054 :
2055 : /* =Store-Group-(Native/Legacy)-(replaces-existing-data)================== */
2056 :
2057 : /* this function does not check that all user members are actually present */
2058 :
2059 122 : int sysdb_store_group(struct sss_domain_info *domain,
2060 : const char *name,
2061 : gid_t gid,
2062 : struct sysdb_attrs *attrs,
2063 : uint64_t cache_timeout,
2064 : time_t now)
2065 : {
2066 : TALLOC_CTX *tmp_ctx;
2067 : static const char *src_attrs[] = { SYSDB_NAME, SYSDB_GIDNUM,
2068 : SYSDB_ORIG_MODSTAMP, NULL };
2069 : struct ldb_message *msg;
2070 122 : bool new_group = false;
2071 : int ret;
2072 :
2073 122 : tmp_ctx = talloc_new(NULL);
2074 122 : if (!tmp_ctx) {
2075 0 : return ENOMEM;
2076 : }
2077 :
2078 122 : ret = sysdb_search_group_by_name(tmp_ctx, domain, name, src_attrs, &msg);
2079 122 : if (ret && ret != ENOENT) {
2080 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2081 : "sysdb_search_group_by_name failed for %s with: [%d][%s].\n",
2082 : name, ret, strerror(ret));
2083 0 : goto done;
2084 : }
2085 122 : if (ret == ENOENT) {
2086 121 : DEBUG(SSSDBG_TRACE_LIBS, "Group %s does not exist.\n", name);
2087 121 : new_group = true;
2088 : }
2089 :
2090 122 : if (!attrs) {
2091 40 : attrs = sysdb_new_attrs(tmp_ctx);
2092 40 : if (!attrs) {
2093 0 : ret = ENOMEM;
2094 0 : goto done;
2095 : }
2096 : }
2097 :
2098 : /* get transaction timestamp */
2099 122 : if (!now) {
2100 98 : now = time(NULL);
2101 : }
2102 :
2103 : /* FIXME: use the remote modification timestamp to know if the
2104 : * group needs any update */
2105 :
2106 122 : if (new_group) {
2107 : /* group doesn't exist, turn into adding a group */
2108 121 : ret = sysdb_add_group(domain, name, gid, attrs, cache_timeout,
2109 : now);
2110 121 : if (ret == EEXIST) {
2111 : /* This may be a group rename. If there is a group with the
2112 : * same GID, remove it and try to add the basic group again
2113 : */
2114 1 : DEBUG(SSSDBG_TRACE_LIBS, "sysdb_add_group failed: [EEXIST].\n");
2115 1 : ret = sysdb_delete_group(domain, NULL, gid);
2116 1 : if (ret == ENOENT) {
2117 : /* Not found by GID, return the original EEXIST,
2118 : * this may be a conflict in MPG domain or something
2119 : * else */
2120 0 : DEBUG(SSSDBG_TRACE_LIBS,
2121 : "sysdb_delete_group failed (while renaming group). Not "
2122 : "found by gid: [%"SPRIgid"].\n", gid);
2123 0 : return EEXIST;
2124 1 : } else if (ret != EOK) {
2125 0 : DEBUG(SSSDBG_TRACE_LIBS, "sysdb_add_group failed.\n");
2126 0 : goto done;
2127 : }
2128 1 : DEBUG(SSSDBG_MINOR_FAILURE,
2129 : "A group with the same GID [%"SPRIgid"] was removed from "
2130 : "the cache\n", gid);
2131 1 : ret = sysdb_add_group(domain, name, gid, attrs, cache_timeout,
2132 : now);
2133 1 : if (ret) {
2134 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2135 : "sysdb_add_group failed (while renaming group) for: "
2136 : "%s [%"SPRIgid"].\n", name, gid);
2137 : }
2138 : }
2139 121 : goto done;
2140 : }
2141 :
2142 : /* the group exists, let's just replace attributes when set */
2143 1 : if (gid) {
2144 1 : ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid);
2145 1 : if (ret) {
2146 0 : DEBUG(SSSDBG_TRACE_LIBS, "Failed to add GID.\n");
2147 0 : goto done;
2148 : }
2149 : }
2150 :
2151 1 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
2152 1 : if (ret) {
2153 0 : DEBUG(SSSDBG_TRACE_LIBS, "Failed to add sysdb-last-update.\n");
2154 0 : goto done;
2155 : }
2156 :
2157 2 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
2158 : ((cache_timeout) ?
2159 1 : (now + cache_timeout) : 0));
2160 1 : if (ret) {
2161 0 : DEBUG(SSSDBG_TRACE_LIBS, "Failed to add sysdb-cache-expire.\n");
2162 0 : goto done;
2163 : }
2164 :
2165 1 : ret = sysdb_set_group_attr(domain, name, attrs, SYSDB_MOD_REP);
2166 1 : if (ret) {
2167 0 : DEBUG(SSSDBG_TRACE_LIBS, "sysdb_set_group_attr failed.\n");
2168 0 : goto done;
2169 : }
2170 :
2171 : done:
2172 122 : if (ret) {
2173 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
2174 : }
2175 122 : talloc_zfree(tmp_ctx);
2176 122 : return ret;
2177 : }
2178 :
2179 :
2180 : /* =Add-User-to-Group(Native/Legacy)====================================== */
2181 : static int
2182 78 : sysdb_group_membership_mod(struct sss_domain_info *domain,
2183 : const char *group,
2184 : const char *member,
2185 : enum sysdb_member_type type,
2186 : int modify_op,
2187 : bool is_dn)
2188 : {
2189 : struct ldb_dn *group_dn;
2190 : struct ldb_dn *member_dn;
2191 : int ret;
2192 78 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
2193 78 : if (!tmp_ctx) {
2194 0 : return ENOMEM;
2195 : }
2196 :
2197 78 : if (type == SYSDB_MEMBER_USER) {
2198 78 : member_dn = sysdb_user_dn(tmp_ctx, domain, member);
2199 0 : } else if (type == SYSDB_MEMBER_GROUP) {
2200 0 : member_dn = sysdb_group_dn(tmp_ctx, domain, member);
2201 : } else {
2202 0 : ret = EINVAL;
2203 0 : goto done;
2204 : }
2205 :
2206 78 : if (!member_dn) {
2207 0 : ret = ENOMEM;
2208 0 : goto done;
2209 : }
2210 :
2211 78 : if (!is_dn) {
2212 76 : group_dn = sysdb_group_dn(tmp_ctx, domain, group);
2213 : } else {
2214 2 : group_dn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, group);
2215 : }
2216 :
2217 78 : if (!group_dn) {
2218 0 : ret = ENOMEM;
2219 0 : goto done;
2220 : }
2221 :
2222 78 : ret = sysdb_mod_group_member(domain, member_dn, group_dn, modify_op);
2223 :
2224 : done:
2225 78 : talloc_free(tmp_ctx);
2226 78 : return ret;
2227 : }
2228 :
2229 65 : int sysdb_add_group_member(struct sss_domain_info *domain,
2230 : const char *group,
2231 : const char *member,
2232 : enum sysdb_member_type type,
2233 : bool is_dn)
2234 : {
2235 65 : return sysdb_group_membership_mod(domain, group, member, type,
2236 : SYSDB_MOD_ADD, is_dn);
2237 : }
2238 :
2239 : /* =Remove-member-from-Group(Native/Legacy)=============================== */
2240 :
2241 :
2242 13 : int sysdb_remove_group_member(struct sss_domain_info *domain,
2243 : const char *group,
2244 : const char *member,
2245 : enum sysdb_member_type type,
2246 : bool is_dn)
2247 : {
2248 13 : return sysdb_group_membership_mod(domain, group, member, type,
2249 : SYSDB_MOD_DEL, is_dn);
2250 : }
2251 :
2252 :
2253 : /* =Password-Caching====================================================== */
2254 :
2255 13 : int sysdb_cache_password_ex(struct sss_domain_info *domain,
2256 : const char *username,
2257 : const char *password,
2258 : enum sss_authtok_type authtok_type,
2259 : size_t second_factor_len)
2260 : {
2261 : TALLOC_CTX *tmp_ctx;
2262 : struct sysdb_attrs *attrs;
2263 13 : char *hash = NULL;
2264 : char *salt;
2265 : int ret;
2266 :
2267 13 : tmp_ctx = talloc_new(NULL);
2268 13 : if (!tmp_ctx) {
2269 0 : return ENOMEM;
2270 : }
2271 :
2272 13 : ret = s3crypt_gen_salt(tmp_ctx, &salt);
2273 13 : if (ret) {
2274 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Failed to generate random salt.\n");
2275 0 : goto fail;
2276 : }
2277 :
2278 13 : ret = s3crypt_sha512(tmp_ctx, password, salt, &hash);
2279 13 : if (ret) {
2280 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Failed to create password hash.\n");
2281 0 : goto fail;
2282 : }
2283 :
2284 13 : attrs = sysdb_new_attrs(tmp_ctx);
2285 13 : if (!attrs) {
2286 0 : ERROR_OUT(ret, ENOMEM, fail);
2287 : }
2288 :
2289 13 : ret = sysdb_attrs_add_string(attrs, SYSDB_CACHEDPWD, hash);
2290 13 : if (ret) goto fail;
2291 :
2292 13 : ret = sysdb_attrs_add_long(attrs, SYSDB_CACHEDPWD_TYPE, authtok_type);
2293 13 : if (ret) goto fail;
2294 :
2295 13 : if (authtok_type == SSS_AUTHTOK_TYPE_2FA && second_factor_len > 0) {
2296 8 : ret = sysdb_attrs_add_long(attrs, SYSDB_CACHEDPWD_FA2_LEN,
2297 : second_factor_len);
2298 8 : if (ret) goto fail;
2299 : }
2300 :
2301 : /* FIXME: should we use a different attribute for chache passwords ?? */
2302 13 : ret = sysdb_attrs_add_long(attrs, "lastCachedPasswordChange",
2303 13 : (long)time(NULL));
2304 13 : if (ret) goto fail;
2305 :
2306 13 : ret = sysdb_attrs_add_uint32(attrs, SYSDB_FAILED_LOGIN_ATTEMPTS, 0U);
2307 13 : if (ret) goto fail;
2308 :
2309 :
2310 13 : ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
2311 13 : if (ret) {
2312 0 : goto fail;
2313 : }
2314 13 : talloc_zfree(tmp_ctx);
2315 13 : return EOK;
2316 :
2317 : fail:
2318 0 : if (ret) {
2319 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
2320 : }
2321 0 : talloc_zfree(tmp_ctx);
2322 0 : return ret;
2323 : }
2324 :
2325 5 : int sysdb_cache_password(struct sss_domain_info *domain,
2326 : const char *username,
2327 : const char *password)
2328 : {
2329 5 : return sysdb_cache_password_ex(domain, username, password,
2330 : SSS_AUTHTOK_TYPE_PASSWORD, 0);
2331 : }
2332 :
2333 : /* =Custom Search================== */
2334 :
2335 25 : int sysdb_search_custom(TALLOC_CTX *mem_ctx,
2336 : struct sss_domain_info *domain,
2337 : const char *filter,
2338 : const char *subtree_name,
2339 : const char **attrs,
2340 : size_t *msgs_count,
2341 : struct ldb_message ***msgs)
2342 : {
2343 : TALLOC_CTX *tmp_ctx;
2344 25 : struct ldb_dn *basedn = NULL;
2345 : int ret;
2346 :
2347 25 : tmp_ctx = talloc_new(NULL);
2348 25 : if (tmp_ctx == NULL) {
2349 0 : ret = ENOMEM;
2350 0 : goto done;
2351 : }
2352 :
2353 25 : if (filter == NULL || subtree_name == NULL) {
2354 0 : ret = EINVAL;
2355 0 : goto done;
2356 : }
2357 :
2358 25 : basedn = sysdb_custom_subtree_dn(tmp_ctx, domain, subtree_name);
2359 25 : if (basedn == NULL) {
2360 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_custom_subtree_dn failed.\n");
2361 0 : ret = ENOMEM;
2362 0 : goto done;
2363 : }
2364 25 : if (!ldb_dn_validate(basedn)) {
2365 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create DN.\n");
2366 0 : ret = EINVAL;
2367 0 : goto done;
2368 : }
2369 :
2370 25 : ret = sysdb_search_entry(mem_ctx, domain->sysdb, basedn,
2371 : LDB_SCOPE_SUBTREE, filter, attrs,
2372 : msgs_count, msgs);
2373 : done:
2374 25 : talloc_free(tmp_ctx);
2375 25 : return ret;
2376 : }
2377 :
2378 26 : int sysdb_search_custom_by_name(TALLOC_CTX *mem_ctx,
2379 : struct sss_domain_info *domain,
2380 : const char *object_name,
2381 : const char *subtree_name,
2382 : const char **attrs,
2383 : size_t *_count,
2384 : struct ldb_message ***_msgs)
2385 : {
2386 : TALLOC_CTX *tmp_ctx;
2387 : struct ldb_dn *basedn;
2388 : struct ldb_message **msgs;
2389 : size_t count;
2390 : int ret;
2391 :
2392 26 : if (object_name == NULL || subtree_name == NULL) {
2393 0 : return EINVAL;
2394 : }
2395 :
2396 26 : tmp_ctx = talloc_new(NULL);
2397 26 : if (!tmp_ctx) {
2398 0 : return ENOMEM;
2399 : }
2400 :
2401 26 : basedn = sysdb_custom_dn(tmp_ctx, domain, object_name, subtree_name);
2402 26 : if (basedn == NULL) {
2403 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_custom_dn failed.\n");
2404 0 : ret = ENOMEM;
2405 0 : goto done;
2406 : }
2407 26 : if (!ldb_dn_validate(basedn)) {
2408 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create DN.\n");
2409 0 : ret = EINVAL;
2410 0 : goto done;
2411 : }
2412 :
2413 26 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn,
2414 : LDB_SCOPE_BASE, NULL, attrs, &count, &msgs);
2415 26 : if (ret) {
2416 23 : goto done;
2417 : }
2418 :
2419 3 : if (count > 1) {
2420 0 : DEBUG(SSSDBG_CRIT_FAILURE, "More than one result found.\n");
2421 0 : ret = EFAULT;
2422 0 : goto done;
2423 : }
2424 :
2425 3 : *_count = count;
2426 3 : *_msgs = talloc_move(mem_ctx, &msgs);
2427 :
2428 : done:
2429 26 : talloc_zfree(tmp_ctx);
2430 26 : return ret;
2431 : }
2432 :
2433 :
2434 : /* =Custom Store (replaces-existing-data)================== */
2435 :
2436 23 : int sysdb_store_custom(struct sss_domain_info *domain,
2437 : const char *object_name,
2438 : const char *subtree_name,
2439 : struct sysdb_attrs *attrs)
2440 : {
2441 : TALLOC_CTX *tmp_ctx;
2442 23 : const char *search_attrs[] = { "*", NULL };
2443 23 : size_t resp_count = 0;
2444 : struct ldb_message **resp;
2445 : struct ldb_message *msg;
2446 : struct ldb_message_element *el;
2447 23 : bool add_object = false;
2448 : int ret;
2449 : int i;
2450 :
2451 23 : if (object_name == NULL || subtree_name == NULL) {
2452 0 : return EINVAL;
2453 : }
2454 :
2455 23 : ret = ldb_transaction_start(domain->sysdb->ldb);
2456 23 : if (ret) {
2457 0 : return sysdb_error_to_errno(ret);
2458 : }
2459 :
2460 23 : tmp_ctx = talloc_new(NULL);
2461 23 : if (!tmp_ctx) {
2462 0 : ret = ENOMEM;
2463 0 : goto done;
2464 : }
2465 :
2466 23 : ret = sysdb_search_custom_by_name(tmp_ctx, domain,
2467 : object_name, subtree_name,
2468 : search_attrs, &resp_count, &resp);
2469 23 : if (ret != EOK && ret != ENOENT) {
2470 0 : goto done;
2471 : }
2472 :
2473 23 : if (ret == ENOENT) {
2474 22 : add_object = true;
2475 : }
2476 :
2477 23 : msg = ldb_msg_new(tmp_ctx);
2478 23 : if (msg == NULL) {
2479 0 : ret = ENOMEM;
2480 0 : goto done;
2481 : }
2482 :
2483 23 : msg->dn = sysdb_custom_dn(tmp_ctx, domain, object_name, subtree_name);
2484 23 : if (!msg->dn) {
2485 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_custom_dn failed.\n");
2486 0 : ret = ENOMEM;
2487 0 : goto done;
2488 : }
2489 :
2490 23 : msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num);
2491 23 : if (!msg->elements) {
2492 0 : ret = ENOMEM;
2493 0 : goto done;
2494 : }
2495 :
2496 93 : for (i = 0; i < attrs->num; i++) {
2497 70 : msg->elements[i] = attrs->a[i];
2498 70 : if (add_object) {
2499 68 : msg->elements[i].flags = LDB_FLAG_MOD_ADD;
2500 : } else {
2501 2 : el = ldb_msg_find_element(resp[0], attrs->a[i].name);
2502 2 : if (el == NULL) {
2503 1 : msg->elements[i].flags = LDB_FLAG_MOD_ADD;
2504 : } else {
2505 1 : msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2506 : }
2507 : }
2508 : }
2509 23 : msg->num_elements = attrs->num;
2510 :
2511 23 : if (add_object) {
2512 22 : ret = ldb_add(domain->sysdb->ldb, msg);
2513 : } else {
2514 1 : ret = ldb_modify(domain->sysdb->ldb, msg);
2515 : }
2516 23 : if (ret != LDB_SUCCESS) {
2517 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to store custom entry: %s(%d)[%s]\n",
2518 : ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
2519 0 : ret = sysdb_error_to_errno(ret);
2520 : }
2521 :
2522 : done:
2523 23 : if (ret) {
2524 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
2525 0 : ldb_transaction_cancel(domain->sysdb->ldb);
2526 : } else {
2527 23 : ret = ldb_transaction_commit(domain->sysdb->ldb);
2528 23 : ret = sysdb_error_to_errno(ret);
2529 : }
2530 23 : talloc_zfree(tmp_ctx);
2531 23 : return ret;
2532 : }
2533 :
2534 : /* = Custom Delete======================================= */
2535 :
2536 13 : int sysdb_delete_custom(struct sss_domain_info *domain,
2537 : const char *object_name,
2538 : const char *subtree_name)
2539 : {
2540 : TALLOC_CTX *tmp_ctx;
2541 : struct ldb_dn *dn;
2542 : int ret;
2543 :
2544 13 : if (object_name == NULL || subtree_name == NULL) {
2545 0 : return EINVAL;
2546 : }
2547 :
2548 13 : tmp_ctx = talloc_new(NULL);
2549 13 : if (!tmp_ctx) {
2550 0 : return ENOMEM;
2551 : }
2552 :
2553 13 : dn = sysdb_custom_dn(tmp_ctx, domain, object_name, subtree_name);
2554 13 : if (dn == NULL) {
2555 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_custom_dn failed.\n");
2556 0 : ret = ENOMEM;
2557 0 : goto done;
2558 : }
2559 :
2560 13 : ret = ldb_delete(domain->sysdb->ldb, dn);
2561 :
2562 13 : switch (ret) {
2563 : case LDB_SUCCESS:
2564 : case LDB_ERR_NO_SUCH_OBJECT:
2565 13 : ret = EOK;
2566 13 : break;
2567 :
2568 : default:
2569 0 : DEBUG(SSSDBG_CRIT_FAILURE, "LDB Error: %s(%d)\nError Message: [%s]\n",
2570 : ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
2571 0 : ret = sysdb_error_to_errno(ret);
2572 0 : break;
2573 : }
2574 :
2575 : done:
2576 13 : talloc_zfree(tmp_ctx);
2577 13 : return ret;
2578 : }
2579 :
2580 : /* = ASQ search request ======================================== */
2581 :
2582 10 : int sysdb_asq_search(TALLOC_CTX *mem_ctx,
2583 : struct sss_domain_info *domain,
2584 : struct ldb_dn *base_dn,
2585 : const char *expression,
2586 : const char *asq_attribute,
2587 : const char **attrs,
2588 : size_t *msgs_count,
2589 : struct ldb_message ***msgs)
2590 : {
2591 : TALLOC_CTX *tmp_ctx;
2592 : struct ldb_request *ldb_req;
2593 : struct ldb_control **ctrl;
2594 : struct ldb_asq_control *asq_control;
2595 : struct ldb_result *res;
2596 : int ret;
2597 :
2598 10 : tmp_ctx = talloc_new(NULL);
2599 10 : if (!tmp_ctx) {
2600 0 : return ENOMEM;
2601 : }
2602 :
2603 10 : ctrl = talloc_array(tmp_ctx, struct ldb_control *, 2);
2604 10 : if (ctrl == NULL) {
2605 0 : ret = ENOMEM;
2606 0 : goto fail;
2607 : }
2608 :
2609 10 : ctrl[0] = talloc(ctrl, struct ldb_control);
2610 10 : if (ctrl[0] == NULL) {
2611 0 : ret = ENOMEM;
2612 0 : goto fail;
2613 : }
2614 10 : ctrl[1] = NULL;
2615 :
2616 10 : ctrl[0]->oid = LDB_CONTROL_ASQ_OID;
2617 10 : ctrl[0]->critical = 1;
2618 :
2619 10 : asq_control = talloc(ctrl[0], struct ldb_asq_control);
2620 10 : if (asq_control == NULL) {
2621 0 : ret = ENOMEM;
2622 0 : goto fail;
2623 : }
2624 :
2625 10 : asq_control->request = 1;
2626 10 : asq_control->source_attribute = talloc_strdup(asq_control, asq_attribute);
2627 10 : if (asq_control->source_attribute == NULL) {
2628 0 : ret = ENOMEM;
2629 0 : goto fail;
2630 : }
2631 10 : asq_control->src_attr_len = strlen(asq_control->source_attribute);
2632 10 : ctrl[0]->data = asq_control;
2633 :
2634 10 : res = talloc_zero(tmp_ctx, struct ldb_result);
2635 10 : if (!res) {
2636 0 : ret = ENOMEM;
2637 0 : goto fail;
2638 : }
2639 :
2640 10 : ret = ldb_build_search_req(&ldb_req, domain->sysdb->ldb, tmp_ctx,
2641 : base_dn, LDB_SCOPE_BASE,
2642 : expression, attrs, ctrl,
2643 : res, ldb_search_default_callback, NULL);
2644 10 : if (ret != LDB_SUCCESS) {
2645 0 : ret = sysdb_error_to_errno(ret);
2646 0 : goto fail;
2647 : }
2648 :
2649 10 : ret = ldb_request(domain->sysdb->ldb, ldb_req);
2650 10 : if (ret == LDB_SUCCESS) {
2651 10 : ret = ldb_wait(ldb_req->handle, LDB_WAIT_ALL);
2652 : }
2653 10 : if (ret) {
2654 1 : ret = sysdb_error_to_errno(ret);
2655 1 : goto fail;
2656 : }
2657 :
2658 9 : *msgs_count = res->count;
2659 9 : *msgs = talloc_move(mem_ctx, &res->msgs);
2660 :
2661 9 : talloc_zfree(tmp_ctx);
2662 9 : return EOK;
2663 :
2664 : fail:
2665 1 : if (ret == ENOENT) {
2666 1 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
2667 : }
2668 0 : else if (ret) {
2669 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
2670 : }
2671 1 : talloc_zfree(tmp_ctx);
2672 1 : return ret;
2673 : }
2674 :
2675 : /* =Search-Users-with-Custom-Filter====================================== */
2676 :
2677 31 : int sysdb_search_users(TALLOC_CTX *mem_ctx,
2678 : struct sss_domain_info *domain,
2679 : const char *sub_filter,
2680 : const char **attrs,
2681 : size_t *msgs_count,
2682 : struct ldb_message ***msgs)
2683 : {
2684 : TALLOC_CTX *tmp_ctx;
2685 : struct ldb_dn *basedn;
2686 : char *filter;
2687 : int ret;
2688 :
2689 31 : tmp_ctx = talloc_new(NULL);
2690 31 : if (!tmp_ctx) {
2691 0 : return ENOMEM;
2692 : }
2693 :
2694 31 : basedn = sysdb_user_base_dn(tmp_ctx, domain);
2695 31 : if (!basedn) {
2696 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
2697 0 : ret = ENOMEM;
2698 0 : goto fail;
2699 : }
2700 :
2701 31 : filter = talloc_asprintf(tmp_ctx, "(&(%s)%s)", SYSDB_UC, sub_filter);
2702 31 : if (!filter) {
2703 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to build filter\n");
2704 0 : ret = ENOMEM;
2705 0 : goto fail;
2706 : }
2707 :
2708 31 : DEBUG(SSSDBG_TRACE_INTERNAL,
2709 : "Search users with filter: %s\n", filter);
2710 :
2711 31 : ret = sysdb_search_entry(mem_ctx, domain->sysdb, basedn,
2712 : LDB_SCOPE_SUBTREE, filter, attrs,
2713 : msgs_count, msgs);
2714 31 : if (ret) {
2715 19 : goto fail;
2716 : }
2717 :
2718 12 : talloc_zfree(tmp_ctx);
2719 12 : return EOK;
2720 :
2721 : fail:
2722 19 : if (ret == ENOENT) {
2723 19 : DEBUG(SSSDBG_TRACE_INTERNAL, "No such entry\n");
2724 : }
2725 0 : else if (ret) {
2726 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
2727 : }
2728 19 : talloc_zfree(tmp_ctx);
2729 19 : return ret;
2730 : }
2731 :
2732 : /* =Delete-User-by-Name-OR-uid============================================ */
2733 :
2734 112 : int sysdb_delete_user(struct sss_domain_info *domain,
2735 : const char *name, uid_t uid)
2736 : {
2737 : TALLOC_CTX *tmp_ctx;
2738 112 : const char *attrs[] = {SYSDB_GHOST, NULL};
2739 : size_t msg_count;
2740 : char *filter;
2741 : struct ldb_message **msgs;
2742 : struct ldb_message *msg;
2743 : int ret;
2744 : int i;
2745 : char *sanitized_name;
2746 :
2747 112 : tmp_ctx = talloc_new(NULL);
2748 112 : if (!tmp_ctx) {
2749 0 : return ENOMEM;
2750 : }
2751 :
2752 112 : if (name) {
2753 93 : ret = sysdb_search_user_by_name(tmp_ctx, domain, name, NULL, &msg);
2754 : } else {
2755 19 : ret = sysdb_search_user_by_uid(tmp_ctx, domain, uid, NULL, &msg);
2756 : }
2757 112 : if (ret == EOK) {
2758 110 : if (name && uid) {
2759 : /* verify name/gid match */
2760 : const char *c_name;
2761 : uint64_t c_uid;
2762 :
2763 3 : c_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
2764 3 : c_uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
2765 3 : if (c_name == NULL || c_uid == 0) {
2766 0 : DEBUG(SSSDBG_OP_FAILURE,
2767 : "Attribute is missing but this should never happen!\n");
2768 0 : ret = EFAULT;
2769 0 : goto fail;
2770 : }
2771 3 : if (strcmp(name, c_name) || uid != c_uid) {
2772 : /* this is not the entry we are looking for */
2773 0 : ret = EINVAL;
2774 0 : goto fail;
2775 : }
2776 : }
2777 :
2778 110 : ret = sysdb_delete_entry(domain->sysdb, msg->dn, false);
2779 110 : if (ret) {
2780 0 : goto fail;
2781 : }
2782 2 : } else if (ret == ENOENT && name != NULL) {
2783 : /* Perhaps a ghost user? */
2784 1 : ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name);
2785 1 : if (ret != EOK) {
2786 0 : goto fail;
2787 : }
2788 :
2789 1 : filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
2790 : SYSDB_GHOST, sanitized_name);
2791 1 : if (filter == NULL) {
2792 0 : ret = ENOMEM;
2793 0 : goto fail;
2794 : }
2795 :
2796 1 : ret = sysdb_search_groups(tmp_ctx, domain, filter, attrs,
2797 : &msg_count, &msgs);
2798 1 : if (ret != EOK) {
2799 1 : goto fail;
2800 : }
2801 :
2802 0 : for (i = 0; i < msg_count; i++) {
2803 0 : msg = ldb_msg_new(tmp_ctx);
2804 0 : if (!msg) {
2805 0 : ERROR_OUT(ret, ENOMEM, fail);
2806 : }
2807 :
2808 0 : msg->dn = msgs[i]->dn;
2809 :
2810 0 : ret = add_string(msg, LDB_FLAG_MOD_DELETE, SYSDB_GHOST, name);
2811 0 : if (ret) goto fail;
2812 :
2813 0 : ret = ldb_modify(domain->sysdb->ldb, msg);
2814 0 : if (ret != LDB_SUCCESS) {
2815 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2816 : "ldb_modify failed: [%s](%d)[%s]\n",
2817 : ldb_strerror(ret), ret,
2818 : ldb_errstring(domain->sysdb->ldb));
2819 : }
2820 0 : ret = sysdb_error_to_errno(ret);
2821 0 : if (ret != EOK) {
2822 0 : goto fail;
2823 : }
2824 :
2825 0 : talloc_zfree(msg);
2826 : }
2827 : } else {
2828 : goto fail;
2829 : }
2830 :
2831 :
2832 110 : talloc_zfree(tmp_ctx);
2833 110 : return EOK;
2834 :
2835 : fail:
2836 2 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
2837 2 : talloc_zfree(tmp_ctx);
2838 2 : return ret;
2839 : }
2840 :
2841 :
2842 : /* =Search-Groups-with-Custom-Filter===================================== */
2843 :
2844 30 : int sysdb_search_groups(TALLOC_CTX *mem_ctx,
2845 : struct sss_domain_info *domain,
2846 : const char *sub_filter,
2847 : const char **attrs,
2848 : size_t *msgs_count,
2849 : struct ldb_message ***msgs)
2850 : {
2851 : TALLOC_CTX *tmp_ctx;
2852 : struct ldb_dn *basedn;
2853 : char *filter;
2854 : int ret;
2855 :
2856 30 : tmp_ctx = talloc_new(NULL);
2857 30 : if (!tmp_ctx) {
2858 0 : return ENOMEM;
2859 : }
2860 :
2861 30 : basedn = sysdb_group_base_dn(tmp_ctx, domain);
2862 30 : if (!basedn) {
2863 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
2864 0 : ret = ENOMEM;
2865 0 : goto fail;
2866 : }
2867 :
2868 30 : filter = talloc_asprintf(tmp_ctx, "(&(%s)%s)", SYSDB_GC, sub_filter);
2869 30 : if (!filter) {
2870 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to build filter\n");
2871 0 : ret = ENOMEM;
2872 0 : goto fail;
2873 : }
2874 :
2875 30 : DEBUG(SSSDBG_TRACE_INTERNAL,
2876 : "Search groups with filter: %s\n", filter);
2877 :
2878 30 : ret = sysdb_search_entry(mem_ctx, domain->sysdb, basedn,
2879 : LDB_SCOPE_SUBTREE, filter, attrs,
2880 : msgs_count, msgs);
2881 30 : if (ret) {
2882 19 : goto fail;
2883 : }
2884 :
2885 11 : talloc_zfree(tmp_ctx);
2886 11 : return EOK;
2887 :
2888 : fail:
2889 19 : if (ret == ENOENT) {
2890 19 : DEBUG(SSSDBG_TRACE_INTERNAL, "No such entry\n");
2891 : }
2892 0 : else if (ret) {
2893 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
2894 : }
2895 19 : talloc_zfree(tmp_ctx);
2896 19 : return ret;
2897 : }
2898 :
2899 : /* =Delete-Group-by-Name-OR-gid=========================================== */
2900 :
2901 132 : int sysdb_delete_group(struct sss_domain_info *domain,
2902 : const char *name, gid_t gid)
2903 : {
2904 : TALLOC_CTX *tmp_ctx;
2905 : struct ldb_message *msg;
2906 : int ret;
2907 :
2908 132 : tmp_ctx = talloc_new(NULL);
2909 132 : if (!tmp_ctx) {
2910 0 : return ENOMEM;
2911 : }
2912 :
2913 132 : if (name) {
2914 28 : ret = sysdb_search_group_by_name(tmp_ctx, domain, name, NULL, &msg);
2915 : } else {
2916 104 : ret = sysdb_search_group_by_gid(tmp_ctx, domain, gid, NULL, &msg);
2917 : }
2918 132 : if (ret) {
2919 3 : goto fail;
2920 : }
2921 :
2922 129 : if (name && gid) {
2923 : /* verify name/gid match */
2924 : const char *c_name;
2925 : uint64_t c_gid;
2926 :
2927 2 : c_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
2928 2 : c_gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
2929 2 : if (c_name == NULL || c_gid == 0) {
2930 0 : DEBUG(SSSDBG_OP_FAILURE,
2931 : "Attribute is missing but this should never happen!\n");
2932 0 : ret = EFAULT;
2933 0 : goto fail;
2934 : }
2935 2 : if (strcmp(name, c_name) || gid != c_gid) {
2936 : /* this is not the entry we are looking for */
2937 0 : ret = EINVAL;
2938 0 : goto fail;
2939 : }
2940 : }
2941 :
2942 129 : ret = sysdb_delete_entry(domain->sysdb, msg->dn, false);
2943 129 : if (ret) {
2944 0 : goto fail;
2945 : }
2946 :
2947 129 : talloc_zfree(tmp_ctx);
2948 129 : return EOK;
2949 :
2950 : fail:
2951 3 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
2952 3 : talloc_zfree(tmp_ctx);
2953 3 : return ret;
2954 : }
2955 :
2956 : /* =Search-Netgroups-with-Custom-Filter===================================== */
2957 :
2958 1 : int sysdb_search_netgroups(TALLOC_CTX *mem_ctx,
2959 : struct sss_domain_info *domain,
2960 : const char *sub_filter,
2961 : const char **attrs,
2962 : size_t *msgs_count,
2963 : struct ldb_message ***msgs)
2964 : {
2965 : TALLOC_CTX *tmp_ctx;
2966 : struct ldb_dn *basedn;
2967 : char *filter;
2968 : int ret;
2969 :
2970 1 : tmp_ctx = talloc_new(NULL);
2971 1 : if (!tmp_ctx) {
2972 0 : return ENOMEM;
2973 : }
2974 :
2975 1 : basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
2976 : SYSDB_TMPL_NETGROUP_BASE, domain->name);
2977 1 : if (!basedn) {
2978 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
2979 0 : ret = ENOMEM;
2980 0 : goto fail;
2981 : }
2982 :
2983 1 : filter = talloc_asprintf(tmp_ctx, "(&(%s)%s)", SYSDB_NC, sub_filter);
2984 1 : if (!filter) {
2985 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to build filter\n");
2986 0 : ret = ENOMEM;
2987 0 : goto fail;
2988 : }
2989 :
2990 1 : DEBUG(SSSDBG_TRACE_FUNC, "Search netgroups with filter: %s\n", filter);
2991 :
2992 1 : ret = sysdb_search_entry(mem_ctx, domain->sysdb, basedn,
2993 : LDB_SCOPE_SUBTREE, filter, attrs,
2994 : msgs_count, msgs);
2995 1 : if (ret) {
2996 1 : goto fail;
2997 : }
2998 :
2999 0 : talloc_zfree(tmp_ctx);
3000 0 : return EOK;
3001 :
3002 : fail:
3003 1 : if (ret == ENOENT) {
3004 1 : DEBUG(SSSDBG_TRACE_FUNC, "Entry not found\n");
3005 : } else {
3006 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
3007 : }
3008 1 : talloc_zfree(tmp_ctx);
3009 1 : return ret;
3010 : }
3011 :
3012 : /* =Delete-Netgroup-by-Name============================================== */
3013 :
3014 5 : int sysdb_delete_netgroup(struct sss_domain_info *domain,
3015 : const char *name)
3016 : {
3017 : TALLOC_CTX *tmp_ctx;
3018 : struct ldb_message *msg;
3019 : int ret;
3020 :
3021 5 : if (!name) return EINVAL;
3022 :
3023 5 : tmp_ctx = talloc_new(NULL);
3024 5 : if (!tmp_ctx) {
3025 0 : return ENOMEM;
3026 : }
3027 :
3028 5 : ret = sysdb_search_netgroup_by_name(tmp_ctx, domain, name, NULL, &msg);
3029 5 : if (ret != EOK && ret != ENOENT) {
3030 0 : DEBUG(SSSDBG_TRACE_FUNC,
3031 : "sysdb_search_netgroup_by_name failed: %d (%s)\n",
3032 : ret, strerror(ret));
3033 0 : goto done;
3034 5 : } else if (ret == ENOENT) {
3035 0 : DEBUG(SSSDBG_TRACE_FUNC,
3036 : "Netgroup does not exist, nothing to delete\n");
3037 0 : ret = EOK;
3038 0 : goto done;
3039 : }
3040 :
3041 5 : ret = sysdb_delete_entry(domain->sysdb, msg->dn, false);
3042 5 : if (ret != EOK) {
3043 0 : goto done;
3044 : }
3045 :
3046 : done:
3047 5 : if (ret != EOK) {
3048 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
3049 : }
3050 5 : talloc_free(tmp_ctx);
3051 5 : return ret;
3052 : }
3053 :
3054 2 : int sysdb_delete_by_sid(struct sysdb_ctx *sysdb,
3055 : struct sss_domain_info *domain,
3056 : const char *sid_str)
3057 : {
3058 : TALLOC_CTX *tmp_ctx;
3059 : struct ldb_result *res;
3060 : int ret;
3061 :
3062 2 : if (!sid_str) return EINVAL;
3063 :
3064 2 : tmp_ctx = talloc_new(NULL);
3065 2 : if (!tmp_ctx) {
3066 0 : return ENOMEM;
3067 : }
3068 :
3069 2 : ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res);
3070 :
3071 2 : if (ret == ENOENT) {
3072 : /* No existing entry. Just quit. */
3073 1 : DEBUG(SSSDBG_TRACE_FUNC,
3074 : "search by sid did not return any results.\n");
3075 1 : ret = EOK;
3076 1 : goto done;
3077 1 : } else if (ret != EOK) {
3078 0 : DEBUG(SSSDBG_OP_FAILURE, "search by sid failed: %d (%s)\n",
3079 : ret, strerror(ret));
3080 0 : goto done;
3081 : }
3082 :
3083 1 : if (res->count > 1) {
3084 0 : DEBUG(SSSDBG_FATAL_FAILURE, "getbysid call returned more than one " \
3085 : "result !?!\n");
3086 0 : ret = EIO;
3087 0 : goto done;
3088 : }
3089 :
3090 1 : ret = sysdb_delete_entry(sysdb, res->msgs[0]->dn, false);
3091 1 : if (ret != EOK) {
3092 0 : goto done;
3093 : }
3094 :
3095 : done:
3096 2 : if (ret != EOK) {
3097 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
3098 : }
3099 2 : talloc_free(tmp_ctx);
3100 2 : return ret;
3101 : }
3102 :
3103 : /* ========= Authentication against cached password ============ */
3104 :
3105 :
3106 34 : errno_t check_failed_login_attempts(struct confdb_ctx *cdb,
3107 : struct ldb_message *ldb_msg,
3108 : uint32_t *failed_login_attempts,
3109 : time_t *delayed_until)
3110 : {
3111 : int ret;
3112 : int allowed_failed_login_attempts;
3113 : int failed_login_delay;
3114 : time_t last_failed_login;
3115 : time_t end;
3116 : TALLOC_CTX *tmp_ctx;
3117 :
3118 34 : tmp_ctx = talloc_new(NULL);
3119 34 : if (!tmp_ctx) {
3120 0 : return ENOMEM;
3121 : }
3122 :
3123 34 : *delayed_until = -1;
3124 34 : *failed_login_attempts = ldb_msg_find_attr_as_uint(ldb_msg,
3125 : SYSDB_FAILED_LOGIN_ATTEMPTS, 0);
3126 34 : last_failed_login = (time_t) ldb_msg_find_attr_as_int64(ldb_msg,
3127 : SYSDB_LAST_FAILED_LOGIN, 0);
3128 34 : ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
3129 : CONFDB_PAM_FAILED_LOGIN_ATTEMPTS,
3130 : CONFDB_DEFAULT_PAM_FAILED_LOGIN_ATTEMPTS,
3131 : &allowed_failed_login_attempts);
3132 34 : if (ret != EOK) {
3133 0 : DEBUG(SSSDBG_CRIT_FAILURE,
3134 : "Failed to read the number of allowed failed login "
3135 : "attempts.\n");
3136 0 : ret = ERR_INTERNAL;
3137 0 : goto done;
3138 : }
3139 34 : ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
3140 : CONFDB_PAM_FAILED_LOGIN_DELAY,
3141 : CONFDB_DEFAULT_PAM_FAILED_LOGIN_DELAY,
3142 : &failed_login_delay);
3143 34 : if (ret != EOK) {
3144 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to read the failed login delay.\n");
3145 0 : ret = ERR_INTERNAL;
3146 0 : goto done;
3147 : }
3148 34 : DEBUG(SSSDBG_TRACE_ALL,
3149 : "Failed login attempts [%d], allowed failed login attempts [%d], "
3150 : "failed login delay [%d].\n", *failed_login_attempts,
3151 : allowed_failed_login_attempts, failed_login_delay);
3152 :
3153 34 : if (allowed_failed_login_attempts) {
3154 8 : if (*failed_login_attempts >= allowed_failed_login_attempts) {
3155 4 : if (failed_login_delay) {
3156 2 : end = last_failed_login + (failed_login_delay * 60);
3157 2 : if (end < time(NULL)) {
3158 1 : DEBUG(SSSDBG_TRACE_LIBS, "failed_login_delay has passed, "
3159 : "resetting failed_login_attempts.\n");
3160 1 : *failed_login_attempts = 0;
3161 : } else {
3162 1 : DEBUG(SSSDBG_TRACE_LIBS,
3163 : "login delayed until %lld.\n", (long long) end);
3164 1 : *delayed_until = end;
3165 1 : ret = ERR_AUTH_DENIED;
3166 1 : goto done;
3167 : }
3168 : } else {
3169 2 : DEBUG(SSSDBG_CONF_SETTINGS, "Too many failed logins.\n");
3170 2 : ret = ERR_AUTH_DENIED;
3171 2 : goto done;
3172 : }
3173 : }
3174 : }
3175 :
3176 31 : ret = EOK;
3177 : done:
3178 34 : talloc_free(tmp_ctx);
3179 34 : return ret;
3180 : }
3181 :
3182 9 : static errno_t check_for_combined_2fa_password(struct sss_domain_info *domain,
3183 : struct ldb_message *ldb_msg,
3184 : const char *password,
3185 : const char *userhash)
3186 : {
3187 :
3188 : unsigned int cached_authtok_type;
3189 : unsigned int cached_fa2_len;
3190 : char *short_pw;
3191 : char *comphash;
3192 : size_t pw_len;
3193 : TALLOC_CTX *tmp_ctx;
3194 : int ret;
3195 :
3196 9 : cached_authtok_type = ldb_msg_find_attr_as_uint(ldb_msg,
3197 : SYSDB_CACHEDPWD_TYPE,
3198 : SSS_AUTHTOK_TYPE_EMPTY);
3199 9 : if (cached_authtok_type != SSS_AUTHTOK_TYPE_2FA) {
3200 4 : DEBUG(SSSDBG_TRACE_LIBS, "Wrong authtok type.\n");
3201 4 : return EINVAL;
3202 : }
3203 :
3204 5 : cached_fa2_len = ldb_msg_find_attr_as_uint(ldb_msg, SYSDB_CACHEDPWD_FA2_LEN,
3205 : 0);
3206 5 : if (cached_fa2_len == 0) {
3207 0 : DEBUG(SSSDBG_TRACE_LIBS, "Second factor size not available.\n");
3208 0 : return EINVAL;
3209 : }
3210 :
3211 5 : pw_len = strlen(password);
3212 5 : if (pw_len < cached_fa2_len + domain->cache_credentials_min_ff_length) {
3213 3 : DEBUG(SSSDBG_TRACE_LIBS, "Password too short.\n");
3214 3 : return EINVAL;
3215 : }
3216 :
3217 2 : tmp_ctx = talloc_new(NULL);
3218 2 : if (tmp_ctx == NULL) {
3219 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
3220 0 : return ENOMEM;
3221 : }
3222 :
3223 2 : short_pw = talloc_strndup(tmp_ctx, password, (pw_len - cached_fa2_len));
3224 2 : if (short_pw == NULL) {
3225 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
3226 0 : ret = ENOMEM;
3227 0 : goto done;
3228 : }
3229 :
3230 2 : ret = s3crypt_sha512(tmp_ctx, short_pw, userhash, &comphash);
3231 2 : if (ret != EOK) {
3232 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Failed to create password hash.\n");
3233 0 : ret = ERR_INTERNAL;
3234 0 : goto done;
3235 : }
3236 :
3237 2 : if (strcmp(userhash, comphash) != 0) {
3238 1 : DEBUG(SSSDBG_MINOR_FAILURE,
3239 : "Hash of shorten password does not match.\n");
3240 1 : ret = ERR_AUTH_FAILED;
3241 1 : goto done;
3242 : }
3243 :
3244 1 : ret = EOK;
3245 :
3246 : done:
3247 2 : talloc_free(tmp_ctx);
3248 :
3249 2 : return ret;
3250 : }
3251 :
3252 18 : int sysdb_cache_auth(struct sss_domain_info *domain,
3253 : const char *name,
3254 : const char *password,
3255 : struct confdb_ctx *cdb,
3256 : bool just_check,
3257 : time_t *_expire_date,
3258 : time_t *_delayed_until)
3259 : {
3260 : TALLOC_CTX *tmp_ctx;
3261 18 : const char *attrs[] = { SYSDB_NAME, SYSDB_CACHEDPWD, SYSDB_DISABLED,
3262 : SYSDB_LAST_LOGIN, SYSDB_LAST_ONLINE_AUTH,
3263 : "lastCachedPasswordChange",
3264 : "accountExpires", SYSDB_FAILED_LOGIN_ATTEMPTS,
3265 : SYSDB_LAST_FAILED_LOGIN, SYSDB_CACHEDPWD_TYPE,
3266 : SYSDB_CACHEDPWD_FA2_LEN, NULL };
3267 : struct ldb_message *ldb_msg;
3268 : const char *userhash;
3269 : char *comphash;
3270 18 : uint64_t lastLogin = 0;
3271 : int cred_expiration;
3272 18 : uint32_t failed_login_attempts = 0;
3273 : struct sysdb_attrs *update_attrs;
3274 18 : bool authentication_successful = false;
3275 18 : time_t expire_date = -1;
3276 18 : time_t delayed_until = -1;
3277 : int ret;
3278 :
3279 18 : if (name == NULL || *name == '\0') {
3280 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing user name.\n");
3281 0 : return EINVAL;
3282 : }
3283 :
3284 18 : if (cdb == NULL) {
3285 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing config db context.\n");
3286 0 : return EINVAL;
3287 : }
3288 :
3289 18 : if (domain->sysdb == NULL) {
3290 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing sysdb db context.\n");
3291 0 : return EINVAL;
3292 : }
3293 :
3294 18 : if (!domain->cache_credentials) {
3295 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Cached credentials not available.\n");
3296 0 : return EINVAL;
3297 : }
3298 :
3299 18 : tmp_ctx = talloc_new(NULL);
3300 18 : if (!tmp_ctx) {
3301 0 : return ENOMEM;
3302 : }
3303 :
3304 18 : ret = ldb_transaction_start(domain->sysdb->ldb);
3305 18 : if (ret) {
3306 0 : talloc_zfree(tmp_ctx);
3307 0 : ret = sysdb_error_to_errno(ret);
3308 0 : return ret;
3309 : }
3310 :
3311 18 : ret = sysdb_search_user_by_name(tmp_ctx, domain, name, attrs, &ldb_msg);
3312 18 : if (ret != EOK) {
3313 0 : DEBUG(SSSDBG_CRIT_FAILURE,
3314 : "sysdb_search_user_by_name failed [%d][%s].\n",
3315 : ret, strerror(ret));
3316 0 : if (ret == ENOENT) ret = ERR_ACCOUNT_UNKNOWN;
3317 0 : goto done;
3318 : }
3319 :
3320 : /* Check offline_auth_cache_timeout */
3321 18 : lastLogin = ldb_msg_find_attr_as_uint64(ldb_msg,
3322 : SYSDB_LAST_ONLINE_AUTH,
3323 : 0);
3324 :
3325 18 : ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
3326 : CONFDB_PAM_CRED_TIMEOUT, 0, &cred_expiration);
3327 18 : if (ret != EOK) {
3328 0 : DEBUG(SSSDBG_CRIT_FAILURE,
3329 : "Failed to read expiration time of offline credentials.\n");
3330 0 : goto done;
3331 : }
3332 18 : DEBUG(SSSDBG_TRACE_ALL, "Offline credentials expiration is [%d] days.\n",
3333 : cred_expiration);
3334 :
3335 18 : if (cred_expiration) {
3336 3 : expire_date = lastLogin + (cred_expiration * 86400);
3337 3 : if (expire_date < time(NULL)) {
3338 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Cached user entry is too old.\n");
3339 0 : expire_date = 0;
3340 0 : ret = ERR_CACHED_CREDS_EXPIRED;
3341 0 : goto done;
3342 : }
3343 : } else {
3344 15 : expire_date = 0;
3345 : }
3346 :
3347 18 : ret = check_failed_login_attempts(cdb, ldb_msg, &failed_login_attempts,
3348 : &delayed_until);
3349 18 : if (ret != EOK) {
3350 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to check login attempts\n");
3351 0 : goto done;
3352 : }
3353 :
3354 : /* TODO: verify user account (disabled, expired ...) */
3355 :
3356 18 : userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL);
3357 18 : if (userhash == NULL || *userhash == '\0') {
3358 3 : DEBUG(SSSDBG_CONF_SETTINGS, "Cached credentials not available.\n");
3359 3 : ret = ERR_NO_CACHED_CREDS;
3360 3 : goto done;
3361 : }
3362 :
3363 15 : ret = s3crypt_sha512(tmp_ctx, password, userhash, &comphash);
3364 15 : if (ret) {
3365 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Failed to create password hash.\n");
3366 0 : ret = ERR_INTERNAL;
3367 0 : goto done;
3368 : }
3369 :
3370 15 : update_attrs = sysdb_new_attrs(tmp_ctx);
3371 15 : if (update_attrs == NULL) {
3372 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_new_attrs failed.\n");
3373 0 : ret = ENOMEM;
3374 0 : goto done;
3375 : }
3376 :
3377 15 : if (strcmp(userhash, comphash) == 0
3378 9 : || check_for_combined_2fa_password(domain, ldb_msg,
3379 : password, userhash) == EOK) {
3380 : /* TODO: probable good point for audit logging */
3381 7 : DEBUG(SSSDBG_CONF_SETTINGS, "Hashes do match!\n");
3382 7 : authentication_successful = true;
3383 :
3384 7 : if (just_check) {
3385 0 : ret = EOK;
3386 0 : goto done;
3387 : }
3388 :
3389 7 : ret = sysdb_attrs_add_time_t(update_attrs,
3390 : SYSDB_LAST_LOGIN, time(NULL));
3391 7 : if (ret != EOK) {
3392 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_add_time_t failed, "
3393 : "but authentication is successful.\n");
3394 0 : ret = EOK;
3395 0 : goto done;
3396 : }
3397 :
3398 7 : ret = sysdb_attrs_add_uint32(update_attrs,
3399 : SYSDB_FAILED_LOGIN_ATTEMPTS, 0U);
3400 14 : if (ret != EOK) {
3401 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_add_uint32 failed, "
3402 : "but authentication is successful.\n");
3403 0 : ret = EOK;
3404 0 : goto done;
3405 : }
3406 :
3407 : } else {
3408 8 : DEBUG(SSSDBG_CONF_SETTINGS, "Authentication failed.\n");
3409 8 : authentication_successful = false;
3410 :
3411 8 : ret = sysdb_attrs_add_time_t(update_attrs,
3412 : SYSDB_LAST_FAILED_LOGIN,
3413 : time(NULL));
3414 8 : if (ret != EOK) {
3415 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_add_time_t failed.\n");
3416 0 : goto done;
3417 : }
3418 :
3419 8 : ret = sysdb_attrs_add_uint32(update_attrs,
3420 : SYSDB_FAILED_LOGIN_ATTEMPTS,
3421 : ++failed_login_attempts);
3422 8 : if (ret != EOK) {
3423 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_add_uint32 failed.\n");
3424 0 : goto done;
3425 : }
3426 : }
3427 :
3428 15 : ret = sysdb_set_user_attr(domain, name, update_attrs,
3429 : LDB_FLAG_MOD_REPLACE);
3430 15 : if (ret) {
3431 0 : DEBUG(SSSDBG_CRIT_FAILURE,
3432 : "Failed to update Login attempt information!\n");
3433 : }
3434 :
3435 : done:
3436 18 : if (_expire_date != NULL) {
3437 18 : *_expire_date = expire_date;
3438 : }
3439 18 : if (_delayed_until != NULL) {
3440 18 : *_delayed_until = delayed_until;
3441 : }
3442 18 : if (ret) {
3443 3 : ldb_transaction_cancel(domain->sysdb->ldb);
3444 : } else {
3445 15 : ret = ldb_transaction_commit(domain->sysdb->ldb);
3446 15 : ret = sysdb_error_to_errno(ret);
3447 15 : if (ret) {
3448 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to commit transaction!\n");
3449 : }
3450 : }
3451 18 : if (authentication_successful) {
3452 7 : ret = EOK;
3453 : } else {
3454 11 : if (ret == EOK) {
3455 8 : ret = ERR_AUTH_FAILED;
3456 : }
3457 : }
3458 18 : talloc_free(tmp_ctx);
3459 18 : return ret;
3460 : }
3461 :
3462 5 : static errno_t sysdb_update_members_ex(struct sss_domain_info *domain,
3463 : const char *member,
3464 : enum sysdb_member_type type,
3465 : const char *const *add_groups,
3466 : const char *const *del_groups,
3467 : bool is_dn)
3468 : {
3469 : errno_t ret;
3470 : errno_t sret;
3471 : int i;
3472 5 : bool in_transaction = false;
3473 :
3474 5 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
3475 5 : if(!tmp_ctx) {
3476 0 : return ENOMEM;
3477 : }
3478 :
3479 5 : ret = sysdb_transaction_start(domain->sysdb);
3480 5 : if (ret != EOK) {
3481 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to start update transaction\n");
3482 0 : goto done;
3483 : }
3484 :
3485 5 : in_transaction = true;
3486 :
3487 5 : if (add_groups) {
3488 : /* Add the user to all add_groups */
3489 9 : for (i = 0; add_groups[i]; i++) {
3490 5 : ret = sysdb_add_group_member(domain, add_groups[i],
3491 : member, type, is_dn);
3492 5 : if (ret != EOK) {
3493 0 : DEBUG(SSSDBG_CRIT_FAILURE,
3494 : "Could not add member [%s] to group [%s]. "
3495 : "Skipping.\n", member, add_groups[i]);
3496 : /* Continue on, we should try to finish the rest */
3497 : }
3498 : }
3499 : }
3500 :
3501 5 : if (del_groups) {
3502 : /* Remove the user from all del_groups */
3503 5 : for (i = 0; del_groups[i]; i++) {
3504 3 : ret = sysdb_remove_group_member(domain, del_groups[i],
3505 : member, type, is_dn);
3506 3 : if (ret != EOK) {
3507 0 : DEBUG(SSSDBG_CRIT_FAILURE,
3508 : "Could not remove member [%s] from group [%s]. "
3509 : "Skipping\n", member, del_groups[i]);
3510 : /* Continue on, we should try to finish the rest */
3511 : }
3512 : }
3513 : }
3514 :
3515 5 : ret = sysdb_transaction_commit(domain->sysdb);
3516 5 : if (ret != EOK) {
3517 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
3518 0 : goto done;
3519 : }
3520 :
3521 5 : in_transaction = false;
3522 :
3523 : done:
3524 5 : if (in_transaction) {
3525 0 : sret = sysdb_transaction_cancel(domain->sysdb);
3526 0 : if (sret != EOK) {
3527 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
3528 : }
3529 : }
3530 5 : talloc_free(tmp_ctx);
3531 5 : return ret;
3532 : }
3533 :
3534 3 : errno_t sysdb_update_members(struct sss_domain_info *domain,
3535 : const char *member,
3536 : enum sysdb_member_type type,
3537 : const char *const *add_groups,
3538 : const char *const *del_groups)
3539 : {
3540 3 : return sysdb_update_members_ex(domain, member, type,
3541 : add_groups, del_groups, false);
3542 : }
3543 :
3544 2 : errno_t sysdb_update_members_dn(struct sss_domain_info *member_domain,
3545 : const char *member,
3546 : enum sysdb_member_type type,
3547 : const char *const *add_groups,
3548 : const char *const *del_groups)
3549 : {
3550 2 : return sysdb_update_members_ex(member_domain, member, type,
3551 : add_groups, del_groups, true);
3552 : }
3553 :
3554 10 : errno_t sysdb_remove_attrs(struct sss_domain_info *domain,
3555 : const char *name,
3556 : enum sysdb_member_type type,
3557 : char **remove_attrs)
3558 : {
3559 : errno_t ret;
3560 10 : errno_t sret = EOK;
3561 10 : bool in_transaction = false;
3562 : struct ldb_message *msg;
3563 : int lret;
3564 : size_t i;
3565 :
3566 10 : msg = ldb_msg_new(NULL);
3567 10 : if (!msg) return ENOMEM;
3568 :
3569 10 : switch(type) {
3570 : case SYSDB_MEMBER_USER:
3571 10 : msg->dn = sysdb_user_dn(msg, domain, name);
3572 10 : break;
3573 :
3574 : case SYSDB_MEMBER_GROUP:
3575 0 : msg->dn = sysdb_group_dn(msg, domain, name);
3576 0 : break;
3577 :
3578 : case SYSDB_MEMBER_NETGROUP:
3579 0 : msg->dn = sysdb_netgroup_dn(msg, domain, name);
3580 0 : break;
3581 :
3582 : case SYSDB_MEMBER_SERVICE:
3583 0 : msg->dn = sysdb_svc_dn(domain->sysdb, msg, domain->name, name);
3584 0 : break;
3585 : }
3586 10 : if (!msg->dn) {
3587 0 : ret = ENOMEM;
3588 0 : goto done;
3589 : }
3590 :
3591 10 : ret = sysdb_transaction_start(domain->sysdb);
3592 10 : if (ret != EOK) {
3593 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
3594 0 : goto done;
3595 : }
3596 :
3597 10 : in_transaction = true;
3598 :
3599 20 : for (i = 0; remove_attrs[i]; i++) {
3600 : /* SYSDB_MEMBEROF is exclusively handled by the memberof plugin */
3601 10 : if (strcasecmp(remove_attrs[i], SYSDB_MEMBEROF) == 0) {
3602 0 : continue;
3603 : }
3604 10 : DEBUG(SSSDBG_TRACE_INTERNAL, "Removing attribute [%s] from [%s]\n",
3605 : remove_attrs[i], name);
3606 10 : lret = ldb_msg_add_empty(msg, remove_attrs[i],
3607 : LDB_FLAG_MOD_DELETE, NULL);
3608 10 : if (lret != LDB_SUCCESS) {
3609 0 : ret = sysdb_error_to_errno(lret);
3610 0 : goto done;
3611 : }
3612 :
3613 : /* We need to do individual modifies so that we can
3614 : * skip unknown attributes. Otherwise, any nonexistent
3615 : * attribute in the sysdb will cause other removals to
3616 : * fail.
3617 : */
3618 10 : lret = ldb_modify(domain->sysdb->ldb, msg);
3619 10 : if (lret != LDB_SUCCESS && lret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
3620 0 : DEBUG(SSSDBG_MINOR_FAILURE,
3621 : "ldb_modify failed: [%s](%d)[%s]\n",
3622 : ldb_strerror(lret), lret, ldb_errstring(domain->sysdb->ldb));
3623 0 : ret = sysdb_error_to_errno(lret);
3624 0 : goto done;
3625 : }
3626 :
3627 : /* Remove this attribute and move on to the next one */
3628 10 : ldb_msg_remove_attr(msg, remove_attrs[i]);
3629 : }
3630 :
3631 10 : ret = sysdb_transaction_commit(domain->sysdb);
3632 10 : if (ret != EOK) {
3633 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
3634 0 : goto done;
3635 : }
3636 :
3637 10 : in_transaction = false;
3638 :
3639 10 : ret = EOK;
3640 : done:
3641 10 : if (in_transaction) {
3642 0 : sret = sysdb_transaction_cancel(domain->sysdb);
3643 0 : if (sret != EOK) {
3644 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
3645 : }
3646 : }
3647 10 : talloc_free(msg);
3648 10 : return ret;
3649 : }
3650 :
3651 26 : static errno_t sysdb_search_object_by_str_attr(TALLOC_CTX *mem_ctx,
3652 : struct sss_domain_info *domain,
3653 : const char *filter_tmpl,
3654 : const char *str,
3655 : const char **attrs,
3656 : struct ldb_result **_res)
3657 : {
3658 : TALLOC_CTX *tmp_ctx;
3659 26 : const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM,
3660 : ORIGINALAD_PREFIX SYSDB_NAME,
3661 : SYSDB_DEFAULT_ATTRS,
3662 : NULL };
3663 : struct ldb_dn *basedn;
3664 : int ret;
3665 26 : struct ldb_result *res = NULL;
3666 :
3667 26 : tmp_ctx = talloc_new(NULL);
3668 26 : if (!tmp_ctx) {
3669 0 : return ENOMEM;
3670 : }
3671 :
3672 26 : basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_DOM_BASE,
3673 : domain->name);
3674 26 : if (basedn == NULL) {
3675 0 : DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
3676 0 : ret = ENOMEM;
3677 0 : goto done;
3678 : }
3679 :
3680 26 : ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
3681 : basedn, LDB_SCOPE_SUBTREE, attrs?attrs:def_attrs,
3682 : filter_tmpl, str);
3683 26 : if (ret != EOK) {
3684 0 : ret = sysdb_error_to_errno(ret);
3685 0 : DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n");
3686 0 : goto done;
3687 : }
3688 :
3689 26 : if (res->count > 1) {
3690 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Search for [%s] with filter [%s] " \
3691 : "returned more than one object.\n",
3692 : str, filter_tmpl);
3693 0 : ret = EINVAL;
3694 0 : goto done;
3695 26 : } else if (res->count == 0) {
3696 15 : ret = ENOENT;
3697 15 : goto done;
3698 : }
3699 :
3700 11 : *_res = talloc_steal(mem_ctx, res);
3701 :
3702 : done:
3703 26 : if (ret == ENOENT) {
3704 15 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry.\n");
3705 11 : } else if (ret) {
3706 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
3707 : }
3708 :
3709 26 : talloc_zfree(tmp_ctx);
3710 26 : return ret;
3711 : }
3712 :
3713 8 : errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
3714 : struct sss_domain_info *domain,
3715 : const char *sid_str,
3716 : const char **attrs,
3717 : struct ldb_result **res)
3718 : {
3719 8 : return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER,
3720 : sid_str, attrs, res);
3721 : }
3722 :
3723 4 : errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
3724 : struct sss_domain_info *domain,
3725 : const char *uuid_str,
3726 : const char **attrs,
3727 : struct ldb_result **res)
3728 : {
3729 4 : return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_UUID_FILTER,
3730 : uuid_str, attrs, res);
3731 : }
3732 :
3733 14 : errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx,
3734 : struct sss_domain_info *domain,
3735 : const char *cert,
3736 : const char **attrs,
3737 : struct ldb_result **res)
3738 : {
3739 : int ret;
3740 : char *user_filter;
3741 :
3742 14 : ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_CERT,
3743 : &user_filter);
3744 14 : if (ret != EOK) {
3745 0 : DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n");
3746 0 : return ret;
3747 : }
3748 :
3749 14 : ret = sysdb_search_object_by_str_attr(mem_ctx, domain,
3750 : SYSDB_USER_CERT_FILTER,
3751 : user_filter, attrs, res);
3752 14 : talloc_free(user_filter);
3753 :
3754 14 : return ret;
3755 : }
3756 :
3757 14 : errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
3758 : struct sss_domain_info *domain,
3759 : const char *cert,
3760 : struct ldb_result **res)
3761 : {
3762 14 : const char *user_attrs[] = SYSDB_PW_ATTRS;
3763 :
3764 14 : return sysdb_search_object_by_cert(mem_ctx, domain, cert, user_attrs, res);
3765 : }
3766 :
3767 0 : errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx,
3768 : struct sss_domain_info *dom,
3769 : const char *group_name,
3770 : const char ***_sids,
3771 : const char ***_dns,
3772 : size_t *_n)
3773 : {
3774 : errno_t ret;
3775 : size_t i, m_count;
3776 : TALLOC_CTX *tmp_ctx;
3777 : struct ldb_message *msg;
3778 : struct ldb_message **members;
3779 0 : const char *attrs[] = { SYSDB_SID_STR, NULL };
3780 0 : const char **sids = NULL, **dns = NULL;
3781 0 : size_t n = 0;
3782 :
3783 0 : tmp_ctx = talloc_new(NULL);
3784 0 : if (tmp_ctx == NULL) {
3785 0 : return ENOMEM;
3786 : }
3787 :
3788 0 : ret = sysdb_search_group_by_name(tmp_ctx, dom, group_name, NULL, &msg);
3789 0 : if (ret != EOK) {
3790 0 : goto done;
3791 : }
3792 :
3793 : /* Get sid_str attribute of all elemets pointed to by group members */
3794 0 : ret = sysdb_asq_search(tmp_ctx, dom, msg->dn, NULL, SYSDB_MEMBER, attrs,
3795 : &m_count, &members);
3796 0 : if (ret != EOK) {
3797 0 : goto done;
3798 : }
3799 :
3800 0 : sids = talloc_array(tmp_ctx, const char*, m_count);
3801 0 : if (sids == NULL) {
3802 0 : ret = ENOMEM;
3803 0 : goto done;
3804 : }
3805 :
3806 0 : dns = talloc_array(tmp_ctx, const char*, m_count);
3807 0 : if (dns == NULL) {
3808 0 : ret = ENOMEM;
3809 0 : goto done;
3810 : }
3811 :
3812 0 : for (i=0; i < m_count; i++) {
3813 : const char *sidstr;
3814 :
3815 0 : sidstr = ldb_msg_find_attr_as_string(members[i], SYSDB_SID_STR, NULL);
3816 :
3817 0 : if (sidstr != NULL) {
3818 0 : sids[n] = talloc_steal(sids, sidstr);
3819 :
3820 0 : dns[n] = talloc_steal(dns, ldb_dn_get_linearized(members[i]->dn));
3821 0 : if (dns[n] == NULL) {
3822 0 : ret = ENOMEM;
3823 0 : goto done;
3824 : }
3825 0 : n++;
3826 : }
3827 : }
3828 :
3829 0 : if (n == 0) {
3830 0 : ret = ENOENT;
3831 0 : goto done;
3832 : }
3833 :
3834 0 : *_n = n;
3835 0 : *_sids = talloc_steal(mem_ctx, sids);
3836 0 : *_dns = talloc_steal(mem_ctx, dns);
3837 :
3838 0 : ret = EOK;
3839 :
3840 : done:
3841 0 : if (ret == ENOENT) {
3842 0 : DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
3843 0 : } else if (ret) {
3844 0 : DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
3845 : }
3846 0 : talloc_free(tmp_ctx);
3847 0 : return ret;
3848 : }
3849 :
3850 7 : errno_t sysdb_handle_original_uuid(const char *orig_name,
3851 : struct sysdb_attrs *src_attrs,
3852 : const char *src_name,
3853 : struct sysdb_attrs *dest_attrs,
3854 : const char *dest_name)
3855 : {
3856 : int ret;
3857 : struct ldb_message_element *el;
3858 : char guid_str_buf[GUID_STR_BUF_SIZE];
3859 :
3860 7 : if (orig_name == NULL) {
3861 : /* This provider doesn't handle UUIDs */
3862 2 : return ENOENT;
3863 : }
3864 :
3865 5 : if (src_attrs == NULL || src_name == NULL
3866 4 : || dest_attrs == NULL || dest_name == NULL) {
3867 1 : return EINVAL;
3868 : }
3869 :
3870 4 : ret = sysdb_attrs_get_el_ext(src_attrs, src_name, false, &el);
3871 4 : if (ret != EOK) {
3872 1 : if (ret != ENOENT) {
3873 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el failed.\n");
3874 : }
3875 1 : return ret;
3876 : }
3877 :
3878 3 : if (el->num_values != 1) {
3879 0 : DEBUG(SSSDBG_MINOR_FAILURE,
3880 : "Found more than one UUID value, using the first.\n");
3881 : }
3882 :
3883 : /* Check if we got a binary AD objectGUID */
3884 3 : if (el->values[0].length == GUID_BIN_LENGTH
3885 1 : && strcasecmp(orig_name, "objectGUID") == 0) {
3886 1 : ret = guid_blob_to_string_buf(el->values[0].data, guid_str_buf,
3887 : GUID_STR_BUF_SIZE);
3888 1 : if (ret != EOK) {
3889 0 : DEBUG(SSSDBG_OP_FAILURE, "guid_blob_to_string_buf failed.\n");
3890 0 : return ret;
3891 : }
3892 :
3893 1 : ret = sysdb_attrs_add_string(dest_attrs, dest_name, guid_str_buf);
3894 : } else {
3895 2 : ret = sysdb_attrs_add_string(dest_attrs, dest_name,
3896 2 : (const char *)el->values[0].data);
3897 : }
3898 :
3899 3 : if (ret != EOK) {
3900 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
3901 0 : return ret;;
3902 : }
3903 :
3904 3 : return EOK;
3905 : }
3906 :
3907 : /* Mark entry as expired */
3908 2 : errno_t sysdb_mark_entry_as_expired_ldb_dn(struct sss_domain_info *dom,
3909 : struct ldb_dn *ldbdn)
3910 : {
3911 : struct ldb_message *msg;
3912 : errno_t ret;
3913 : TALLOC_CTX *tmp_ctx;
3914 :
3915 2 : tmp_ctx = talloc_new(NULL);
3916 2 : if (tmp_ctx == NULL) {
3917 0 : return ENOMEM;
3918 : }
3919 :
3920 2 : msg = ldb_msg_new(tmp_ctx);
3921 2 : if (msg == NULL) {
3922 0 : ret = ENOMEM;
3923 0 : goto done;
3924 : }
3925 :
3926 2 : msg->dn = ldbdn;
3927 :
3928 2 : ret = ldb_msg_add_empty(msg, SYSDB_CACHE_EXPIRE,
3929 : LDB_FLAG_MOD_REPLACE, NULL);
3930 2 : if (ret != LDB_SUCCESS) {
3931 0 : ret = sysdb_error_to_errno(ret);
3932 0 : goto done;
3933 : }
3934 :
3935 2 : ret = ldb_msg_add_string(msg, SYSDB_CACHE_EXPIRE, "1");
3936 2 : if (ret != LDB_SUCCESS) {
3937 0 : ret = sysdb_error_to_errno(ret);
3938 0 : goto done;
3939 : }
3940 :
3941 2 : ret = ldb_modify(dom->sysdb->ldb, msg);
3942 2 : if (ret != LDB_SUCCESS) {
3943 0 : ret = sysdb_error_to_errno(ret);
3944 0 : goto done;
3945 : }
3946 :
3947 2 : ret = EOK;
3948 :
3949 : done:
3950 2 : talloc_free(tmp_ctx);
3951 2 : return ret;
3952 : }
3953 :
3954 0 : errno_t sysdb_mark_entry_as_expired_ldb_val(struct sss_domain_info *dom,
3955 : struct ldb_val *dn_val)
3956 : {
3957 : struct ldb_dn *ldbdn;
3958 : errno_t ret;
3959 : TALLOC_CTX *tmp_ctx;
3960 :
3961 0 : tmp_ctx = talloc_new(NULL);
3962 0 : if (tmp_ctx == NULL) {
3963 0 : return ENOMEM;
3964 : }
3965 :
3966 0 : ldbdn = ldb_dn_from_ldb_val(tmp_ctx, dom->sysdb->ldb, dn_val);
3967 0 : if (ldbdn == NULL) {
3968 0 : ret = ENOMEM;
3969 0 : goto done;
3970 : }
3971 :
3972 0 : ret = sysdb_mark_entry_as_expired_ldb_dn(dom, ldbdn);
3973 :
3974 : done:
3975 0 : talloc_free(tmp_ctx);
3976 0 : return ret;
3977 : }
|