Line data Source code
1 : /*
2 : SSSD
3 :
4 : System Database
5 :
6 : Copyright (C) 2008-2011 Simo Sorce <ssorce@redhat.com>
7 : Copyright (C) 2008-2011 Stephen Gallagher <ssorce@redhat.com>
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "util/util.h"
24 : #include "util/strtonum.h"
25 : #include "util/sss_utf8.h"
26 : #include "db/sysdb_private.h"
27 : #include "confdb/confdb.h"
28 : #include <time.h>
29 :
30 : #define LDB_MODULES_PATH "LDB_MODULES_PATH"
31 :
32 1197 : errno_t sysdb_ldb_connect(TALLOC_CTX *mem_ctx, const char *filename,
33 : struct ldb_context **_ldb)
34 : {
35 : int ret;
36 : struct ldb_context *ldb;
37 : const char *mod_path;
38 :
39 1197 : if (_ldb == NULL) {
40 0 : return EINVAL;
41 : }
42 :
43 1197 : ldb = ldb_init(mem_ctx, NULL);
44 1197 : if (!ldb) {
45 0 : return EIO;
46 : }
47 :
48 1197 : ret = ldb_set_debug(ldb, ldb_debug_messages, NULL);
49 1197 : if (ret != LDB_SUCCESS) {
50 0 : return EIO;
51 : }
52 :
53 1197 : mod_path = getenv(LDB_MODULES_PATH);
54 1197 : if (mod_path != NULL) {
55 1197 : DEBUG(SSSDBG_TRACE_ALL, "Setting ldb module path to [%s].\n", mod_path);
56 1197 : ldb_set_modules_dir(ldb, mod_path);
57 : }
58 :
59 1197 : ret = ldb_connect(ldb, filename, 0, NULL);
60 1197 : if (ret != LDB_SUCCESS) {
61 0 : return EIO;
62 : }
63 :
64 1197 : *_ldb = ldb;
65 :
66 1197 : return EOK;
67 : }
68 :
69 1675 : errno_t sysdb_dn_sanitize(TALLOC_CTX *mem_ctx, const char *input,
70 : char **sanitized)
71 : {
72 : struct ldb_val val;
73 1675 : errno_t ret = EOK;
74 :
75 1675 : val.data = (uint8_t *)talloc_strdup(mem_ctx, input);
76 1675 : if (!val.data) {
77 0 : return ENOMEM;
78 : }
79 :
80 : /* We can't include the trailing NULL because it would
81 : * be escaped and result in an unterminated string
82 : */
83 1675 : val.length = strlen(input);
84 :
85 1675 : *sanitized = ldb_dn_escape_value(mem_ctx, val);
86 1675 : if (!*sanitized) {
87 0 : ret = ENOMEM;
88 : }
89 :
90 1675 : talloc_free(val.data);
91 1675 : return ret;
92 : }
93 :
94 25 : struct ldb_dn *sysdb_custom_subtree_dn(TALLOC_CTX *mem_ctx,
95 : struct sss_domain_info *dom,
96 : const char *subtree_name)
97 : {
98 : errno_t ret;
99 : char *clean_subtree;
100 25 : struct ldb_dn *dn = NULL;
101 : TALLOC_CTX *tmp_ctx;
102 :
103 25 : tmp_ctx = talloc_new(NULL);
104 25 : if (!tmp_ctx) return NULL;
105 :
106 25 : ret = sysdb_dn_sanitize(tmp_ctx, subtree_name, &clean_subtree);
107 25 : if (ret != EOK) {
108 0 : talloc_free(tmp_ctx);
109 0 : return NULL;
110 : }
111 :
112 25 : dn = ldb_dn_new_fmt(tmp_ctx, dom->sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE,
113 : clean_subtree, dom->name);
114 25 : if (dn) {
115 25 : talloc_steal(mem_ctx, dn);
116 : }
117 25 : talloc_free(tmp_ctx);
118 :
119 25 : return dn;
120 : }
121 :
122 72 : struct ldb_dn *sysdb_custom_dn(TALLOC_CTX *mem_ctx,
123 : struct sss_domain_info *dom,
124 : const char *object_name,
125 : const char *subtree_name)
126 : {
127 : errno_t ret;
128 : TALLOC_CTX *tmp_ctx;
129 : char *clean_name;
130 : char *clean_subtree;
131 72 : struct ldb_dn *dn = NULL;
132 :
133 72 : tmp_ctx = talloc_new(NULL);
134 72 : if (!tmp_ctx) {
135 0 : return NULL;
136 : }
137 :
138 72 : ret = sysdb_dn_sanitize(tmp_ctx, object_name, &clean_name);
139 72 : if (ret != EOK) {
140 0 : goto done;
141 : }
142 :
143 72 : ret = sysdb_dn_sanitize(tmp_ctx, subtree_name, &clean_subtree);
144 72 : if (ret != EOK) {
145 0 : goto done;
146 : }
147 :
148 72 : dn = ldb_dn_new_fmt(mem_ctx, dom->sysdb->ldb, SYSDB_TMPL_CUSTOM, clean_name,
149 : clean_subtree, dom->name);
150 :
151 : done:
152 72 : talloc_free(tmp_ctx);
153 72 : return dn;
154 : }
155 :
156 719 : struct ldb_dn *sysdb_user_dn(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
157 : const char *name)
158 : {
159 : errno_t ret;
160 : char *clean_name;
161 : struct ldb_dn *dn;
162 :
163 719 : ret = sysdb_dn_sanitize(NULL, name, &clean_name);
164 719 : if (ret != EOK) {
165 0 : return NULL;
166 : }
167 :
168 719 : dn = ldb_dn_new_fmt(mem_ctx, dom->sysdb->ldb, SYSDB_TMPL_USER,
169 : clean_name, dom->name);
170 719 : talloc_free(clean_name);
171 :
172 719 : return dn;
173 : }
174 :
175 468 : struct ldb_dn *sysdb_user_base_dn(TALLOC_CTX *mem_ctx,
176 : struct sss_domain_info *dom)
177 : {
178 468 : return ldb_dn_new_fmt(mem_ctx, dom->sysdb->ldb,
179 : SYSDB_TMPL_USER_BASE, dom->name);
180 : }
181 :
182 503 : struct ldb_dn *sysdb_group_dn(TALLOC_CTX *mem_ctx,
183 : struct sss_domain_info *dom, const char *name)
184 : {
185 : errno_t ret;
186 : char *clean_name;
187 : struct ldb_dn *dn;
188 :
189 503 : ret = sysdb_dn_sanitize(NULL, name, &clean_name);
190 503 : if (ret != EOK) {
191 0 : return NULL;
192 : }
193 :
194 503 : dn = ldb_dn_new_fmt(mem_ctx, dom->sysdb->ldb, SYSDB_TMPL_GROUP,
195 : clean_name, dom->name);
196 503 : talloc_free(clean_name);
197 :
198 503 : return dn;
199 : }
200 :
201 933 : struct ldb_dn *sysdb_group_base_dn(TALLOC_CTX *mem_ctx,
202 : struct sss_domain_info *dom)
203 : {
204 933 : return ldb_dn_new_fmt(mem_ctx, dom->sysdb->ldb,
205 : SYSDB_TMPL_GROUP_BASE, dom->name);
206 : }
207 :
208 :
209 53 : struct ldb_dn *sysdb_netgroup_dn(TALLOC_CTX *mem_ctx,
210 : struct sss_domain_info *dom, const char *name)
211 : {
212 : errno_t ret;
213 : char *clean_name;
214 : struct ldb_dn *dn;
215 :
216 53 : ret = sysdb_dn_sanitize(NULL, name, &clean_name);
217 53 : if (ret != EOK) {
218 0 : return NULL;
219 : }
220 :
221 53 : dn = ldb_dn_new_fmt(mem_ctx, dom->sysdb->ldb, SYSDB_TMPL_NETGROUP,
222 : clean_name, dom->name);
223 53 : talloc_free(clean_name);
224 :
225 53 : return dn;
226 : }
227 :
228 1 : struct ldb_dn *sysdb_netgroup_base_dn(TALLOC_CTX *mem_ctx,
229 : struct sss_domain_info *dom)
230 : {
231 1 : return ldb_dn_new_fmt(mem_ctx, dom->sysdb->ldb,
232 : SYSDB_TMPL_NETGROUP_BASE, dom->name);
233 : }
234 :
235 10 : errno_t sysdb_get_rdn(struct sysdb_ctx *sysdb, TALLOC_CTX *mem_ctx,
236 : const char *dn, char **_name, char **_val)
237 : {
238 : errno_t ret;
239 : struct ldb_dn *ldb_dn;
240 10 : const char *attr_name = NULL;
241 : const struct ldb_val *val;
242 : TALLOC_CTX *tmp_ctx;
243 :
244 : /* We have to create a tmp_ctx here because
245 : * ldb_dn_new_fmt() fails if mem_ctx is NULL
246 : */
247 10 : tmp_ctx = talloc_new(NULL);
248 10 : if (!tmp_ctx) {
249 0 : return ENOMEM;
250 : }
251 :
252 10 : ldb_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, "%s", dn);
253 10 : if (ldb_dn == NULL) {
254 0 : ret = ENOMEM;
255 0 : goto done;
256 : }
257 :
258 10 : if (_name) {
259 0 : attr_name = ldb_dn_get_rdn_name(ldb_dn);
260 0 : if (attr_name == NULL) {
261 0 : ret = EINVAL;
262 0 : goto done;
263 : }
264 :
265 0 : *_name = talloc_strdup(mem_ctx, attr_name);
266 0 : if (!*_name) {
267 0 : ret = ENOMEM;
268 0 : goto done;
269 : }
270 : }
271 :
272 10 : val = ldb_dn_get_rdn_val(ldb_dn);
273 10 : if (val == NULL) {
274 0 : ret = EINVAL;
275 0 : if (_name) talloc_free(*_name);
276 0 : goto done;
277 : }
278 :
279 10 : *_val = talloc_strndup(mem_ctx, (char *) val->data, val->length);
280 10 : if (!*_val) {
281 0 : ret = ENOMEM;
282 0 : if (_name) talloc_free(*_name);
283 0 : goto done;
284 : }
285 :
286 10 : ret = EOK;
287 :
288 : done:
289 10 : talloc_zfree(tmp_ctx);
290 10 : return ret;
291 : }
292 :
293 10 : errno_t sysdb_group_dn_name(struct sysdb_ctx *sysdb, TALLOC_CTX *mem_ctx,
294 : const char *dn, char **_name)
295 : {
296 10 : return sysdb_get_rdn(sysdb, mem_ctx, dn, NULL, _name);
297 : }
298 :
299 28 : struct ldb_dn *sysdb_domain_dn(TALLOC_CTX *mem_ctx,
300 : struct sss_domain_info *dom)
301 : {
302 28 : return ldb_dn_new_fmt(mem_ctx, dom->sysdb->ldb, SYSDB_DOM_BASE, dom->name);
303 : }
304 :
305 44 : struct ldb_dn *sysdb_base_dn(struct sysdb_ctx *sysdb, TALLOC_CTX *mem_ctx)
306 : {
307 44 : return ldb_dn_new(mem_ctx, sysdb->ldb, SYSDB_BASE);
308 : }
309 :
310 0 : struct ldb_context *sysdb_ctx_get_ldb(struct sysdb_ctx *sysdb)
311 : {
312 0 : return sysdb->ldb;
313 : }
314 :
315 726 : struct sysdb_attrs *sysdb_new_attrs(TALLOC_CTX *mem_ctx)
316 : {
317 726 : return talloc_zero(mem_ctx, struct sysdb_attrs);
318 : }
319 :
320 2689 : int sysdb_attrs_get_el_ext(struct sysdb_attrs *attrs, const char *name,
321 : bool alloc, struct ldb_message_element **el)
322 : {
323 2689 : struct ldb_message_element *e = NULL;
324 : int i;
325 :
326 6601 : for (i = 0; i < attrs->num; i++) {
327 3912 : if (strcasecmp(name, attrs->a[i].name) == 0)
328 203 : e = &(attrs->a[i]);
329 : }
330 :
331 2689 : if (!e && alloc) {
332 2293 : e = talloc_realloc(attrs, attrs->a,
333 : struct ldb_message_element, attrs->num+1);
334 2293 : if (!e) return ENOMEM;
335 2293 : attrs->a = e;
336 :
337 2293 : e[attrs->num].name = talloc_strdup(e, name);
338 2293 : if (!e[attrs->num].name) return ENOMEM;
339 :
340 2293 : e[attrs->num].num_values = 0;
341 2293 : e[attrs->num].values = NULL;
342 2293 : e[attrs->num].flags = 0;
343 :
344 2293 : e = &(attrs->a[attrs->num]);
345 2293 : attrs->num++;
346 : }
347 :
348 2689 : if (!e) {
349 193 : return ENOENT;
350 : }
351 :
352 2496 : *el = e;
353 :
354 2496 : return EOK;
355 : }
356 :
357 2357 : int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
358 : struct ldb_message_element **el)
359 : {
360 2357 : return sysdb_attrs_get_el_ext(attrs, name, true, el);
361 : }
362 :
363 134 : int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name,
364 : const char **string)
365 : {
366 : struct ldb_message_element *el;
367 : int ret;
368 :
369 134 : ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
370 134 : if (ret) {
371 31 : return ret;
372 : }
373 :
374 103 : if (el->num_values != 1) {
375 0 : return ERANGE;
376 : }
377 :
378 103 : *string = (const char *)el->values[0].data;
379 103 : return EOK;
380 : }
381 :
382 0 : int sysdb_attrs_get_int32_t(struct sysdb_attrs *attrs, const char *name,
383 : int32_t *value)
384 : {
385 : struct ldb_message_element *el;
386 : int ret;
387 : char *endptr;
388 : int32_t val;
389 :
390 0 : ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
391 0 : if (ret) {
392 0 : return ret;
393 : }
394 :
395 0 : if (el->num_values != 1) {
396 0 : return ERANGE;
397 : }
398 :
399 0 : errno = 0;
400 0 : val = strtoint32((const char *) el->values[0].data, &endptr, 10);
401 0 : if (errno != 0) return errno;
402 0 : if (*endptr) return EINVAL;
403 :
404 0 : *value = val;
405 0 : return EOK;
406 : }
407 :
408 20 : int sysdb_attrs_get_uint32_t(struct sysdb_attrs *attrs, const char *name,
409 : uint32_t *value)
410 : {
411 : struct ldb_message_element *el;
412 : int ret;
413 : char *endptr;
414 : uint32_t val;
415 :
416 20 : ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
417 20 : if (ret) {
418 2 : return ret;
419 : }
420 :
421 18 : if (el->num_values != 1) {
422 0 : return ERANGE;
423 : }
424 :
425 18 : errno = 0;
426 18 : val = strtouint32((const char *) el->values[0].data, &endptr, 10);
427 18 : if (errno != 0) return errno;
428 18 : if (*endptr) return EINVAL;
429 :
430 18 : *value = val;
431 18 : return EOK;
432 : }
433 :
434 0 : int sysdb_attrs_get_uint16_t(struct sysdb_attrs *attrs, const char *name,
435 : uint16_t *value)
436 : {
437 : struct ldb_message_element *el;
438 : int ret;
439 : char *endptr;
440 : uint16_t val;
441 :
442 0 : ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
443 0 : if (ret) {
444 0 : return ret;
445 : }
446 :
447 0 : if (el->num_values != 1) {
448 0 : return ERANGE;
449 : }
450 :
451 0 : errno = 0;
452 0 : val = strtouint16((const char *) el->values[0].data, &endptr, 10);
453 0 : if (errno != 0) return errno;
454 0 : if (*endptr) return EINVAL;
455 :
456 0 : *value = val;
457 0 : return EOK;
458 : }
459 :
460 155 : errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name,
461 : bool *value)
462 : {
463 : struct ldb_message_element *el;
464 : int ret;
465 :
466 155 : ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
467 155 : if (ret) {
468 155 : return ret;
469 : }
470 :
471 0 : if (el->num_values != 1) {
472 0 : return ERANGE;
473 : }
474 :
475 0 : if (strcmp((const char *)el->values[0].data, "TRUE") == 0)
476 0 : *value = true;
477 : else
478 0 : *value = false;
479 0 : return EOK;
480 : }
481 :
482 2 : const char **sss_ldb_el_to_string_list(TALLOC_CTX *mem_ctx,
483 : struct ldb_message_element *el)
484 : {
485 : unsigned int u;
486 : const char **a;
487 :
488 2 : a = talloc_zero_array(mem_ctx, const char *, el->num_values + 1);
489 2 : if (a == NULL) {
490 0 : return NULL;
491 : }
492 :
493 6 : for (u = 0; u < el->num_values; u++) {
494 8 : a[u] = talloc_strndup(a, (const char *)el->values[u].data,
495 4 : el->values[u].length);
496 4 : if (a[u] == NULL) {
497 0 : talloc_free(a);
498 0 : return NULL;
499 : }
500 : }
501 :
502 2 : return a;
503 : }
504 :
505 1 : int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,
506 : TALLOC_CTX *mem_ctx, const char ***string)
507 : {
508 : struct ldb_message_element *el;
509 : int ret;
510 : const char **a;
511 :
512 1 : ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
513 1 : if (ret) {
514 0 : return ret;
515 : }
516 :
517 1 : a = sss_ldb_el_to_string_list(mem_ctx, el);
518 1 : if (a == NULL) {
519 0 : return ENOMEM;
520 : }
521 :
522 1 : *string = a;
523 1 : return EOK;
524 : }
525 :
526 :
527 1988 : static int sysdb_attrs_add_val_int(struct sysdb_attrs *attrs,
528 : const char *name, bool check_values,
529 : const struct ldb_val *val)
530 : {
531 1988 : struct ldb_message_element *el = NULL;
532 : struct ldb_val *vals;
533 : int ret;
534 : size_t c;
535 :
536 1988 : ret = sysdb_attrs_get_el(attrs, name, &el);
537 1988 : if (ret != EOK) {
538 0 : return ret;
539 : }
540 :
541 1988 : if (check_values) {
542 2 : for (c = 0; c < el->num_values; c++) {
543 2 : if (val->length == el->values[c].length
544 2 : && memcmp(val->data, el->values[c].data,
545 : val->length) == 0) {
546 2 : return EOK;
547 : }
548 : }
549 : }
550 :
551 1986 : vals = talloc_realloc(attrs->a, el->values,
552 : struct ldb_val, el->num_values+1);
553 1986 : if (!vals) return ENOMEM;
554 :
555 1986 : vals[el->num_values] = ldb_val_dup(vals, val);
556 1986 : if (vals[el->num_values].data == NULL &&
557 0 : vals[el->num_values].length != 0) {
558 0 : return ENOMEM;
559 : }
560 :
561 1986 : el->values = vals;
562 1986 : el->num_values++;
563 :
564 1986 : return EOK;
565 : }
566 1986 : int sysdb_attrs_add_val(struct sysdb_attrs *attrs,
567 : const char *name, const struct ldb_val *val)
568 : {
569 1986 : return sysdb_attrs_add_val_int(attrs, name, false, val);
570 : }
571 :
572 : /* Check if the same value already exists. */
573 2 : int sysdb_attrs_add_val_safe(struct sysdb_attrs *attrs,
574 : const char *name, const struct ldb_val *val)
575 : {
576 2 : return sysdb_attrs_add_val_int(attrs, name, true, val);
577 : }
578 :
579 1 : int sysdb_attrs_add_string_safe(struct sysdb_attrs *attrs,
580 : const char *name, const char *str)
581 : {
582 : struct ldb_val v;
583 :
584 1 : v.data = (uint8_t *)discard_const(str);
585 1 : v.length = strlen(str);
586 :
587 1 : return sysdb_attrs_add_val_safe(attrs, name, &v);
588 : }
589 :
590 953 : int sysdb_attrs_add_string(struct sysdb_attrs *attrs,
591 : const char *name, const char *str)
592 : {
593 : struct ldb_val v;
594 :
595 953 : v.data = (uint8_t *)discard_const(str);
596 953 : v.length = strlen(str);
597 :
598 953 : return sysdb_attrs_add_val(attrs, name, &v);
599 : }
600 :
601 2 : int sysdb_attrs_add_lower_case_string(struct sysdb_attrs *attrs,
602 : const char *name, const char *str)
603 : {
604 : char *lc_str;
605 : int ret;
606 :
607 2 : if (attrs == NULL || str == NULL) {
608 1 : return EINVAL;
609 : }
610 :
611 1 : lc_str = sss_tc_utf8_str_tolower(attrs, str);
612 1 : if (lc_str == NULL) {
613 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n");
614 0 : return ENOMEM;
615 : }
616 :
617 1 : ret = sysdb_attrs_add_string(attrs, name, lc_str);
618 1 : talloc_free(lc_str);
619 :
620 1 : return ret;
621 : }
622 :
623 5 : int sysdb_attrs_add_mem(struct sysdb_attrs *attrs, const char *name,
624 : const void *mem, size_t size)
625 : {
626 : struct ldb_val v;
627 :
628 5 : v.data = discard_const(mem);
629 5 : v.length = size;
630 5 : return sysdb_attrs_add_val(attrs, name, &v);
631 : }
632 :
633 170 : int sysdb_attrs_add_bool(struct sysdb_attrs *attrs,
634 : const char *name, bool value)
635 : {
636 170 : if(value) {
637 170 : return sysdb_attrs_add_string(attrs, name, "TRUE");
638 : }
639 :
640 0 : return sysdb_attrs_add_string(attrs, name, "FALSE");
641 : }
642 :
643 211 : int sysdb_attrs_steal_string(struct sysdb_attrs *attrs,
644 : const char *name, char *str)
645 : {
646 211 : struct ldb_message_element *el = NULL;
647 : struct ldb_val *vals;
648 : int ret;
649 :
650 211 : ret = sysdb_attrs_get_el(attrs, name, &el);
651 211 : if (ret != EOK) {
652 0 : return ret;
653 : }
654 :
655 211 : vals = talloc_realloc(attrs->a, el->values,
656 : struct ldb_val, el->num_values+1);
657 211 : if (!vals) return ENOMEM;
658 211 : el->values = vals;
659 :
660 : /* now steal and assign the string */
661 211 : talloc_steal(el->values, str);
662 :
663 211 : el->values[el->num_values].data = (uint8_t *)str;
664 211 : el->values[el->num_values].length = strlen(str);
665 211 : el->num_values++;
666 :
667 211 : return EOK;
668 : }
669 :
670 34 : int sysdb_attrs_add_long(struct sysdb_attrs *attrs,
671 : const char *name, long value)
672 : {
673 : struct ldb_val v;
674 : char *str;
675 : int ret;
676 :
677 34 : str = talloc_asprintf(attrs, "%ld", value);
678 34 : if (!str) return ENOMEM;
679 :
680 34 : v.data = (uint8_t *)str;
681 34 : v.length = strlen(str);
682 :
683 34 : ret = sysdb_attrs_add_val(attrs, name, &v);
684 34 : talloc_free(str);
685 :
686 34 : return ret;
687 : }
688 :
689 158 : int sysdb_attrs_add_uint32(struct sysdb_attrs *attrs,
690 : const char *name, uint32_t value)
691 : {
692 158 : unsigned long val = value;
693 : struct ldb_val v;
694 : char *str;
695 : int ret;
696 :
697 158 : str = talloc_asprintf(attrs, "%lu", val);
698 158 : if (!str) return ENOMEM;
699 :
700 158 : v.data = (uint8_t *)str;
701 158 : v.length = strlen(str);
702 :
703 158 : ret = sysdb_attrs_add_val(attrs, name, &v);
704 158 : talloc_free(str);
705 :
706 158 : return ret;
707 : }
708 :
709 822 : int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs,
710 : const char *name, time_t value)
711 : {
712 822 : long long val = value;
713 : struct ldb_val v;
714 : char *str;
715 : int ret;
716 :
717 822 : str = talloc_asprintf(attrs, "%lld", val);
718 822 : if (!str) return ENOMEM;
719 :
720 822 : v.data = (uint8_t *)str;
721 822 : v.length = strlen(str);
722 :
723 822 : ret = sysdb_attrs_add_val(attrs, name, &v);
724 822 : talloc_free(str);
725 :
726 822 : return ret;
727 : }
728 :
729 2 : int sysdb_attrs_add_lc_name_alias(struct sysdb_attrs *attrs,
730 : const char *value)
731 : {
732 2 : return sysdb_attrs_add_lower_case_string(attrs, SYSDB_NAME_ALIAS, value);
733 : }
734 :
735 0 : int sysdb_attrs_copy_values(struct sysdb_attrs *src,
736 : struct sysdb_attrs *dst,
737 : const char *name)
738 : {
739 0 : int ret = EOK;
740 : int i;
741 : struct ldb_message_element *src_el;
742 :
743 0 : ret = sysdb_attrs_get_el(src, name, &src_el);
744 0 : if (ret != EOK) {
745 0 : goto done;
746 : }
747 :
748 0 : for (i = 0; i < src_el->num_values; i++) {
749 0 : ret = sysdb_attrs_add_val(dst, name, &src_el->values[i]);
750 0 : if (ret != EOK) {
751 0 : goto done;
752 : }
753 : }
754 :
755 : done:
756 0 : return ret;
757 : }
758 :
759 0 : int sysdb_attrs_users_from_str_list(struct sysdb_attrs *attrs,
760 : const char *attr_name,
761 : const char *domain,
762 : const char *const *list)
763 : {
764 0 : struct ldb_message_element *el = NULL;
765 : struct ldb_val *vals;
766 : int i, j, num;
767 : char *member;
768 : int ret;
769 :
770 0 : ret = sysdb_attrs_get_el(attrs, attr_name, &el);
771 0 : if (ret) {
772 0 : return ret;
773 : }
774 :
775 0 : for (num = 0; list[num]; num++) /* count */ ;
776 :
777 0 : vals = talloc_realloc(attrs->a, el->values,
778 : struct ldb_val, el->num_values + num);
779 0 : if (!vals) {
780 0 : return ENOMEM;
781 : }
782 0 : el->values = vals;
783 :
784 0 : DEBUG(SSSDBG_TRACE_ALL, "Adding %d members to existing %d ones\n",
785 : num, el->num_values);
786 :
787 0 : for (i = 0, j = el->num_values; i < num; i++) {
788 :
789 0 : member = sysdb_user_strdn(el->values, domain, list[i]);
790 0 : if (!member) {
791 0 : DEBUG(SSSDBG_CONF_SETTINGS,
792 : "Failed to get user dn for [%s]\n", list[i]);
793 0 : continue;
794 : }
795 0 : el->values[j].data = (uint8_t *)member;
796 0 : el->values[j].length = strlen(member);
797 0 : j++;
798 :
799 0 : DEBUG(SSSDBG_TRACE_LIBS, " member #%d: [%s]\n", i, member);
800 : }
801 0 : el->num_values = j;
802 :
803 0 : return EOK;
804 : }
805 :
806 70 : static char *build_dom_dn_str_escape(TALLOC_CTX *mem_ctx, const char *template,
807 : const char *domain, const char *name)
808 : {
809 : char *ret;
810 : int l;
811 :
812 70 : l = strcspn(name, ",=\n+<>#;\\\"");
813 70 : if (name[l] != '\0') {
814 : struct ldb_val v;
815 : char *tmp;
816 :
817 0 : v.data = discard_const_p(uint8_t, name);
818 0 : v.length = strlen(name);
819 :
820 0 : tmp = ldb_dn_escape_value(mem_ctx, v);
821 0 : if (!tmp) {
822 0 : return NULL;
823 : }
824 :
825 0 : ret = talloc_asprintf(mem_ctx, template, tmp, domain);
826 0 : talloc_zfree(tmp);
827 0 : if (!ret) {
828 0 : return NULL;
829 : }
830 :
831 0 : return ret;
832 : }
833 :
834 70 : ret = talloc_asprintf(mem_ctx, template, name, domain);
835 70 : if (!ret) {
836 0 : return NULL;
837 : }
838 :
839 70 : return ret;
840 : }
841 :
842 0 : char *sysdb_user_strdn(TALLOC_CTX *mem_ctx,
843 : const char *domain, const char *name)
844 : {
845 0 : return build_dom_dn_str_escape(mem_ctx, SYSDB_TMPL_USER, domain, name);
846 : }
847 :
848 70 : char *sysdb_group_strdn(TALLOC_CTX *mem_ctx,
849 : const char *domain, const char *name)
850 : {
851 70 : return build_dom_dn_str_escape(mem_ctx, SYSDB_TMPL_GROUP, domain, name);
852 : }
853 :
854 : /* TODO: make a more complete and precise mapping */
855 1866 : int sysdb_error_to_errno(int ldberr)
856 : {
857 1866 : switch (ldberr) {
858 : case LDB_SUCCESS:
859 1865 : return EOK;
860 : case LDB_ERR_OPERATIONS_ERROR:
861 0 : return EIO;
862 : case LDB_ERR_NO_SUCH_OBJECT:
863 1 : return ENOENT;
864 : case LDB_ERR_BUSY:
865 0 : return EBUSY;
866 : case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
867 : case LDB_ERR_ENTRY_ALREADY_EXISTS:
868 0 : return EEXIST;
869 : case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
870 0 : return EINVAL;
871 : default:
872 0 : DEBUG(SSSDBG_CRIT_FAILURE,
873 : "LDB returned unexpected error: [%s]\n",
874 : ldb_strerror(ldberr));
875 0 : return EFAULT;
876 : }
877 : }
878 :
879 : /* =Transactions========================================================== */
880 :
881 145 : int sysdb_transaction_start(struct sysdb_ctx *sysdb)
882 : {
883 : int ret;
884 :
885 145 : ret = ldb_transaction_start(sysdb->ldb);
886 145 : if (ret != LDB_SUCCESS) {
887 0 : DEBUG(SSSDBG_CRIT_FAILURE,
888 : "Failed to start ldb transaction! (%d)\n", ret);
889 : }
890 145 : return sysdb_error_to_errno(ret);
891 : }
892 :
893 145 : int sysdb_transaction_commit(struct sysdb_ctx *sysdb)
894 : {
895 : int ret;
896 :
897 145 : ret = ldb_transaction_commit(sysdb->ldb);
898 145 : if (ret != LDB_SUCCESS) {
899 0 : DEBUG(SSSDBG_CRIT_FAILURE,
900 : "Failed to commit ldb transaction! (%d)\n", ret);
901 : }
902 145 : return sysdb_error_to_errno(ret);
903 : }
904 :
905 0 : int sysdb_transaction_cancel(struct sysdb_ctx *sysdb)
906 : {
907 : int ret;
908 :
909 0 : ret = ldb_transaction_cancel(sysdb->ldb);
910 0 : if (ret != LDB_SUCCESS) {
911 0 : DEBUG(SSSDBG_CRIT_FAILURE,
912 : "Failed to cancel ldb transaction! (%d)\n", ret);
913 : }
914 0 : return sysdb_error_to_errno(ret);
915 : }
916 :
917 : /* =Initialization======================================================== */
918 :
919 1081 : int sysdb_get_db_file(TALLOC_CTX *mem_ctx,
920 : const char *provider, const char *name,
921 : const char *base_path, char **_ldb_file)
922 : {
923 : char *ldb_file;
924 :
925 : /* special case for the local domain */
926 1081 : if (strcasecmp(provider, "local") == 0) {
927 871 : ldb_file = talloc_asprintf(mem_ctx, "%s/"LOCAL_SYSDB_FILE,
928 : base_path);
929 : } else {
930 210 : ldb_file = talloc_asprintf(mem_ctx, "%s/"CACHE_SYSDB_FILE,
931 : base_path, name);
932 : }
933 1081 : if (!ldb_file) {
934 0 : return ENOMEM;
935 : }
936 :
937 1081 : *_ldb_file = ldb_file;
938 1081 : return EOK;
939 : }
940 :
941 131 : errno_t sysdb_domain_create(struct sysdb_ctx *sysdb, const char *domain_name)
942 : {
943 : struct ldb_message *msg;
944 : TALLOC_CTX *tmp_ctx;
945 : int ret;
946 :
947 131 : tmp_ctx = talloc_new(NULL);
948 131 : if (tmp_ctx == NULL) {
949 0 : ret = ENOMEM;
950 0 : goto done;
951 : }
952 :
953 : /* == create base domain object == */
954 :
955 131 : msg = ldb_msg_new(tmp_ctx);
956 131 : if (!msg) {
957 0 : ret = ENOMEM;
958 0 : goto done;
959 : }
960 131 : msg->dn = ldb_dn_new_fmt(msg, sysdb->ldb, SYSDB_DOM_BASE, domain_name);
961 131 : if (!msg->dn) {
962 0 : ret = ENOMEM;
963 0 : goto done;
964 : }
965 131 : ret = ldb_msg_add_string(msg, "cn", domain_name);
966 131 : if (ret != LDB_SUCCESS) {
967 0 : ret = EIO;
968 0 : goto done;
969 : }
970 : /* do a synchronous add */
971 131 : ret = ldb_add(sysdb->ldb, msg);
972 131 : if (ret != LDB_SUCCESS) {
973 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to initialize DB (%d, [%s]) "
974 : "for domain %s!\n",
975 : ret, ldb_errstring(sysdb->ldb),
976 : domain_name);
977 0 : ret = EIO;
978 0 : goto done;
979 : }
980 131 : talloc_zfree(msg);
981 :
982 : /* == create Users tree == */
983 :
984 131 : msg = ldb_msg_new(tmp_ctx);
985 131 : if (!msg) {
986 0 : ret = ENOMEM;
987 0 : goto done;
988 : }
989 131 : msg->dn = ldb_dn_new_fmt(msg, sysdb->ldb,
990 : SYSDB_TMPL_USER_BASE, domain_name);
991 131 : if (!msg->dn) {
992 0 : ret = ENOMEM;
993 0 : goto done;
994 : }
995 131 : ret = ldb_msg_add_string(msg, "cn", "Users");
996 131 : if (ret != LDB_SUCCESS) {
997 0 : ret = EIO;
998 0 : goto done;
999 : }
1000 : /* do a synchronous add */
1001 131 : ret = ldb_add(sysdb->ldb, msg);
1002 131 : if (ret != LDB_SUCCESS) {
1003 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to initialize DB (%d, [%s]) "
1004 : "for domain %s!\n",
1005 : ret, ldb_errstring(sysdb->ldb),
1006 : domain_name);
1007 0 : ret = EIO;
1008 0 : goto done;
1009 : }
1010 131 : talloc_zfree(msg);
1011 :
1012 : /* == create Groups tree == */
1013 :
1014 131 : msg = ldb_msg_new(tmp_ctx);
1015 131 : if (!msg) {
1016 0 : ret = ENOMEM;
1017 0 : goto done;
1018 : }
1019 131 : msg->dn = ldb_dn_new_fmt(msg, sysdb->ldb,
1020 : SYSDB_TMPL_GROUP_BASE, domain_name);
1021 131 : if (!msg->dn) {
1022 0 : ret = ENOMEM;
1023 0 : goto done;
1024 : }
1025 131 : ret = ldb_msg_add_string(msg, "cn", "Groups");
1026 131 : if (ret != LDB_SUCCESS) {
1027 0 : ret = EIO;
1028 0 : goto done;
1029 : }
1030 : /* do a synchronous add */
1031 131 : ret = ldb_add(sysdb->ldb, msg);
1032 131 : if (ret != LDB_SUCCESS) {
1033 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to initialize DB (%d, [%s]) for "
1034 : "domain %s!\n",
1035 : ret, ldb_errstring(sysdb->ldb),
1036 : domain_name);
1037 0 : ret = EIO;
1038 0 : goto done;
1039 : }
1040 131 : talloc_zfree(msg);
1041 :
1042 131 : ret = EOK;
1043 :
1044 : done:
1045 131 : talloc_zfree(tmp_ctx);
1046 131 : return ret;
1047 : }
1048 :
1049 : /* Compare versions of sysdb, returns ERRNO accordingly */
1050 : static errno_t
1051 0 : sysdb_version_check(const char *expected,
1052 : const char *received)
1053 : {
1054 : int ret;
1055 : unsigned int exp_major, exp_minor, recv_major, recv_minor;
1056 :
1057 0 : ret = sscanf(expected, "%u.%u", &exp_major, &exp_minor);
1058 0 : if (ret != 2) {
1059 0 : return EINVAL;
1060 : }
1061 0 : ret = sscanf(received, "%u.%u", &recv_major, &recv_minor);
1062 0 : if (ret != 2) {
1063 0 : return EINVAL;
1064 : }
1065 :
1066 0 : if (recv_major > exp_major) {
1067 0 : return EUCLEAN;
1068 0 : } else if (recv_major < exp_major) {
1069 0 : return EMEDIUMTYPE;
1070 : }
1071 :
1072 0 : if (recv_minor > exp_minor) {
1073 0 : return EUCLEAN;
1074 0 : } else if (recv_minor < exp_minor) {
1075 0 : return EMEDIUMTYPE;
1076 : }
1077 :
1078 0 : return EOK;
1079 : }
1080 :
1081 1081 : int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx,
1082 : struct sss_domain_info *domain,
1083 : const char *db_path,
1084 : bool allow_upgrade,
1085 : struct sysdb_ctx **_ctx)
1086 : {
1087 1081 : TALLOC_CTX *tmp_ctx = NULL;
1088 : struct sysdb_ctx *sysdb;
1089 : const char *base_ldif;
1090 : struct ldb_ldif *ldif;
1091 : struct ldb_message_element *el;
1092 : struct ldb_result *res;
1093 : struct ldb_dn *verdn;
1094 1081 : const char *version = NULL;
1095 : int ret;
1096 :
1097 1081 : sysdb = talloc_zero(mem_ctx, struct sysdb_ctx);
1098 1081 : if (!sysdb) {
1099 0 : return ENOMEM;
1100 : }
1101 :
1102 2162 : ret = sysdb_get_db_file(sysdb, domain->provider,
1103 1081 : domain->name, db_path,
1104 : &sysdb->ldb_file);
1105 1081 : if (ret != EOK) {
1106 0 : goto done;
1107 : }
1108 1081 : DEBUG(SSSDBG_FUNC_DATA,
1109 : "DB File for %s: %s\n", domain->name, sysdb->ldb_file);
1110 :
1111 1081 : ret = sysdb_ldb_connect(sysdb, sysdb->ldb_file, &sysdb->ldb);
1112 1081 : if (ret != EOK) {
1113 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_ldb_connect failed.\n");
1114 0 : goto done;
1115 : }
1116 :
1117 1081 : tmp_ctx = talloc_new(NULL);
1118 1081 : if (!tmp_ctx) {
1119 0 : ret = ENOMEM;
1120 0 : goto done;
1121 : }
1122 :
1123 1081 : verdn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_BASE);
1124 1081 : if (!verdn) {
1125 0 : ret = EIO;
1126 0 : goto done;
1127 : }
1128 :
1129 1081 : ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
1130 : verdn, LDB_SCOPE_BASE,
1131 : NULL, NULL);
1132 1081 : if (ret != LDB_SUCCESS) {
1133 0 : ret = EIO;
1134 0 : goto done;
1135 : }
1136 1081 : if (res->count > 1) {
1137 0 : ret = EIO;
1138 0 : goto done;
1139 : }
1140 :
1141 1081 : if (res->count == 1) {
1142 965 : el = ldb_msg_find_element(res->msgs[0], "version");
1143 965 : if (!el) {
1144 0 : ret = EIO;
1145 0 : goto done;
1146 : }
1147 :
1148 965 : if (el->num_values != 1) {
1149 0 : ret = EINVAL;
1150 0 : goto done;
1151 : }
1152 1930 : version = talloc_strndup(tmp_ctx,
1153 965 : (char *)(el->values[0].data),
1154 965 : el->values[0].length);
1155 965 : if (!version) {
1156 0 : ret = ENOMEM;
1157 0 : goto done;
1158 : }
1159 :
1160 965 : if (strcmp(version, SYSDB_VERSION) == 0) {
1161 : /* all fine, return */
1162 965 : ret = EOK;
1163 965 : goto done;
1164 : }
1165 :
1166 0 : if (!allow_upgrade) {
1167 0 : DEBUG(SSSDBG_FATAL_FAILURE,
1168 : "Wrong DB version (got %s expected %s)\n",
1169 : version, SYSDB_VERSION);
1170 0 : ret = sysdb_version_check(SYSDB_VERSION, version);
1171 0 : goto done;
1172 : }
1173 :
1174 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Upgrading DB [%s] from version: %s\n",
1175 : domain->name, version);
1176 :
1177 0 : if (strcmp(version, SYSDB_VERSION_0_3) == 0) {
1178 0 : ret = sysdb_upgrade_03(sysdb, &version);
1179 0 : if (ret != EOK) {
1180 0 : goto done;
1181 : }
1182 : }
1183 :
1184 0 : if (strcmp(version, SYSDB_VERSION_0_4) == 0) {
1185 0 : ret = sysdb_upgrade_04(sysdb, &version);
1186 0 : if (ret != EOK) {
1187 0 : goto done;
1188 : }
1189 : }
1190 :
1191 0 : if (strcmp(version, SYSDB_VERSION_0_5) == 0) {
1192 0 : ret = sysdb_upgrade_05(sysdb, &version);
1193 0 : if (ret != EOK) {
1194 0 : goto done;
1195 : }
1196 : }
1197 :
1198 0 : if (strcmp(version, SYSDB_VERSION_0_6) == 0) {
1199 0 : ret = sysdb_upgrade_06(sysdb, &version);
1200 0 : if (ret != EOK) {
1201 0 : goto done;
1202 : }
1203 : }
1204 :
1205 0 : if (strcmp(version, SYSDB_VERSION_0_7) == 0) {
1206 0 : ret = sysdb_upgrade_07(sysdb, &version);
1207 0 : if (ret != EOK) {
1208 0 : goto done;
1209 : }
1210 : }
1211 :
1212 0 : if (strcmp(version, SYSDB_VERSION_0_8) == 0) {
1213 0 : ret = sysdb_upgrade_08(sysdb, &version);
1214 0 : if (ret != EOK) {
1215 0 : goto done;
1216 : }
1217 : }
1218 :
1219 0 : if (strcmp(version, SYSDB_VERSION_0_9) == 0) {
1220 0 : ret = sysdb_upgrade_09(sysdb, &version);
1221 0 : if (ret != EOK) {
1222 0 : goto done;
1223 : }
1224 : }
1225 :
1226 0 : if (strcmp(version, SYSDB_VERSION_0_10) == 0) {
1227 0 : ret = sysdb_upgrade_10(sysdb, domain, &version);
1228 0 : if (ret != EOK) {
1229 0 : goto done;
1230 : }
1231 : }
1232 :
1233 0 : if (strcmp(version, SYSDB_VERSION_0_11) == 0) {
1234 0 : ret = sysdb_upgrade_11(sysdb, domain, &version);
1235 0 : if (ret != EOK) {
1236 0 : goto done;
1237 : }
1238 : }
1239 :
1240 0 : if (strcmp(version, SYSDB_VERSION_0_12) == 0) {
1241 0 : ret = sysdb_upgrade_12(sysdb, &version);
1242 0 : if (ret != EOK) {
1243 0 : goto done;
1244 : }
1245 : }
1246 :
1247 0 : if (strcmp(version, SYSDB_VERSION_0_13) == 0) {
1248 0 : ret = sysdb_upgrade_13(sysdb, &version);
1249 0 : if (ret != EOK) {
1250 0 : goto done;
1251 : }
1252 : }
1253 :
1254 0 : if (strcmp(version, SYSDB_VERSION_0_14) == 0) {
1255 0 : ret = sysdb_upgrade_14(sysdb, &version);
1256 0 : if (ret != EOK) {
1257 0 : goto done;
1258 : }
1259 : }
1260 :
1261 0 : if (strcmp(version, SYSDB_VERSION_0_15) == 0) {
1262 0 : ret = sysdb_upgrade_15(sysdb, &version);
1263 0 : if (ret != EOK) {
1264 0 : goto done;
1265 : }
1266 : }
1267 :
1268 0 : if (strcmp(version, SYSDB_VERSION_0_16) == 0) {
1269 0 : ret = sysdb_upgrade_16(sysdb, &version);
1270 0 : if (ret != EOK) {
1271 0 : goto done;
1272 : }
1273 : }
1274 :
1275 : /* The version should now match SYSDB_VERSION.
1276 : * If not, it means we didn't match any of the
1277 : * known older versions. The DB might be
1278 : * corrupt or generated by a newer version of
1279 : * SSSD.
1280 : */
1281 0 : if (strcmp(version, SYSDB_VERSION) == 0) {
1282 : /* The cache has been upgraded.
1283 : * We need to reopen the LDB to ensure that
1284 : * any changes made above take effect.
1285 : */
1286 0 : talloc_zfree(sysdb->ldb);
1287 0 : ret = sysdb_ldb_connect(sysdb, sysdb->ldb_file, &sysdb->ldb);
1288 0 : if (ret != EOK) {
1289 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_ldb_connect failed.\n");
1290 : }
1291 0 : goto done;
1292 : }
1293 :
1294 0 : DEBUG(SSSDBG_FATAL_FAILURE,
1295 : "Unknown DB version [%s], expected [%s] for domain %s!\n",
1296 : version, SYSDB_VERSION, domain->name);
1297 0 : ret = sysdb_version_check(SYSDB_VERSION, version);
1298 0 : goto done;
1299 : }
1300 :
1301 : /* SYSDB_BASE does not exists, means db is empty, populate */
1302 :
1303 116 : base_ldif = SYSDB_BASE_LDIF;
1304 812 : while ((ldif = ldb_ldif_read_string(sysdb->ldb, &base_ldif))) {
1305 580 : ret = ldb_add(sysdb->ldb, ldif->msg);
1306 580 : if (ret != LDB_SUCCESS) {
1307 0 : DEBUG(SSSDBG_FATAL_FAILURE,
1308 : "Failed to initialize DB (%d, [%s]) for domain %s!\n",
1309 : ret, ldb_errstring(sysdb->ldb), domain->name);
1310 0 : ret = EIO;
1311 0 : goto done;
1312 : }
1313 580 : ldb_ldif_read_free(sysdb->ldb, ldif);
1314 : }
1315 :
1316 116 : ret = sysdb_domain_create(sysdb, domain->name);
1317 116 : if (ret != EOK) {
1318 0 : goto done;
1319 : }
1320 :
1321 : /* The cache has been newly created.
1322 : * We need to reopen the LDB to ensure that
1323 : * all of the special values take effect
1324 : * (such as enabling the memberOf plugin and
1325 : * the various indexes).
1326 : */
1327 116 : talloc_zfree(sysdb->ldb);
1328 116 : ret = sysdb_ldb_connect(sysdb, sysdb->ldb_file, &sysdb->ldb);
1329 116 : if (ret != EOK) {
1330 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_ldb_connect failed.\n");
1331 : }
1332 :
1333 : done:
1334 1081 : talloc_free(tmp_ctx);
1335 1081 : if (ret == EOK) {
1336 1081 : *_ctx = sysdb;
1337 : } else {
1338 0 : talloc_free(sysdb);
1339 : }
1340 1081 : return ret;
1341 : }
1342 :
1343 0 : int sysdb_init(TALLOC_CTX *mem_ctx,
1344 : struct sss_domain_info *domains,
1345 : bool allow_upgrade)
1346 : {
1347 0 : return sysdb_init_ext(mem_ctx, domains, allow_upgrade, false, 0, 0);
1348 : }
1349 :
1350 0 : int sysdb_init_ext(TALLOC_CTX *mem_ctx,
1351 : struct sss_domain_info *domains,
1352 : bool allow_upgrade,
1353 : bool chown_dbfile,
1354 : uid_t uid,
1355 : gid_t gid)
1356 : {
1357 : struct sss_domain_info *dom;
1358 : struct sysdb_ctx *sysdb;
1359 : int ret;
1360 :
1361 0 : if (allow_upgrade) {
1362 : /* check if we have an old sssd.ldb to upgrade */
1363 0 : ret = sysdb_check_upgrade_02(domains, DB_PATH);
1364 0 : if (ret != EOK) {
1365 0 : return ret;
1366 : }
1367 : }
1368 :
1369 : /* open a db for each domain */
1370 0 : for (dom = domains; dom; dom = dom->next) {
1371 :
1372 0 : ret = sysdb_domain_init_internal(mem_ctx, dom, DB_PATH,
1373 : allow_upgrade, &sysdb);
1374 0 : if (ret != EOK) {
1375 0 : return ret;
1376 : }
1377 :
1378 0 : if (chown_dbfile) {
1379 0 : ret = chown(sysdb->ldb_file, uid, gid);
1380 0 : if (ret != 0) {
1381 0 : ret = errno;
1382 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1383 : "Cannot set sysdb ownership to %"SPRIuid":%"SPRIgid"\n",
1384 : uid, gid);
1385 0 : return ret;
1386 : }
1387 : }
1388 :
1389 0 : dom->sysdb = talloc_move(dom, &sysdb);
1390 : }
1391 :
1392 0 : return EOK;
1393 : }
1394 :
1395 1081 : int sysdb_domain_init(TALLOC_CTX *mem_ctx,
1396 : struct sss_domain_info *domain,
1397 : const char *db_path,
1398 : struct sysdb_ctx **_ctx)
1399 : {
1400 1081 : return sysdb_domain_init_internal(mem_ctx, domain,
1401 : db_path, false, _ctx);
1402 : }
1403 :
1404 37 : int compare_ldb_dn_comp_num(const void *m1, const void *m2)
1405 : {
1406 37 : struct ldb_message *msg1 = talloc_get_type(*(void **) discard_const(m1),
1407 : struct ldb_message);
1408 37 : struct ldb_message *msg2 = talloc_get_type(*(void **) discard_const(m2),
1409 : struct ldb_message);
1410 :
1411 37 : return ldb_dn_get_comp_num(msg2->dn) - ldb_dn_get_comp_num(msg1->dn);
1412 : }
1413 :
1414 2 : int sysdb_attrs_replace_name(struct sysdb_attrs *attrs, const char *oldname,
1415 : const char *newname)
1416 : {
1417 2 : struct ldb_message_element *e = NULL;
1418 : int i;
1419 : const char *dummy;
1420 :
1421 2 : if (attrs == NULL || oldname == NULL || newname == NULL) return EINVAL;
1422 :
1423 7 : for (i = 0; i < attrs->num; i++) {
1424 6 : if (strcasecmp(oldname, attrs->a[i].name) == 0) {
1425 2 : e = &(attrs->a[i]);
1426 : }
1427 6 : if (strcasecmp(newname, attrs->a[i].name) == 0) {
1428 1 : DEBUG(SSSDBG_MINOR_FAILURE,
1429 : "New attribute name [%s] already exists.\n", newname);
1430 1 : return EEXIST;
1431 : }
1432 : }
1433 :
1434 1 : if (e != NULL) {
1435 1 : dummy = talloc_strdup(attrs, newname);
1436 1 : if (dummy == NULL) {
1437 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
1438 0 : return ENOMEM;
1439 : }
1440 :
1441 1 : talloc_free(discard_const(e->name));
1442 1 : e->name = dummy;
1443 : }
1444 :
1445 1 : return EOK;
1446 : }
1447 :
1448 : /* Search for all incidences of attr_name in a list of
1449 : * sysdb_attrs and add their value to a list
1450 : *
1451 : * TODO: Currently only works for single-valued
1452 : * attributes. Multi-valued attributes will return
1453 : * only the first entry
1454 : */
1455 1 : errno_t sysdb_attrs_to_list(TALLOC_CTX *mem_ctx,
1456 : struct sysdb_attrs **attrs,
1457 : int attr_count,
1458 : const char *attr_name,
1459 : char ***_list)
1460 : {
1461 : int attr_idx;
1462 : int i;
1463 : char **list;
1464 : char **tmp_list;
1465 : int list_idx;
1466 :
1467 1 : *_list = NULL;
1468 :
1469 : /* Assume that every attrs entry contains the attr_name
1470 : * This may waste a little memory if some entries don't
1471 : * have the attribute, but it will save us the trouble
1472 : * of continuously resizing the array.
1473 : */
1474 1 : list = talloc_array(mem_ctx, char *, attr_count+1);
1475 1 : if (!list) {
1476 0 : return ENOMEM;
1477 : }
1478 :
1479 1 : list_idx = 0;
1480 : /* Loop through all entries in attrs */
1481 4 : for (attr_idx = 0; attr_idx < attr_count; attr_idx++) {
1482 : /* Examine each attribute within the entry */
1483 4 : for (i = 0; i < attrs[attr_idx]->num; i++) {
1484 3 : if (strcasecmp(attrs[attr_idx]->a[i].name, attr_name) == 0) {
1485 : /* Attribute name matches the requested name
1486 : * Copy it to the output list
1487 : */
1488 4 : list[list_idx] = talloc_strdup(
1489 : list,
1490 2 : (const char *)attrs[attr_idx]->a[i].values[0].data);
1491 2 : if (!list[list_idx]) {
1492 0 : talloc_free(list);
1493 0 : return ENOMEM;
1494 : }
1495 2 : list_idx++;
1496 :
1497 : /* We only support single-valued attributes
1498 : * Break here and go on to the next entry
1499 : */
1500 2 : break;
1501 : }
1502 : }
1503 : }
1504 :
1505 1 : list[list_idx] = NULL;
1506 :
1507 : /* if list_idx < attr_count, do a realloc to
1508 : * reclaim unused memory
1509 : */
1510 1 : if (list_idx < attr_count) {
1511 1 : tmp_list = talloc_realloc(mem_ctx, list, char *, list_idx+1);
1512 1 : if (!tmp_list) {
1513 0 : talloc_zfree(list);
1514 0 : return ENOMEM;
1515 : }
1516 1 : list = tmp_list;
1517 : }
1518 :
1519 1 : *_list = list;
1520 1 : return EOK;
1521 : }
1522 :
1523 5 : errno_t sysdb_get_bool(struct sysdb_ctx *sysdb,
1524 : struct ldb_dn *dn,
1525 : const char *attr_name,
1526 : bool *value)
1527 : {
1528 : TALLOC_CTX *tmp_ctx;
1529 : struct ldb_result *res;
1530 : errno_t ret;
1531 : int lret;
1532 5 : const char *attrs[2] = {attr_name, NULL};
1533 : struct ldb_message_element *el;
1534 :
1535 5 : tmp_ctx = talloc_new(NULL);
1536 5 : if (tmp_ctx == NULL) {
1537 0 : return ENOMEM;
1538 : }
1539 :
1540 5 : lret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
1541 : attrs, NULL);
1542 5 : if (lret != LDB_SUCCESS) {
1543 0 : ret = sysdb_error_to_errno(lret);
1544 0 : goto done;
1545 : }
1546 :
1547 5 : if (res->count == 0) {
1548 : /* This entry has not been populated in LDB
1549 : * This is a common case, as unlike LDAP,
1550 : * LDB does not need to have all of its parent
1551 : * objects actually exist.
1552 : * This object in the sysdb exists mostly just
1553 : * to contain this attribute.
1554 : */
1555 2 : *value = false;
1556 2 : ret = ENOENT;
1557 2 : goto done;
1558 3 : } else if (res->count != 1) {
1559 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1560 : "Got more than one reply for base search!\n");
1561 0 : ret = EIO;
1562 0 : goto done;
1563 : }
1564 :
1565 3 : el = ldb_msg_find_element(res->msgs[0], attr_name);
1566 3 : if (el == NULL || el->num_values == 0) {
1567 1 : ret = ENOENT;
1568 1 : goto done;
1569 : }
1570 :
1571 2 : *value = ldb_msg_find_attr_as_bool(res->msgs[0], attr_name, false);
1572 :
1573 2 : ret = EOK;
1574 :
1575 : done:
1576 5 : talloc_free(tmp_ctx);
1577 5 : return ret;
1578 : }
1579 :
1580 2 : errno_t sysdb_set_bool(struct sysdb_ctx *sysdb,
1581 : struct ldb_dn *dn,
1582 : const char *cn_value,
1583 : const char *attr_name,
1584 : bool value)
1585 : {
1586 2 : TALLOC_CTX *tmp_ctx = NULL;
1587 2 : struct ldb_message *msg = NULL;
1588 2 : struct ldb_result *res = NULL;
1589 : errno_t ret;
1590 : int lret;
1591 :
1592 2 : if (dn == NULL || cn_value == NULL || attr_name == NULL) {
1593 0 : return EINVAL;
1594 : }
1595 :
1596 2 : tmp_ctx = talloc_new(NULL);
1597 2 : if (tmp_ctx == NULL) {
1598 0 : return ENOMEM;
1599 : }
1600 :
1601 2 : lret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
1602 : NULL, NULL);
1603 2 : if (lret != LDB_SUCCESS) {
1604 0 : ret = sysdb_error_to_errno(lret);
1605 0 : goto done;
1606 : }
1607 :
1608 2 : msg = ldb_msg_new(tmp_ctx);
1609 2 : if (msg == NULL) {
1610 0 : ret = ENOMEM;
1611 0 : goto done;
1612 : }
1613 2 : msg->dn = dn;
1614 :
1615 2 : if (res->count == 0) {
1616 1 : lret = ldb_msg_add_string(msg, "cn", cn_value);
1617 1 : if (lret != LDB_SUCCESS) {
1618 0 : ret = sysdb_error_to_errno(lret);
1619 0 : goto done;
1620 : }
1621 1 : } else if (res->count != 1) {
1622 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1623 : "Got more than one reply for base search!\n");
1624 0 : ret = EIO;
1625 0 : goto done;
1626 : } else {
1627 1 : lret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
1628 1 : if (lret != LDB_SUCCESS) {
1629 0 : ret = sysdb_error_to_errno(lret);
1630 0 : goto done;
1631 : }
1632 : }
1633 :
1634 2 : lret = ldb_msg_add_string(msg, attr_name, value ? "TRUE" : "FALSE");
1635 2 : if (lret != LDB_SUCCESS) {
1636 0 : ret = sysdb_error_to_errno(lret);
1637 0 : goto done;
1638 : }
1639 :
1640 2 : if (res->count) {
1641 1 : lret = ldb_modify(sysdb->ldb, msg);
1642 : } else {
1643 1 : lret = ldb_add(sysdb->ldb, msg);
1644 : }
1645 :
1646 2 : if (lret != LDB_SUCCESS) {
1647 0 : DEBUG(SSSDBG_OP_FAILURE,
1648 : "ldb operation failed: [%s](%d)[%s]\n",
1649 : ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb));
1650 : }
1651 2 : ret = sysdb_error_to_errno(lret);
1652 :
1653 : done:
1654 2 : talloc_free(tmp_ctx);
1655 2 : return ret;
1656 : }
1657 :
1658 2 : errno_t sysdb_has_enumerated(struct sss_domain_info *domain,
1659 : bool *has_enumerated)
1660 : {
1661 : errno_t ret;
1662 : struct ldb_dn *dn;
1663 : TALLOC_CTX *tmp_ctx;
1664 :
1665 :
1666 2 : tmp_ctx = talloc_new(NULL);
1667 2 : if (!tmp_ctx) {
1668 0 : ret = ENOMEM;
1669 0 : goto done;
1670 : }
1671 :
1672 2 : dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_DOM_BASE,
1673 : domain->name);
1674 2 : if (!dn) {
1675 0 : ret = ENOMEM;
1676 0 : goto done;
1677 : }
1678 :
1679 2 : ret = sysdb_get_bool(domain->sysdb, dn, SYSDB_HAS_ENUMERATED,
1680 : has_enumerated);
1681 :
1682 : done:
1683 2 : talloc_free(tmp_ctx);
1684 2 : return ret;
1685 : }
1686 :
1687 1 : errno_t sysdb_set_enumerated(struct sss_domain_info *domain,
1688 : bool enumerated)
1689 : {
1690 : errno_t ret;
1691 : TALLOC_CTX *tmp_ctx;
1692 : struct ldb_dn *dn;
1693 :
1694 1 : tmp_ctx = talloc_new(NULL);
1695 1 : if (!tmp_ctx) {
1696 0 : ret = ENOMEM;
1697 0 : goto done;
1698 : }
1699 :
1700 1 : dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_DOM_BASE,
1701 : domain->name);
1702 1 : if (!dn) {
1703 0 : ret = ENOMEM;
1704 0 : goto done;
1705 : }
1706 :
1707 1 : ret = sysdb_set_bool(domain->sysdb, dn, domain->name,
1708 : SYSDB_HAS_ENUMERATED, enumerated);
1709 :
1710 : done:
1711 1 : talloc_free(tmp_ctx);
1712 1 : return ret;
1713 : }
1714 :
1715 0 : errno_t sysdb_attrs_primary_name(struct sysdb_ctx *sysdb,
1716 : struct sysdb_attrs *attrs,
1717 : const char *ldap_attr,
1718 : const char **_primary)
1719 : {
1720 : errno_t ret;
1721 0 : char *rdn_attr = NULL;
1722 0 : char *rdn_val = NULL;
1723 : struct ldb_message_element *sysdb_name_el;
1724 : struct ldb_message_element *orig_dn_el;
1725 : size_t i;
1726 0 : TALLOC_CTX *tmp_ctx = NULL;
1727 :
1728 0 : tmp_ctx = talloc_new(NULL);
1729 0 : if (!tmp_ctx) {
1730 0 : return ENOMEM;
1731 : }
1732 :
1733 0 : ret = sysdb_attrs_get_el(attrs,
1734 : SYSDB_NAME,
1735 : &sysdb_name_el);
1736 0 : if (ret != EOK || sysdb_name_el->num_values == 0) {
1737 0 : ret = EINVAL;
1738 0 : goto done;
1739 : }
1740 :
1741 0 : if (sysdb_name_el->num_values == 1) {
1742 : /* Entry contains only one name. Just return that */
1743 0 : *_primary = (const char *)sysdb_name_el->values[0].data;
1744 0 : ret = EOK;
1745 0 : goto done;
1746 : }
1747 :
1748 : /* Multiple values for name. Check whether one matches the RDN */
1749 :
1750 0 : ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &orig_dn_el);
1751 0 : if (ret) {
1752 0 : goto done;
1753 : }
1754 0 : if (orig_dn_el->num_values == 0) {
1755 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Original DN is not available.\n");
1756 0 : ret = EINVAL;
1757 0 : goto done;
1758 0 : } else if (orig_dn_el->num_values == 1) {
1759 0 : ret = sysdb_get_rdn(sysdb, tmp_ctx,
1760 0 : (const char *) orig_dn_el->values[0].data,
1761 : &rdn_attr,
1762 : &rdn_val);
1763 0 : if (ret != EOK) {
1764 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not get rdn from [%s]\n",
1765 : (const char *) orig_dn_el->values[0].data);
1766 0 : goto done;
1767 : }
1768 : } else {
1769 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Should not have more than one origDN\n");
1770 0 : ret = EINVAL;
1771 0 : goto done;
1772 : }
1773 :
1774 : /* First check whether the attribute name matches */
1775 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Comparing attribute names [%s] and [%s]\n",
1776 : rdn_attr, ldap_attr);
1777 0 : if (strcasecmp(rdn_attr, ldap_attr) != 0) {
1778 : /* Multiple entries, and the RDN attribute doesn't match.
1779 : * We have no way of resolving this deterministically,
1780 : * so we'll use the first value as a fallback.
1781 : */
1782 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1783 : "The entry has multiple names and the RDN attribute does "
1784 : "not match. Will use the first value as fallback.\n");
1785 0 : *_primary = (const char *)sysdb_name_el->values[0].data;
1786 0 : ret = EOK;
1787 0 : goto done;
1788 : }
1789 :
1790 0 : for (i = 0; i < sysdb_name_el->num_values; i++) {
1791 0 : if (strcasecmp(rdn_val,
1792 0 : (const char *)sysdb_name_el->values[i].data) == 0) {
1793 : /* This name matches the RDN. Use it */
1794 0 : break;
1795 : }
1796 : }
1797 0 : if (i < sysdb_name_el->num_values) {
1798 : /* Match was found */
1799 0 : *_primary = (const char *)sysdb_name_el->values[i].data;
1800 : } else {
1801 : /* If we can't match the name to the RDN, we just have to
1802 : * throw up our hands. There's no deterministic way to
1803 : * decide which name is correct.
1804 : */
1805 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1806 : "Cannot save entry. Unable to determine groupname\n");
1807 0 : ret = EINVAL;
1808 0 : goto done;
1809 : }
1810 :
1811 0 : ret = EOK;
1812 :
1813 : done:
1814 0 : if (ret != EOK) {
1815 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1816 : "Could not determine primary name: [%d][%s]\n",
1817 : ret, strerror(ret));
1818 : }
1819 0 : talloc_free(tmp_ctx);
1820 0 : return ret;
1821 : }
1822 :
1823 : /*
1824 : * An entity with multiple names would have multiple SYSDB_NAME attributes
1825 : * after being translated into sysdb names using a map.
1826 : * Given a primary name returned by sysdb_attrs_primary_name(), this function
1827 : * returns the other SYSDB_NAME attribute values so they can be saved as
1828 : * SYSDB_NAME_ALIAS into cache.
1829 : *
1830 : * If lowercase is set, all aliases are duplicated in lowercase as well.
1831 : */
1832 0 : errno_t sysdb_attrs_get_aliases(TALLOC_CTX *mem_ctx,
1833 : struct sysdb_attrs *attrs,
1834 : const char *primary,
1835 : bool lowercase,
1836 : const char ***_aliases)
1837 : {
1838 0 : TALLOC_CTX *tmp_ctx = NULL;
1839 : struct ldb_message_element *sysdb_name_el;
1840 : size_t i, j, ai;
1841 : errno_t ret;
1842 0 : const char **aliases = NULL;
1843 : const char *name;
1844 : char *lower;
1845 :
1846 0 : if (_aliases == NULL) return EINVAL;
1847 :
1848 0 : tmp_ctx = talloc_new(NULL);
1849 0 : if (!tmp_ctx) {
1850 0 : return ENOMEM;
1851 : }
1852 :
1853 0 : ret = sysdb_attrs_get_el(attrs,
1854 : SYSDB_NAME,
1855 : &sysdb_name_el);
1856 0 : if (ret != EOK || sysdb_name_el->num_values == 0) {
1857 0 : ret = EINVAL;
1858 0 : goto done;
1859 : }
1860 :
1861 0 : aliases = talloc_array(tmp_ctx, const char *,
1862 : sysdb_name_el->num_values + 1);
1863 0 : if (!aliases) {
1864 0 : ret = ENOMEM;
1865 0 : goto done;
1866 : }
1867 :
1868 0 : if (lowercase) {
1869 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1870 : "Domain is case-insensitive; will add lowercased aliases\n");
1871 : }
1872 :
1873 0 : ai = 0;
1874 0 : for (i=0; i < sysdb_name_el->num_values; i++) {
1875 0 : name = (const char *)sysdb_name_el->values[i].data;
1876 :
1877 0 : if (lowercase) {
1878 : /* Domain is case-insensitive. Save the lower-cased version */
1879 0 : lower = sss_tc_utf8_str_tolower(tmp_ctx, name);
1880 0 : if (!lower) {
1881 0 : ret = ENOMEM;
1882 0 : goto done;
1883 : }
1884 :
1885 0 : for (j=0; j < ai; j++) {
1886 0 : if (sss_utf8_case_eq((const uint8_t *) aliases[j],
1887 : (const uint8_t *) lower) == ENOMATCH) {
1888 0 : break;
1889 : }
1890 : }
1891 :
1892 0 : if (ai == 0 || j < ai) {
1893 0 : aliases[ai] = talloc_strdup(aliases, lower);
1894 0 : if (!aliases[ai]) {
1895 0 : ret = ENOMEM;
1896 0 : goto done;
1897 : }
1898 0 : ai++;
1899 : }
1900 : } else {
1901 : /* Domain is case-sensitive. Save it as-is */
1902 0 : if (strcmp(primary, name) != 0) {
1903 0 : aliases[ai] = talloc_strdup(aliases, name);
1904 0 : if (!aliases[ai]) {
1905 0 : ret = ENOMEM;
1906 0 : goto done;
1907 : }
1908 0 : ai++;
1909 : }
1910 : }
1911 : }
1912 :
1913 0 : aliases[ai] = NULL;
1914 :
1915 0 : ret = EOK;
1916 :
1917 : done:
1918 0 : *_aliases = talloc_steal(mem_ctx, aliases);
1919 0 : talloc_free(tmp_ctx);
1920 0 : return ret;
1921 : }
1922 :
1923 0 : errno_t sysdb_attrs_primary_name_list(struct sysdb_ctx *sysdb,
1924 : TALLOC_CTX *mem_ctx,
1925 : struct sysdb_attrs **attr_list,
1926 : size_t attr_count,
1927 : const char *ldap_attr,
1928 : char ***name_list)
1929 : {
1930 : errno_t ret;
1931 : size_t i, j;
1932 : char **list;
1933 : const char *name;
1934 :
1935 : /* Assume that every entry has a primary name */
1936 0 : list = talloc_array(mem_ctx, char *, attr_count+1);
1937 0 : if (!list) {
1938 0 : return ENOMEM;
1939 : }
1940 :
1941 0 : j = 0;
1942 0 : for (i = 0; i < attr_count; i++) {
1943 0 : ret = sysdb_attrs_primary_name(sysdb,
1944 0 : attr_list[i],
1945 : ldap_attr,
1946 : &name);
1947 0 : if (ret != EOK) {
1948 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not determine primary name\n");
1949 : /* Skip and continue. Don't advance 'j' */
1950 0 : continue;
1951 : }
1952 :
1953 0 : list[j] = talloc_strdup(list, name);
1954 0 : if (!list[j]) {
1955 0 : ret = ENOMEM;
1956 0 : goto done;
1957 : }
1958 :
1959 0 : j++;
1960 : }
1961 :
1962 : /* NULL-terminate the list */
1963 0 : list[j] = NULL;
1964 :
1965 0 : *name_list = list;
1966 :
1967 0 : ret = EOK;
1968 :
1969 : done:
1970 0 : if (ret != EOK) {
1971 0 : talloc_free(list);
1972 : }
1973 0 : return ret;
1974 : }
1975 :
1976 0 : errno_t sysdb_msg2attrs(TALLOC_CTX *mem_ctx, size_t count,
1977 : struct ldb_message **msgs,
1978 : struct sysdb_attrs ***attrs)
1979 : {
1980 : int i;
1981 : struct sysdb_attrs **a;
1982 :
1983 0 : a = talloc_array(mem_ctx, struct sysdb_attrs *, count);
1984 0 : if (a == NULL) {
1985 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n");
1986 0 : return ENOMEM;
1987 : }
1988 :
1989 0 : for (i = 0; i < count; i++) {
1990 0 : a[i] = talloc(a, struct sysdb_attrs);
1991 0 : if (a[i] == NULL) {
1992 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
1993 0 : talloc_free(a);
1994 0 : return ENOMEM;
1995 : }
1996 0 : a[i]->num = msgs[i]->num_elements;
1997 0 : a[i]->a = talloc_steal(a[i], msgs[i]->elements);
1998 : }
1999 :
2000 0 : *attrs = a;
2001 :
2002 0 : return EOK;
2003 : }
|