Line data Source code
1 : /*
2 : SSSD
3 :
4 : LDAP Helper routines
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com>
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 "util/crypto/sss_crypto.h"
24 : #include "confdb/confdb.h"
25 : #include "providers/ldap/ldap_common.h"
26 : #include "providers/ldap/sdap.h"
27 : #include "providers/ldap/sdap_range.h"
28 :
29 : /* =Retrieve-Options====================================================== */
30 :
31 3 : errno_t sdap_copy_map_entry(const struct sdap_attr_map *src_map,
32 : struct sdap_attr_map *dst_map,
33 : int entry_index)
34 : {
35 3 : if (src_map[entry_index].name != NULL) {
36 4 : dst_map[entry_index].name = talloc_strdup(dst_map,
37 2 : src_map[entry_index].name);
38 2 : if (dst_map[entry_index].name == NULL) {
39 0 : return ENOMEM;
40 : }
41 : } else {
42 1 : dst_map->name = NULL;
43 : }
44 :
45 3 : return EOK;
46 : }
47 :
48 133 : int sdap_copy_map(TALLOC_CTX *memctx,
49 : struct sdap_attr_map *src_map,
50 : int num_entries,
51 : struct sdap_attr_map **_map)
52 : {
53 : struct sdap_attr_map *map;
54 : int i;
55 :
56 133 : map = talloc_array(memctx, struct sdap_attr_map, num_entries + 1);
57 133 : if (!map) {
58 0 : return ENOMEM;
59 : }
60 :
61 2627 : for (i = 0; i < num_entries; i++) {
62 2494 : map[i].opt_name = talloc_strdup(map, src_map[i].opt_name);
63 2494 : map[i].sys_name = talloc_strdup(map, src_map[i].sys_name);
64 2494 : if (map[i].opt_name == NULL || map[i].sys_name == NULL) {
65 0 : return ENOMEM;
66 : }
67 :
68 2494 : if (src_map[i].def_name != NULL) {
69 1848 : map[i].def_name = talloc_strdup(map, src_map[i].def_name);
70 1848 : map[i].name = talloc_strdup(map, src_map[i].def_name);
71 1848 : if (map[i].def_name == NULL || map[i].name == NULL) {
72 0 : return ENOMEM;
73 : }
74 : } else {
75 646 : map[i].def_name = NULL;
76 646 : map[i].name = NULL;
77 : }
78 :
79 2494 : DEBUG(SSSDBG_TRACE_FUNC, "Option %s has%s value %s\n",
80 : map[i].opt_name, map[i].name ? "" : " no",
81 : map[i].name ? map[i].name : "");
82 : }
83 :
84 : /* Include the sentinel */
85 133 : memset(&map[num_entries], 0, sizeof(struct sdap_attr_map));
86 :
87 133 : *_map = map;
88 133 : return EOK;
89 : }
90 :
91 5 : static errno_t split_extra_attr(TALLOC_CTX *mem_ctx,
92 : char *conf_attr,
93 : char **_sysdb_attr,
94 : char **_ldap_attr)
95 : {
96 : char *ldap_attr;
97 : char *sysdb_attr;
98 : char *sep;
99 :
100 5 : ldap_attr = conf_attr;
101 :
102 5 : sep = strchr(conf_attr, ':');
103 5 : if (sep == NULL) {
104 1 : sysdb_attr = talloc_strdup(mem_ctx, conf_attr);
105 1 : ldap_attr = talloc_strdup(mem_ctx, conf_attr);
106 : } else {
107 4 : if (sep == conf_attr || *(sep + 1) == '\0') {
108 2 : return ERR_INVALID_EXTRA_ATTR;
109 : }
110 :
111 2 : sysdb_attr = talloc_strndup(mem_ctx, ldap_attr,
112 2 : sep - ldap_attr);
113 2 : ldap_attr = talloc_strdup(mem_ctx, sep+1);
114 : }
115 :
116 3 : if (sysdb_attr == NULL || ldap_attr == NULL) {
117 0 : return ENOMEM;
118 : }
119 :
120 3 : *_sysdb_attr = sysdb_attr;
121 3 : *_ldap_attr = ldap_attr;
122 3 : return EOK;
123 : }
124 :
125 3 : static bool is_sysdb_duplicate(struct sdap_attr_map *map,
126 : int num_entries,
127 : const char *sysdb_attr)
128 : {
129 : int i;
130 :
131 78 : for (i = 0; i < num_entries; i++) {
132 76 : if (strcmp(map[i].sys_name, sysdb_attr) == 0) {
133 1 : return true;
134 : }
135 : }
136 :
137 2 : return false;
138 : }
139 :
140 4 : int sdap_extend_map(TALLOC_CTX *memctx,
141 : struct sdap_attr_map *src_map,
142 : size_t num_entries,
143 : char **extra_attrs,
144 : struct sdap_attr_map **_map,
145 : size_t *_new_size)
146 : {
147 : struct sdap_attr_map *map;
148 4 : size_t nextra = 0;
149 : size_t i;
150 : char *ldap_attr;
151 : char *sysdb_attr;
152 : errno_t ret;
153 :
154 4 : if (extra_attrs == NULL) {
155 1 : DEBUG(SSSDBG_FUNC_DATA, "No extra attributes\n");
156 1 : *_map = src_map;
157 1 : *_new_size = num_entries;
158 1 : return EOK;
159 : }
160 :
161 3 : for (nextra = 0; extra_attrs[nextra]; nextra++) ;
162 3 : DEBUG(SSSDBG_FUNC_DATA, "%zu extra attributes\n", nextra);
163 :
164 3 : map = talloc_realloc(memctx, src_map, struct sdap_attr_map,
165 : num_entries + nextra + 1);
166 3 : if (map == NULL) {
167 0 : return ENOMEM;
168 : }
169 :
170 7 : for (i = 0; extra_attrs[i]; i++) {
171 5 : ret = split_extra_attr(map, extra_attrs[i], &sysdb_attr, &ldap_attr);
172 5 : if (ret != EOK) {
173 2 : DEBUG(SSSDBG_MINOR_FAILURE, "Cannot split %s\n", extra_attrs[i]);
174 2 : continue;
175 : }
176 :
177 3 : if (is_sysdb_duplicate(map, num_entries, sysdb_attr)) {
178 1 : DEBUG(SSSDBG_FATAL_FAILURE,
179 : "Attribute %s (%s in LDAP) is already used by SSSD, please "
180 : "choose a different cache name\n", sysdb_attr, ldap_attr);
181 1 : return ERR_DUP_EXTRA_ATTR;
182 : }
183 :
184 2 : map[num_entries+i].name = ldap_attr;
185 2 : map[num_entries+i].sys_name = sysdb_attr;
186 4 : map[num_entries+i].opt_name = talloc_strdup(map,
187 2 : map[num_entries+i].name);
188 4 : map[num_entries+i].def_name = talloc_strdup(map,
189 2 : map[num_entries+i].name);
190 4 : if (map[num_entries+i].opt_name == NULL ||
191 4 : map[num_entries+i].sys_name == NULL ||
192 4 : map[num_entries+i].name == NULL ||
193 2 : map[num_entries+i].def_name == NULL) {
194 0 : return ENOMEM;
195 : }
196 2 : DEBUG(SSSDBG_TRACE_FUNC, "Extending map with %s\n", extra_attrs[i]);
197 : }
198 :
199 : /* Sentinel */
200 2 : memset(&map[num_entries+nextra], 0, sizeof(struct sdap_attr_map));
201 :
202 2 : *_map = map;
203 2 : *_new_size = num_entries + nextra;
204 2 : return EOK;
205 : }
206 :
207 7 : int sdap_extend_map_with_list(TALLOC_CTX *mem_ctx,
208 : struct sdap_options *opts,
209 : int extra_attr_index,
210 : struct sdap_attr_map *src_map,
211 : size_t num_entries,
212 : struct sdap_attr_map **_map,
213 : size_t *_new_size)
214 : {
215 : const char *extra_attrs;
216 : char **extra_attrs_list;
217 : errno_t ret;
218 :
219 7 : extra_attrs = dp_opt_get_string(opts->basic, extra_attr_index);
220 7 : if (extra_attrs == NULL) {
221 7 : *_map = src_map;
222 7 : *_new_size = num_entries;
223 7 : return EOK;
224 : }
225 :
226 : /* split server parm into a list */
227 0 : ret = split_on_separator(mem_ctx, extra_attrs, ',', true, true,
228 : &extra_attrs_list, NULL);
229 0 : if (ret != EOK) {
230 0 : DEBUG(SSSDBG_OP_FAILURE, ("Failed to parse server list!\n"));
231 0 : return ret;
232 : }
233 :
234 :
235 0 : ret = sdap_extend_map(mem_ctx, src_map,
236 : num_entries, extra_attrs_list,
237 : _map, _new_size);
238 0 : talloc_free(extra_attrs_list);
239 0 : if (ret != EOK) {
240 0 : return ret;
241 : }
242 :
243 0 : return EOK;
244 : }
245 :
246 16 : static void sdap_inherit_basic_options(char **inherit_opt_list,
247 : struct dp_option *parent_opts,
248 : struct dp_option *subdom_opts)
249 : {
250 16 : int inherit_options[] = {
251 : SDAP_PURGE_CACHE_TIMEOUT,
252 : SDAP_AD_USE_TOKENGROUPS,
253 : SDAP_OPTS_BASIC /* sentinel */
254 : };
255 : int i;
256 :
257 48 : for (i = 0; inherit_options[i] != SDAP_OPTS_BASIC; i++) {
258 32 : dp_option_inherit(inherit_opt_list,
259 : inherit_options[i],
260 : parent_opts,
261 : subdom_opts);
262 : }
263 16 : }
264 :
265 16 : static void sdap_inherit_user_options(char **inherit_opt_list,
266 : struct sdap_attr_map *parent_user_map,
267 : struct sdap_attr_map *child_user_map)
268 : {
269 16 : int inherit_options[] = {
270 : SDAP_AT_USER_PRINC,
271 : SDAP_OPTS_USER /* sentinel */
272 : };
273 : int i;
274 : int opt_index;
275 : bool inherit_option;
276 :
277 32 : for (i = 0; inherit_options[i] != SDAP_OPTS_USER; i++) {
278 16 : opt_index = inherit_options[i];
279 :
280 16 : inherit_option = string_in_list(parent_user_map[opt_index].opt_name,
281 : inherit_opt_list,
282 : false);
283 16 : if (inherit_option == false) {
284 15 : continue;
285 : }
286 :
287 1 : sdap_copy_map_entry(parent_user_map, child_user_map, opt_index);
288 : }
289 16 : }
290 :
291 16 : void sdap_inherit_options(char **inherit_opt_list,
292 : struct sdap_options *parent_sdap_opts,
293 : struct sdap_options *child_sdap_opts)
294 : {
295 16 : sdap_inherit_basic_options(inherit_opt_list,
296 : parent_sdap_opts->basic,
297 : child_sdap_opts->basic);
298 :
299 16 : sdap_inherit_user_options(inherit_opt_list,
300 : parent_sdap_opts->user_map,
301 : child_sdap_opts->user_map);
302 16 : }
303 :
304 35 : int sdap_get_map(TALLOC_CTX *memctx,
305 : struct confdb_ctx *cdb,
306 : const char *conf_path,
307 : struct sdap_attr_map *def_map,
308 : int num_entries,
309 : struct sdap_attr_map **_map)
310 : {
311 : struct sdap_attr_map *map;
312 : char *name;
313 : int i, ret;
314 :
315 35 : map = talloc_array(memctx, struct sdap_attr_map, num_entries);
316 35 : if (!map) {
317 0 : return ENOMEM;
318 : }
319 :
320 455 : for (i = 0; i < num_entries; i++) {
321 :
322 420 : map[i].opt_name = def_map[i].opt_name;
323 420 : map[i].def_name = def_map[i].def_name;
324 420 : map[i].sys_name = def_map[i].sys_name;
325 :
326 840 : ret = confdb_get_string(cdb, map, conf_path,
327 420 : map[i].opt_name,
328 420 : map[i].def_name,
329 : &name);
330 420 : if (ret != EOK) {
331 0 : DEBUG(SSSDBG_CRIT_FAILURE,
332 : "Failed to retrieve value for %s\n", map[i].opt_name);
333 0 : talloc_zfree(map);
334 0 : return EINVAL;
335 : }
336 :
337 420 : if (name) {
338 322 : ret = sss_filter_sanitize(map, name, &map[i].name);
339 322 : if (ret != EOK) {
340 0 : DEBUG(SSSDBG_CRIT_FAILURE,
341 : "Could not sanitize attribute [%s]\n", name);
342 0 : talloc_zfree(map);
343 0 : return EINVAL;
344 : }
345 322 : talloc_zfree(name);
346 : } else {
347 98 : map[i].name = NULL;
348 : }
349 :
350 420 : if (map[i].def_name && !map[i].name) {
351 0 : DEBUG(SSSDBG_CRIT_FAILURE,
352 : "Failed to retrieve value for %s\n", map[i].opt_name);
353 0 : talloc_zfree(map);
354 0 : return EINVAL;
355 : }
356 :
357 420 : DEBUG(SSSDBG_TRACE_FUNC, "Option %s has%s value %s\n",
358 : map[i].opt_name, map[i].name ? "" : " no",
359 : map[i].name ? map[i].name : "");
360 : }
361 :
362 35 : *_map = map;
363 35 : return EOK;
364 : }
365 :
366 : /* =Parse-msg============================================================= */
367 :
368 : static bool objectclass_matched(struct sdap_attr_map *map,
369 : const char *objcl, int len);
370 8 : int sdap_parse_entry(TALLOC_CTX *memctx,
371 : struct sdap_handle *sh, struct sdap_msg *sm,
372 : struct sdap_attr_map *map, int attrs_num,
373 : struct sysdb_attrs **_attrs,
374 : bool disable_range_retrieval)
375 : {
376 : struct sysdb_attrs *attrs;
377 8 : BerElement *ber = NULL;
378 : struct berval **vals;
379 : struct ldb_val v;
380 : char *str;
381 : int lerrno;
382 : int i, ret, ai;
383 8 : int base_attr_idx = 0;
384 : const char *name;
385 : bool store;
386 : bool base64;
387 : char *base_attr;
388 : uint32_t range_offset;
389 8 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
390 8 : if (!tmp_ctx) return ENOMEM;
391 :
392 8 : lerrno = 0;
393 8 : ret = ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
394 8 : if (ret != LDAP_OPT_SUCCESS) {
395 0 : DEBUG(SSSDBG_MINOR_FAILURE, "ldap_set_option failed [%s], ignored.\n",
396 : sss_ldap_err2string(ret));
397 : }
398 :
399 8 : attrs = sysdb_new_attrs(tmp_ctx);
400 8 : if (!attrs) {
401 0 : ret = ENOMEM;
402 0 : goto done;
403 : }
404 :
405 8 : str = ldap_get_dn(sh->ldap, sm->msg);
406 8 : if (!str) {
407 1 : ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
408 1 : DEBUG(SSSDBG_CRIT_FAILURE, "ldap_get_dn failed: %d(%s)\n",
409 : lerrno, sss_ldap_err2string(lerrno));
410 1 : ret = EIO;
411 1 : goto done;
412 : }
413 :
414 7 : DEBUG(SSSDBG_TRACE_LIBS, "OriginalDN: [%s].\n", str);
415 7 : ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, str);
416 7 : ldap_memfree(str);
417 7 : if (ret) goto done;
418 :
419 7 : if (map) {
420 6 : vals = ldap_get_values_len(sh->ldap, sm->msg, "objectClass");
421 6 : if (!vals) {
422 1 : DEBUG(SSSDBG_CRIT_FAILURE,
423 : "Unknown entry type, no objectClasses found!\n");
424 1 : ret = EINVAL;
425 1 : goto done;
426 : }
427 :
428 6 : for (i = 0; vals[i]; i++) {
429 5 : if (objectclass_matched(map, vals[i]->bv_val, vals[i]->bv_len)) {
430 : /* ok it's an entry of the right type */
431 4 : break;
432 : }
433 : }
434 5 : if (!vals[i]) {
435 1 : DEBUG(SSSDBG_CRIT_FAILURE, "objectClass not matching: %s\n",
436 : map[0].name);
437 1 : ldap_value_free_len(vals);
438 1 : ret = EINVAL;
439 1 : goto done;
440 : }
441 4 : ldap_value_free_len(vals);
442 : }
443 :
444 5 : str = ldap_first_attribute(sh->ldap, sm->msg, &ber);
445 5 : if (!str) {
446 0 : ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
447 0 : DEBUG(lerrno == LDAP_SUCCESS
448 : ? SSSDBG_TRACE_LIBS
449 : : SSSDBG_MINOR_FAILURE,
450 : "Entry has no attributes [%d(%s)]!?\n",
451 : lerrno, sss_ldap_err2string(lerrno));
452 0 : if (map) {
453 0 : ret = EINVAL;
454 0 : goto done;
455 : }
456 : }
457 22 : while (str) {
458 12 : base64 = false;
459 :
460 12 : ret = sdap_parse_range(tmp_ctx, str, &base_attr, &range_offset,
461 : disable_range_retrieval);
462 12 : switch(ret) {
463 : case EAGAIN:
464 : /* This attribute contained range values and needs more to
465 : * be retrieved
466 : */
467 : /* TODO: return the set of attributes that need additional retrieval
468 : * For now, we'll continue below and treat it as regular values.
469 : */
470 : /* FALLTHROUGH */
471 : case ECANCELED:
472 : /* FALLTHROUGH */
473 : case EOK:
474 12 : break;
475 : default:
476 0 : DEBUG(SSSDBG_CRIT_FAILURE,
477 : "Could not determine if attribute [%s] was ranged\n", str);
478 0 : goto done;
479 : }
480 :
481 12 : if (map) {
482 234 : for (i = 1; i < attrs_num; i++) {
483 : /* check if this attr is valid with the chosen schema */
484 228 : if (!map[i].name) continue;
485 : /* check if it is an attr we are interested in */
486 198 : if (strcasecmp(base_attr, map[i].name) == 0) break;
487 : }
488 : /* interesting attr */
489 10 : if (i < attrs_num) {
490 4 : store = true;
491 4 : name = map[i].sys_name;
492 4 : base_attr_idx = i;
493 4 : if (strcmp(name, SYSDB_SSH_PUBKEY) == 0) {
494 1 : base64 = true;
495 : }
496 : } else {
497 6 : store = false;
498 6 : name = NULL;
499 : }
500 : } else {
501 2 : name = base_attr;
502 2 : store = true;
503 : }
504 :
505 12 : if (ret == ECANCELED) {
506 0 : ret = EOK;
507 0 : store = false;
508 : }
509 :
510 12 : if (store) {
511 6 : vals = ldap_get_values_len(sh->ldap, sm->msg, str);
512 6 : if (!vals) {
513 0 : ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
514 0 : if (lerrno != LDAP_SUCCESS) {
515 0 : DEBUG(SSSDBG_CRIT_FAILURE, "LDAP Library error: %d(%s)\n",
516 : lerrno, sss_ldap_err2string(lerrno));
517 0 : ret = EIO;
518 0 : goto done;
519 : }
520 :
521 0 : DEBUG(SSSDBG_TRACE_LIBS,
522 : "Attribute [%s] has no values, skipping.\n", str);
523 :
524 : } else {
525 6 : if (!vals[0]) {
526 0 : DEBUG(SSSDBG_CRIT_FAILURE,
527 : "Missing value after ldap_get_values() ??\n");
528 0 : ldap_value_free_len(vals);
529 0 : ret = EINVAL;
530 0 : goto done;
531 : }
532 14 : for (i = 0; vals[i]; i++) {
533 8 : if (vals[i]->bv_len == 0) {
534 0 : DEBUG(SSSDBG_TRACE_LIBS,
535 : "Value of attribute [%s] is empty. "
536 : "Skipping this value.\n", str);
537 0 : continue;
538 : }
539 8 : if (base64) {
540 2 : v.data = (uint8_t *) sss_base64_encode(attrs,
541 2 : (uint8_t *) vals[i]->bv_val, vals[i]->bv_len);
542 1 : if (!v.data) {
543 0 : ldap_value_free_len(vals);
544 0 : ret = ENOMEM;
545 0 : goto done;
546 : }
547 1 : v.length = strlen((const char *)v.data);
548 : } else {
549 7 : v.data = (uint8_t *)vals[i]->bv_val;
550 7 : v.length = vals[i]->bv_len;
551 : }
552 :
553 8 : if (map) {
554 : /* The same LDAP attr might be used for more sysdb
555 : * attrs in case there is a map. Find all that match
556 : * and copy the value
557 : */
558 100 : for (ai = base_attr_idx; ai < attrs_num; ai++) {
559 : /* check if this attr is valid with the chosen
560 : * schema */
561 95 : if (!map[ai].name) continue;
562 :
563 : /* check if it is an attr we are interested in */
564 86 : if (strcasecmp(base_attr, map[ai].name) == 0) {
565 6 : ret = sysdb_attrs_add_val(attrs,
566 6 : map[ai].sys_name,
567 : &v);
568 6 : if (ret) {
569 0 : ldap_value_free_len(vals);
570 0 : goto done;
571 : }
572 : }
573 : }
574 : } else {
575 : /* No map, just store the attribute */
576 3 : ret = sysdb_attrs_add_val(attrs, name, &v);
577 3 : if (ret) {
578 0 : ldap_value_free_len(vals);
579 0 : goto done;
580 : }
581 : }
582 : }
583 6 : ldap_value_free_len(vals);
584 : }
585 : }
586 :
587 12 : ldap_memfree(str);
588 12 : str = ldap_next_attribute(sh->ldap, sm->msg, ber);
589 : }
590 5 : ber_free(ber, 0);
591 5 : ber = NULL;
592 :
593 5 : ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
594 5 : if (lerrno) {
595 0 : DEBUG(SSSDBG_CRIT_FAILURE, "LDAP Library error: %d(%s)\n",
596 : lerrno, sss_ldap_err2string(lerrno));
597 0 : ret = EIO;
598 0 : goto done;
599 : }
600 :
601 5 : *_attrs = talloc_steal(memctx, attrs);
602 5 : ret = EOK;
603 :
604 : done:
605 8 : if (ber) ber_free(ber, 0);
606 8 : talloc_free(tmp_ctx);
607 8 : return ret;
608 : }
609 :
610 7 : static bool objectclass_matched(struct sdap_attr_map *map,
611 : const char *objcl, int len)
612 : {
613 7 : if (len == 0) {
614 2 : len = strlen(objcl) + 1;
615 : }
616 :
617 7 : if (strncasecmp(map[SDAP_OC_GROUP].name, objcl, len) == 0) {
618 4 : return true;
619 : }
620 :
621 3 : if (map[SDAP_OC_GROUP_ALT].name != NULL
622 2 : && strncasecmp(map[SDAP_OC_GROUP_ALT].name, objcl, len) == 0) {
623 1 : return true;
624 : }
625 :
626 2 : return false;
627 : }
628 :
629 : /* Parses an LDAPDerefRes into sdap_deref_attrs structure */
630 3 : errno_t sdap_parse_deref(TALLOC_CTX *mem_ctx,
631 : struct sdap_attr_map_info *minfo,
632 : size_t num_maps,
633 : LDAPDerefRes *dref,
634 : struct sdap_deref_attrs ***_deref_res)
635 : {
636 : TALLOC_CTX *tmp_ctx;
637 : LDAPDerefVal *dval;
638 : const char *orig_dn;
639 : const char **ocs;
640 : struct sdap_attr_map *map;
641 : int num_attrs;
642 : int ret, i, a, mi;
643 : const char *name;
644 : size_t len;
645 : struct sdap_deref_attrs **res;
646 :
647 3 : if (!dref || !minfo) return EINVAL;
648 :
649 3 : tmp_ctx = talloc_new(NULL);
650 3 : if (!tmp_ctx) return ENOMEM;
651 :
652 3 : res = talloc_array(tmp_ctx, struct sdap_deref_attrs *, num_maps);
653 3 : if (!res) {
654 0 : ret = ENOMEM;
655 0 : goto done;
656 : }
657 :
658 6 : for (i=0; i < num_maps; i++) {
659 3 : res[i] = talloc_zero(res, struct sdap_deref_attrs);
660 3 : if (!res[i]) {
661 0 : ret = ENOMEM;
662 0 : goto done;
663 : }
664 :
665 3 : res[i]->map = minfo[i].map;
666 : }
667 :
668 3 : if (!dref->derefVal.bv_val) {
669 0 : DEBUG(SSSDBG_OP_FAILURE, "Entry has no DN?\n");
670 0 : ret = EINVAL;
671 0 : goto done;
672 : }
673 :
674 3 : orig_dn = dref->derefVal.bv_val;
675 3 : DEBUG(SSSDBG_TRACE_LIBS,
676 : "Dereferenced DN: %s\n", orig_dn);
677 :
678 3 : if (!dref->attrVals) {
679 1 : DEBUG(SSSDBG_FUNC_DATA,
680 : "Dereferenced entry [%s] has no attributes, skipping\n",
681 : orig_dn);
682 1 : *_deref_res = NULL;
683 1 : ret = EOK;
684 1 : goto done;
685 : }
686 :
687 2 : ocs = NULL;
688 2 : for (dval = dref->attrVals; dval != NULL; dval = dval->next) {
689 2 : if (strcasecmp("objectClass", dval->type) == 0) {
690 2 : if (dval->vals == NULL) {
691 0 : DEBUG(SSSDBG_CONF_SETTINGS,
692 : "No value for objectClass, skipping\n");
693 0 : continue;
694 : }
695 :
696 2 : for(len=0; dval->vals[len].bv_val; len++);
697 :
698 2 : ocs = talloc_array(tmp_ctx, const char *, len+1);
699 2 : if (!ocs) {
700 0 : ret = ENOMEM;
701 0 : goto done;
702 : }
703 :
704 4 : for (i=0; i<len; i++) {
705 2 : DEBUG(SSSDBG_TRACE_ALL, "Dereferenced objectClass value: %s\n",
706 : dval->vals[i].bv_val);
707 2 : ocs[i] = talloc_strdup(ocs, dval->vals[i].bv_val);
708 2 : if (!ocs[i]) {
709 0 : ret = ENOMEM;
710 0 : goto done;
711 : }
712 : }
713 2 : ocs[i] = NULL;
714 2 : break;
715 : }
716 : }
717 2 : if (!ocs) {
718 0 : DEBUG(SSSDBG_CRIT_FAILURE,
719 : "Unknown entry type, no objectClasses found!\n");
720 0 : ret = EINVAL;
721 0 : goto done;
722 : }
723 :
724 4 : for (mi = 0; mi < num_maps; mi++) {
725 2 : map = NULL;
726 :
727 3 : for (i=0; ocs[i]; i++) {
728 : /* the objectclass is always the first name in the map */
729 2 : if (objectclass_matched(minfo[mi].map, ocs[i], 0)) {
730 1 : DEBUG(SSSDBG_TRACE_ALL,
731 : "Found map for objectclass '%s'\n", ocs[i]);
732 1 : map = minfo[mi].map;
733 1 : num_attrs = minfo[mi].num_attrs;
734 1 : break;
735 : }
736 : }
737 2 : if (!map) continue;
738 :
739 1 : res[mi]->attrs = sysdb_new_attrs(res[mi]);
740 1 : if (!res[mi]->attrs) {
741 0 : ret = ENOMEM;
742 0 : goto done;
743 : }
744 :
745 1 : ret = sysdb_attrs_add_string(res[mi]->attrs, SYSDB_ORIG_DN,
746 : orig_dn);
747 1 : if (ret) {
748 0 : goto done;
749 : }
750 :
751 4 : for (dval = dref->attrVals; dval != NULL; dval = dval->next) {
752 3 : DEBUG(SSSDBG_TRACE_INTERNAL,
753 : "Dereferenced attribute: %s\n", dval->type);
754 :
755 75 : for (a = 1; a < num_attrs; a++) {
756 : /* check if this attr is valid with the chosen schema */
757 73 : if (!map[a].name) continue;
758 : /* check if it is an attr we are interested in */
759 59 : if (strcasecmp(dval->type, map[a].name) == 0) break;
760 : }
761 :
762 : /* interesting attr */
763 3 : if (a < num_attrs) {
764 1 : name = map[a].sys_name;
765 : } else {
766 2 : continue;
767 : }
768 :
769 1 : if (dval->vals == NULL) {
770 0 : DEBUG(SSSDBG_CONF_SETTINGS,
771 : "No value for attribute %s, skipping\n", name);
772 0 : continue;
773 : }
774 :
775 2 : for (i=0; dval->vals[i].bv_val; i++) {
776 1 : DEBUG(SSSDBG_TRACE_ALL, "Dereferenced attribute value: %s\n",
777 : dval->vals[i].bv_val);
778 2 : ret = sysdb_attrs_add_mem(res[mi]->attrs, name,
779 1 : dval->vals[i].bv_val,
780 1 : dval->vals[i].bv_len);
781 1 : if (ret) goto done;
782 : }
783 : }
784 : }
785 :
786 :
787 2 : *_deref_res = talloc_steal(mem_ctx, res);
788 2 : ret = EOK;
789 : done:
790 3 : talloc_zfree(tmp_ctx);
791 3 : return ret;
792 : }
793 :
794 0 : errno_t setup_tls_config(struct dp_option *basic_opts)
795 : {
796 : int ret;
797 : int ldap_opt_x_tls_require_cert;
798 : const char *tls_opt;
799 0 : tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_REQCERT);
800 0 : if (tls_opt) {
801 0 : if (strcasecmp(tls_opt, "never") == 0) {
802 0 : ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_NEVER;
803 : }
804 0 : else if (strcasecmp(tls_opt, "allow") == 0) {
805 0 : ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_ALLOW;
806 : }
807 0 : else if (strcasecmp(tls_opt, "try") == 0) {
808 0 : ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_TRY;
809 : }
810 0 : else if (strcasecmp(tls_opt, "demand") == 0) {
811 0 : ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_DEMAND;
812 : }
813 0 : else if (strcasecmp(tls_opt, "hard") == 0) {
814 0 : ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_HARD;
815 : }
816 : else {
817 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown value for tls_reqcert.\n");
818 0 : return EINVAL;
819 : }
820 : /* LDAP_OPT_X_TLS_REQUIRE_CERT has to be set as a global option,
821 : * because the SSL/TLS context is initialized from this value. */
822 0 : ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
823 : &ldap_opt_x_tls_require_cert);
824 0 : if (ret != LDAP_OPT_SUCCESS) {
825 0 : DEBUG(SSSDBG_CRIT_FAILURE,
826 : "ldap_set_option failed: %s\n", sss_ldap_err2string(ret));
827 0 : return EIO;
828 : }
829 : }
830 :
831 0 : tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_CACERT);
832 0 : if (tls_opt) {
833 0 : ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, tls_opt);
834 0 : if (ret != LDAP_OPT_SUCCESS) {
835 0 : DEBUG(SSSDBG_CRIT_FAILURE,
836 : "ldap_set_option failed: %s\n", sss_ldap_err2string(ret));
837 0 : return EIO;
838 : }
839 : }
840 :
841 0 : tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_CACERTDIR);
842 0 : if (tls_opt) {
843 0 : ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR, tls_opt);
844 0 : if (ret != LDAP_OPT_SUCCESS) {
845 0 : DEBUG(SSSDBG_CRIT_FAILURE,
846 : "ldap_set_option failed: %s\n", sss_ldap_err2string(ret));
847 0 : return EIO;
848 : }
849 : }
850 :
851 0 : tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_CERT);
852 0 : if (tls_opt) {
853 0 : ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE, tls_opt);
854 0 : if (ret != LDAP_OPT_SUCCESS) {
855 0 : DEBUG(SSSDBG_CRIT_FAILURE,
856 : "ldap_set_option failed: %s\n", sss_ldap_err2string(ret));
857 0 : return EIO;
858 : }
859 : }
860 :
861 0 : tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_KEY);
862 0 : if (tls_opt) {
863 0 : ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE, tls_opt);
864 0 : if (ret != LDAP_OPT_SUCCESS) {
865 0 : DEBUG(SSSDBG_CRIT_FAILURE,
866 : "ldap_set_option failed: %s\n", sss_ldap_err2string(ret));
867 0 : return EIO;
868 : }
869 : }
870 :
871 0 : tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_CIPHER_SUITE);
872 0 : if (tls_opt) {
873 0 : ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, tls_opt);
874 0 : if (ret != LDAP_OPT_SUCCESS) {
875 0 : DEBUG(SSSDBG_CRIT_FAILURE,
876 : "ldap_set_option failed: %s\n", sss_ldap_err2string(ret));
877 0 : return EIO;
878 : }
879 : }
880 :
881 0 : return EOK;
882 : }
883 :
884 :
885 0 : bool sdap_check_sup_list(struct sup_list *l, const char *val)
886 : {
887 : int i;
888 :
889 0 : if (!val) {
890 0 : return false;
891 : }
892 :
893 0 : for (i = 0; i < l->num_vals; i++) {
894 0 : if (strcasecmp(val, (char *)l->vals[i])) {
895 0 : continue;
896 : }
897 0 : return true;
898 : }
899 :
900 0 : return false;
901 : }
902 :
903 0 : static int sdap_init_sup_list(TALLOC_CTX *memctx,
904 : struct sup_list *list,
905 : int num, struct ldb_val *vals)
906 : {
907 : int i;
908 :
909 0 : list->vals = talloc_array(memctx, char *, num);
910 0 : if (!list->vals) {
911 0 : return ENOMEM;
912 : }
913 :
914 0 : for (i = 0; i < num; i++) {
915 0 : list->vals[i] = talloc_strndup(list->vals,
916 0 : (char *)vals[i].data, vals[i].length);
917 0 : if (!list->vals[i]) {
918 0 : return ENOMEM;
919 : }
920 : }
921 :
922 0 : list->num_vals = num;
923 :
924 0 : return EOK;
925 : }
926 :
927 0 : int sdap_set_rootdse_supported_lists(struct sysdb_attrs *rootdse,
928 : struct sdap_handle *sh)
929 : {
930 0 : struct ldb_message_element *el = NULL;
931 : int ret;
932 : int i;
933 :
934 0 : for (i = 0; i < rootdse->num; i++) {
935 0 : el = &rootdse->a[i];
936 0 : if (strcasecmp(el->name, "supportedControl") == 0) {
937 :
938 0 : ret = sdap_init_sup_list(sh, &sh->supported_controls,
939 0 : el->num_values, el->values);
940 0 : if (ret) {
941 0 : return ret;
942 : }
943 0 : } else if (strcasecmp(el->name, "supportedExtension") == 0) {
944 :
945 0 : ret = sdap_init_sup_list(sh, &sh->supported_extensions,
946 0 : el->num_values, el->values);
947 0 : if (ret) {
948 0 : return ret;
949 : }
950 0 : } else if (strcasecmp(el->name, "supportedSASLMechanisms") == 0) {
951 :
952 0 : ret = sdap_init_sup_list(sh, &sh->supported_saslmechs,
953 0 : el->num_values, el->values);
954 0 : if (ret) {
955 0 : return ret;
956 : }
957 : }
958 : }
959 :
960 0 : return EOK;
961 :
962 : }
963 :
964 0 : static char *get_single_value_as_string(TALLOC_CTX *mem_ctx,
965 : struct ldb_message_element *el)
966 : {
967 0 : char *str = NULL;
968 :
969 0 : if (el->num_values == 0) {
970 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Missing value.\n");
971 0 : } else if (el->num_values == 1) {
972 0 : str = talloc_strndup(mem_ctx, (char *) el->values[0].data,
973 0 : el->values[0].length);
974 0 : if (str == NULL) {
975 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
976 : }
977 : } else {
978 0 : DEBUG(SSSDBG_MINOR_FAILURE, "More than one value found.\n");
979 : }
980 :
981 0 : return str;
982 : }
983 :
984 0 : static char *get_naming_context(TALLOC_CTX *mem_ctx,
985 : struct sysdb_attrs *rootdse)
986 : {
987 0 : struct ldb_message_element *nc = NULL;
988 0 : struct ldb_message_element *dnc = NULL;
989 : int i;
990 0 : char *naming_context = NULL;
991 :
992 0 : for (i = 0; i < rootdse->num; i++) {
993 0 : if (strcasecmp(rootdse->a[i].name,
994 : SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS) == 0) {
995 0 : nc = &rootdse->a[i];
996 0 : } else if (strcasecmp(rootdse->a[i].name,
997 : SDAP_ROOTDSE_ATTR_DEFAULT_NAMING_CONTEXT) == 0) {
998 0 : dnc = &rootdse->a[i];
999 : }
1000 : }
1001 :
1002 0 : if (dnc == NULL && nc == NULL) {
1003 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1004 : "No attributes [%s] or [%s] found in rootDSE.\n",
1005 : SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS,
1006 : SDAP_ROOTDSE_ATTR_DEFAULT_NAMING_CONTEXT);
1007 : } else {
1008 0 : if (dnc != NULL) {
1009 0 : DEBUG(SSSDBG_FUNC_DATA,
1010 : "Using value from [%s] as naming context.\n",
1011 : SDAP_ROOTDSE_ATTR_DEFAULT_NAMING_CONTEXT);
1012 0 : naming_context = get_single_value_as_string(mem_ctx, dnc);
1013 : }
1014 :
1015 0 : if (naming_context == NULL && nc != NULL) {
1016 0 : DEBUG(SSSDBG_FUNC_DATA,
1017 : "Using value from [%s] as naming context.\n",
1018 : SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS);
1019 0 : naming_context = get_single_value_as_string(mem_ctx, nc);
1020 : }
1021 : }
1022 :
1023 : /* Some directory servers such as Novell eDirectory will return
1024 : * a zero-length namingContexts value in some situations. In this
1025 : * case, we should return it as NULL so things fail gracefully.
1026 : */
1027 0 : if (naming_context && naming_context[0] == '\0') {
1028 0 : talloc_zfree(naming_context);
1029 : }
1030 :
1031 0 : return naming_context;
1032 : }
1033 :
1034 : errno_t
1035 74 : sdap_create_search_base(TALLOC_CTX *mem_ctx,
1036 : const char *unparsed_base,
1037 : int scope,
1038 : const char *filter,
1039 : struct sdap_search_base **_base)
1040 : {
1041 : struct sdap_search_base *base;
1042 : TALLOC_CTX *tmp_ctx;
1043 : errno_t ret;
1044 : struct ldb_dn *ldn;
1045 : struct ldb_context *ldb;
1046 :
1047 74 : tmp_ctx = talloc_new(NULL);
1048 74 : if (!tmp_ctx) {
1049 0 : ret = ENOMEM;
1050 0 : goto done;
1051 : }
1052 :
1053 : /* Create a throwaway LDB context for validating the DN */
1054 74 : ldb = ldb_init(tmp_ctx, NULL);
1055 74 : if (!ldb) {
1056 0 : ret = ENOMEM;
1057 0 : goto done;
1058 : }
1059 :
1060 74 : base = talloc_zero(tmp_ctx, struct sdap_search_base);
1061 74 : if (base == NULL) {
1062 0 : ret = ENOMEM;
1063 0 : goto done;
1064 : }
1065 :
1066 74 : base->basedn = talloc_strdup(base, unparsed_base);
1067 74 : if (base->basedn == NULL) {
1068 0 : ret = ENOMEM;
1069 0 : goto done;
1070 : }
1071 :
1072 : /* Validate the basedn */
1073 74 : ldn = ldb_dn_new(tmp_ctx, ldb, unparsed_base);
1074 74 : if (!ldn) {
1075 0 : ret = ENOMEM;
1076 0 : goto done;
1077 : }
1078 :
1079 74 : if (!ldb_dn_validate(ldn)) {
1080 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid base DN [%s]\n", unparsed_base);
1081 0 : ret = EINVAL;
1082 0 : goto done;
1083 : }
1084 :
1085 74 : base->scope = scope;
1086 74 : base->filter = filter;
1087 :
1088 74 : *_base = talloc_steal(mem_ctx, base);
1089 74 : ret = EOK;
1090 : done:
1091 74 : talloc_free(tmp_ctx);
1092 74 : return ret;
1093 : }
1094 :
1095 0 : static errno_t sdap_set_search_base(struct sdap_options *opts,
1096 : struct sdap_domain *sdom,
1097 : enum sdap_basic_opt class,
1098 : char *naming_context)
1099 : {
1100 : errno_t ret;
1101 : struct sdap_search_base ***bases;
1102 :
1103 0 : switch(class) {
1104 : case SDAP_SEARCH_BASE:
1105 0 : bases = &sdom->search_bases;
1106 0 : break;
1107 : case SDAP_USER_SEARCH_BASE:
1108 0 : bases = &sdom->user_search_bases;
1109 0 : break;
1110 : case SDAP_GROUP_SEARCH_BASE:
1111 0 : bases = &sdom->group_search_bases;
1112 0 : break;
1113 : case SDAP_NETGROUP_SEARCH_BASE:
1114 0 : bases = &sdom->netgroup_search_bases;
1115 0 : break;
1116 : case SDAP_SUDO_SEARCH_BASE:
1117 0 : bases = &sdom->sudo_search_bases;
1118 0 : break;
1119 : case SDAP_SERVICE_SEARCH_BASE:
1120 0 : bases = &sdom->service_search_bases;
1121 0 : break;
1122 : case SDAP_AUTOFS_SEARCH_BASE:
1123 0 : bases = &sdom->autofs_search_bases;
1124 0 : break;
1125 : default:
1126 0 : return EINVAL;
1127 : }
1128 :
1129 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1130 : "Setting option [%s] to [%s].\n",
1131 : opts->basic[class].opt_name, naming_context);
1132 :
1133 0 : ret = dp_opt_set_string(opts->basic, class, naming_context);
1134 0 : if (ret != EOK) {
1135 0 : DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n");
1136 0 : goto done;
1137 : }
1138 :
1139 0 : ret = sdap_parse_search_base(opts, opts->basic, class, bases);
1140 0 : if (ret != EOK) goto done;
1141 :
1142 0 : ret = EOK;
1143 : done:
1144 0 : return ret;
1145 : }
1146 :
1147 0 : errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
1148 : struct sdap_options *opts,
1149 : struct sdap_domain *sdom)
1150 : {
1151 : int ret;
1152 0 : char *naming_context = NULL;
1153 :
1154 0 : if (!sdom->search_bases
1155 0 : || !sdom->user_search_bases
1156 0 : || !sdom->group_search_bases
1157 0 : || !sdom->netgroup_search_bases
1158 0 : || !sdom->sudo_search_bases
1159 0 : || !sdom->autofs_search_bases) {
1160 0 : naming_context = get_naming_context(opts->basic, rootdse);
1161 0 : if (naming_context == NULL) {
1162 0 : DEBUG(SSSDBG_CRIT_FAILURE, "get_naming_context failed.\n");
1163 :
1164 : /* This has to be non-fatal, since some servers offer
1165 : * multiple namingContexts entries. We will just
1166 : * add NULL checks for the search bases in the lookups.
1167 : */
1168 0 : ret = EOK;
1169 0 : goto done;
1170 : }
1171 : }
1172 :
1173 : /* Default */
1174 0 : if (!sdom->search_bases) {
1175 0 : ret = sdap_set_search_base(opts, sdom,
1176 : SDAP_SEARCH_BASE,
1177 : naming_context);
1178 0 : if (ret != EOK) goto done;
1179 : }
1180 :
1181 : /* Users */
1182 0 : if (!sdom->user_search_bases) {
1183 0 : ret = sdap_set_search_base(opts, sdom,
1184 : SDAP_USER_SEARCH_BASE,
1185 : naming_context);
1186 0 : if (ret != EOK) goto done;
1187 : }
1188 :
1189 : /* Groups */
1190 0 : if (!sdom->group_search_bases) {
1191 0 : ret = sdap_set_search_base(opts, sdom,
1192 : SDAP_GROUP_SEARCH_BASE,
1193 : naming_context);
1194 0 : if (ret != EOK) goto done;
1195 : }
1196 :
1197 : /* Netgroups */
1198 0 : if (!sdom->netgroup_search_bases) {
1199 0 : ret = sdap_set_search_base(opts, sdom,
1200 : SDAP_NETGROUP_SEARCH_BASE,
1201 : naming_context);
1202 0 : if (ret != EOK) goto done;
1203 : }
1204 :
1205 : /* Sudo */
1206 0 : if (!sdom->sudo_search_bases) {
1207 0 : ret = sdap_set_search_base(opts, sdom,
1208 : SDAP_SUDO_SEARCH_BASE,
1209 : naming_context);
1210 0 : if (ret != EOK) goto done;
1211 : }
1212 :
1213 : /* Services */
1214 0 : if (!sdom->service_search_bases) {
1215 0 : ret = sdap_set_search_base(opts, sdom,
1216 : SDAP_SERVICE_SEARCH_BASE,
1217 : naming_context);
1218 0 : if (ret != EOK) goto done;
1219 : }
1220 :
1221 : /* autofs */
1222 0 : if (!sdom->autofs_search_bases) {
1223 0 : ret = sdap_set_search_base(opts, sdom,
1224 : SDAP_AUTOFS_SEARCH_BASE,
1225 : naming_context);
1226 0 : if (ret != EOK) goto done;
1227 : }
1228 :
1229 0 : ret = EOK;
1230 :
1231 : done:
1232 0 : talloc_free(naming_context);
1233 0 : return ret;
1234 : }
1235 :
1236 0 : int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx,
1237 : const char *server,
1238 : struct sysdb_attrs *rootdse,
1239 : struct sdap_options *opts,
1240 : struct sdap_server_opts **srv_opts)
1241 : {
1242 : struct sdap_server_opts *so;
1243 : struct {
1244 : const char *last_name;
1245 : const char *entry_name;
1246 0 : } usn_attrs[] = { { SDAP_IPA_LAST_USN, SDAP_IPA_USN },
1247 : { SDAP_AD_LAST_USN, SDAP_AD_USN },
1248 : { NULL, NULL } };
1249 : const char *last_usn_name;
1250 : const char *last_usn_value;
1251 : const char *entry_usn_name;
1252 0 : char *endptr = NULL;
1253 : int ret;
1254 : int i;
1255 : uint32_t dc_level;
1256 :
1257 0 : so = talloc_zero(memctx, struct sdap_server_opts);
1258 0 : if (!so) {
1259 0 : return ENOMEM;
1260 : }
1261 0 : so->server_id = talloc_strdup(so, server);
1262 0 : if (!so->server_id) {
1263 0 : talloc_zfree(so);
1264 0 : return ENOMEM;
1265 : }
1266 :
1267 0 : last_usn_name = opts->gen_map[SDAP_AT_LAST_USN].name;
1268 0 : entry_usn_name = opts->gen_map[SDAP_AT_ENTRY_USN].name;
1269 0 : if (rootdse) {
1270 0 : if (last_usn_name) {
1271 0 : ret = sysdb_attrs_get_string(rootdse,
1272 : last_usn_name, &last_usn_value);
1273 0 : if (ret != EOK) {
1274 0 : switch (ret) {
1275 : case ENOENT:
1276 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1277 : "%s configured but not found in rootdse!\n",
1278 : opts->gen_map[SDAP_AT_LAST_USN].opt_name);
1279 0 : break;
1280 : case ERANGE:
1281 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1282 : "Multiple values of %s found in rootdse!\n",
1283 : opts->gen_map[SDAP_AT_LAST_USN].opt_name);
1284 0 : break;
1285 : default:
1286 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1287 : "Unkown error (%d) checking rootdse!\n", ret);
1288 : }
1289 : } else {
1290 0 : if (!entry_usn_name) {
1291 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1292 : "%s found in rootdse but %s is not set!\n",
1293 : last_usn_name,
1294 : opts->gen_map[SDAP_AT_ENTRY_USN].opt_name);
1295 : } else {
1296 0 : so->supports_usn = true;
1297 0 : so->last_usn = strtoul(last_usn_value, &endptr, 10);
1298 0 : if (endptr != NULL && (*endptr != '\0' || endptr == last_usn_value)) {
1299 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1300 : "USN is not valid (value: %s)\n", last_usn_value);
1301 0 : so->last_usn = 0;
1302 : } else {
1303 0 : DEBUG(SSSDBG_TRACE_ALL,
1304 : "USN value: %s (int: %lu)\n", last_usn_value, so->last_usn);
1305 : }
1306 : }
1307 : }
1308 : } else {
1309 : /* no usn option configure, let's try to autodetect. */
1310 0 : for (i = 0; usn_attrs[i].last_name; i++) {
1311 0 : ret = sysdb_attrs_get_string(rootdse,
1312 : usn_attrs[i].last_name,
1313 : &last_usn_value);
1314 0 : if (ret == EOK) {
1315 : /* Fixate discovered configuration */
1316 0 : opts->gen_map[SDAP_AT_LAST_USN].name =
1317 0 : talloc_strdup(opts->gen_map, usn_attrs[i].last_name);
1318 0 : opts->gen_map[SDAP_AT_ENTRY_USN].name =
1319 0 : talloc_strdup(opts->gen_map, usn_attrs[i].entry_name);
1320 0 : so->supports_usn = true;
1321 0 : so->last_usn = strtoul(last_usn_value, &endptr, 10);
1322 0 : if (endptr != NULL && (*endptr != '\0' || endptr == last_usn_value)) {
1323 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1324 : "USN is not valid (value: %s)\n", last_usn_value);
1325 0 : so->last_usn = 0;
1326 : } else {
1327 0 : DEBUG(SSSDBG_TRACE_ALL,
1328 : "USN value: %s (int: %lu)\n", last_usn_value, so->last_usn);
1329 : }
1330 0 : last_usn_name = usn_attrs[i].last_name;
1331 0 : break;
1332 : }
1333 : }
1334 : }
1335 :
1336 : /* Detect Active Directory version if available */
1337 0 : ret = sysdb_attrs_get_uint32_t(rootdse,
1338 : SDAP_ROOTDSE_ATTR_AD_VERSION,
1339 : &dc_level);
1340 0 : if (ret == EOK) {
1341 : /* Validate that the DC level matches an expected value */
1342 0 : switch(dc_level) {
1343 : case DS_BEHAVIOR_WIN2000:
1344 : case DS_BEHAVIOR_WIN2003:
1345 : case DS_BEHAVIOR_WIN2008:
1346 : case DS_BEHAVIOR_WIN2008R2:
1347 : case DS_BEHAVIOR_WIN2012:
1348 : case DS_BEHAVIOR_WIN2012R2:
1349 0 : opts->dc_functional_level = dc_level;
1350 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1351 : "Setting AD compatibility level to [%d]\n",
1352 : opts->dc_functional_level);
1353 0 : break;
1354 : default:
1355 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1356 : "Received invalid value for AD compatibility level. "
1357 : "Using the lowest-common compatibility level\n");
1358 0 : opts->dc_functional_level = DS_BEHAVIOR_WIN2003;
1359 : }
1360 0 : } else if (ret != ENOENT) {
1361 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1362 : "Error detecting Active Directory compatibility level "
1363 : "(%s). Continuing without AD performance enhancements\n",
1364 : strerror(ret));
1365 : }
1366 : }
1367 :
1368 0 : if (!last_usn_name) {
1369 0 : DEBUG(SSSDBG_FUNC_DATA,
1370 : "No known USN scheme is supported by this server!\n");
1371 0 : if (!entry_usn_name) {
1372 0 : DEBUG(SSSDBG_FUNC_DATA,
1373 : "Will use modification timestamp as usn!\n");
1374 0 : opts->gen_map[SDAP_AT_ENTRY_USN].name =
1375 0 : talloc_strdup(opts->gen_map, "modifyTimestamp");
1376 : }
1377 : }
1378 :
1379 0 : if (!opts->user_map[SDAP_AT_USER_USN].name) {
1380 0 : opts->user_map[SDAP_AT_USER_USN].name =
1381 0 : talloc_strdup(opts->user_map,
1382 0 : opts->gen_map[SDAP_AT_ENTRY_USN].name);
1383 : }
1384 0 : if (!opts->group_map[SDAP_AT_GROUP_USN].name) {
1385 0 : opts->group_map[SDAP_AT_GROUP_USN].name =
1386 0 : talloc_strdup(opts->group_map,
1387 0 : opts->gen_map[SDAP_AT_ENTRY_USN].name);
1388 : }
1389 0 : if (!opts->service_map[SDAP_AT_SERVICE_USN].name) {
1390 0 : opts->service_map[SDAP_AT_SERVICE_USN].name =
1391 0 : talloc_strdup(opts->service_map,
1392 0 : opts->gen_map[SDAP_AT_ENTRY_USN].name);
1393 : }
1394 0 : if (opts->sudorule_map &&
1395 0 : !opts->sudorule_map[SDAP_AT_SUDO_USN].name) {
1396 0 : opts->sudorule_map[SDAP_AT_SUDO_USN].name =
1397 0 : talloc_strdup(opts->sudorule_map,
1398 0 : opts->gen_map[SDAP_AT_ENTRY_USN].name);
1399 : }
1400 :
1401 0 : *srv_opts = so;
1402 0 : return EOK;
1403 : }
1404 :
1405 0 : void sdap_steal_server_opts(struct sdap_id_ctx *id_ctx,
1406 : struct sdap_server_opts **srv_opts)
1407 : {
1408 0 : if (!id_ctx || !srv_opts || !*srv_opts) {
1409 0 : return;
1410 : }
1411 :
1412 0 : if (!id_ctx->srv_opts) {
1413 0 : id_ctx->srv_opts = talloc_move(id_ctx, srv_opts);
1414 0 : return;
1415 : }
1416 :
1417 : /* discard if same as previous so we do not reset max usn values
1418 : * unnecessarily */
1419 0 : if (strcmp(id_ctx->srv_opts->server_id, (*srv_opts)->server_id) == 0) {
1420 0 : talloc_zfree(*srv_opts);
1421 0 : return;
1422 : }
1423 :
1424 0 : talloc_zfree(id_ctx->srv_opts);
1425 0 : id_ctx->srv_opts = talloc_move(id_ctx, srv_opts);
1426 : }
1427 :
1428 40 : static bool attr_is_filtered(const char *attr, const char **filter)
1429 : {
1430 : int i;
1431 :
1432 40 : if (filter) {
1433 0 : i = 0;
1434 0 : while (filter[i]) {
1435 0 : if (filter[i] == attr ||
1436 0 : strcasecmp(filter[i], attr) == 0) {
1437 0 : return true;
1438 : }
1439 0 : i++;
1440 : }
1441 : }
1442 :
1443 40 : return false;
1444 : }
1445 :
1446 8 : int build_attrs_from_map(TALLOC_CTX *memctx,
1447 : struct sdap_attr_map *map,
1448 : size_t size,
1449 : const char **filter,
1450 : const char ***_attrs,
1451 : size_t *attr_count)
1452 : {
1453 : errno_t ret;
1454 : const char **attrs;
1455 : int i, j;
1456 8 : TALLOC_CTX *tmp_ctx = talloc_new(NULL);
1457 8 : if (!tmp_ctx) return ENOMEM;
1458 :
1459 : /* Assume that all entries in the map have values */
1460 8 : attrs = talloc_zero_array(tmp_ctx, const char *, size + 1);
1461 8 : if (!attrs) {
1462 0 : ret = ENOMEM;
1463 0 : goto done;
1464 : }
1465 :
1466 : /* first attribute is "objectclass" not the specifc one */
1467 8 : attrs[0] = talloc_strdup(memctx, "objectClass");
1468 8 : if (!attrs[0]) return ENOMEM;
1469 :
1470 : /* add the others */
1471 88 : for (i = j = 1; i < size; i++) {
1472 80 : if (map[i].name && !attr_is_filtered(map[i].name, filter)) {
1473 40 : attrs[j] = map[i].name;
1474 40 : j++;
1475 : }
1476 : }
1477 8 : attrs[j] = NULL;
1478 :
1479 : /* Trim down the used memory if some attributes were NULL */
1480 8 : attrs = talloc_realloc(tmp_ctx, attrs, const char *, j + 1);
1481 8 : if (!attrs) {
1482 0 : ret = ENOMEM;
1483 0 : goto done;
1484 : }
1485 :
1486 8 : *_attrs = talloc_steal(memctx, attrs);
1487 8 : if (attr_count) *attr_count = j;
1488 :
1489 8 : ret = EOK;
1490 :
1491 : done:
1492 8 : talloc_free(tmp_ctx);
1493 8 : return ret;
1494 : }
1495 :
1496 0 : int sdap_control_create(struct sdap_handle *sh, const char *oid, int iscritical,
1497 : struct berval *value, int dupval, LDAPControl **ctrlp)
1498 : {
1499 : int ret;
1500 :
1501 0 : if (sdap_is_control_supported(sh, oid)) {
1502 0 : ret = sss_ldap_control_create(oid, iscritical, value, dupval, ctrlp);
1503 0 : if (ret != LDAP_SUCCESS) {
1504 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1505 : "sss_ldap_control_create failed [%d][%s].\n",
1506 : ret, sss_ldap_err2string(ret));
1507 : }
1508 : } else {
1509 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1510 : "Server does not support the requested control [%s].\n", oid);
1511 0 : ret = LDAP_NOT_SUPPORTED;
1512 : }
1513 :
1514 0 : return ret;
1515 : }
1516 :
1517 0 : int sdap_replace_id(struct sysdb_attrs *entry, const char *attr, id_t val)
1518 : {
1519 : char *str;
1520 : errno_t ret;
1521 : struct ldb_message_element *el;
1522 :
1523 0 : ret = sysdb_attrs_get_el_ext(entry, attr, false, &el);
1524 0 : if (ret == ENOENT) {
1525 0 : return sysdb_attrs_add_uint32(entry, attr, val);
1526 0 : } else if (ret) {
1527 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot get attribute [%s]\n", attr);
1528 0 : return ret;
1529 : }
1530 :
1531 0 : if (el->num_values != 1) {
1532 0 : DEBUG(SSSDBG_OP_FAILURE,
1533 : "Expected 1 value for %s, got %d\n", attr, el->num_values);
1534 0 : return EINVAL;
1535 : }
1536 :
1537 0 : str = talloc_asprintf(entry, "%llu", (unsigned long long) val);
1538 0 : if (!str) {
1539 0 : return ENOMEM;
1540 : }
1541 :
1542 0 : el->values[0].data = (uint8_t *) str;
1543 0 : el->values[0].length = strlen(str);
1544 :
1545 0 : return EOK;
1546 : }
1547 :
1548 : static errno_t
1549 0 : sdap_get_primary_name(TALLOC_CTX *memctx,
1550 : const char *attr_name,
1551 : struct sysdb_attrs *attrs,
1552 : struct sss_domain_info *dom,
1553 : const char **_primary_name)
1554 : {
1555 : errno_t ret;
1556 0 : const char *orig_name = NULL;
1557 : char *name;
1558 :
1559 0 : ret = sysdb_attrs_primary_name(dom->sysdb, attrs, attr_name, &orig_name);
1560 0 : if (ret != EOK) {
1561 0 : DEBUG(SSSDBG_CRIT_FAILURE, "The object has no name attribute\n");
1562 0 : return EINVAL;
1563 : }
1564 :
1565 0 : name = sss_get_domain_name(memctx, orig_name, dom);
1566 0 : if (name == NULL) {
1567 0 : DEBUG(SSSDBG_OP_FAILURE,
1568 : "Failed to format original name [%s]\n", orig_name);
1569 0 : return ENOMEM;
1570 : }
1571 0 : DEBUG(SSSDBG_TRACE_FUNC, "Processing object %s\n", name);
1572 :
1573 0 : *_primary_name = name;
1574 0 : return EOK;
1575 : }
1576 :
1577 0 : errno_t sdap_get_user_primary_name(TALLOC_CTX *memctx,
1578 : struct sdap_options *opts,
1579 : struct sysdb_attrs *attrs,
1580 : struct sss_domain_info *dom,
1581 : const char **_user_name)
1582 : {
1583 0 : return sdap_get_primary_name(memctx,
1584 0 : opts->user_map[SDAP_AT_USER_NAME].name,
1585 : attrs, dom, _user_name);
1586 : }
1587 :
1588 0 : errno_t sdap_get_group_primary_name(TALLOC_CTX *memctx,
1589 : struct sdap_options *opts,
1590 : struct sysdb_attrs *attrs,
1591 : struct sss_domain_info *dom,
1592 : const char **_group_name)
1593 : {
1594 0 : return sdap_get_primary_name(memctx,
1595 0 : opts->group_map[SDAP_AT_GROUP_NAME].name,
1596 : attrs, dom, _group_name);
1597 : }
1598 :
1599 0 : errno_t sdap_get_netgroup_primary_name(TALLOC_CTX *memctx,
1600 : struct sdap_options *opts,
1601 : struct sysdb_attrs *attrs,
1602 : struct sss_domain_info *dom,
1603 : const char **_netgroup_name)
1604 : {
1605 0 : return sdap_get_primary_name(memctx,
1606 0 : opts->netgroup_map[SDAP_AT_NETGROUP_NAME].name,
1607 : attrs, dom, _netgroup_name);
1608 : }
1609 :
1610 8 : char *sdap_make_oc_list(TALLOC_CTX *mem_ctx, struct sdap_attr_map *map)
1611 : {
1612 8 : if (map[SDAP_OC_GROUP_ALT].name == NULL) {
1613 8 : return talloc_asprintf(mem_ctx, "objectClass=%s",
1614 : map[SDAP_OC_GROUP].name);
1615 : } else {
1616 0 : return talloc_asprintf(mem_ctx,
1617 : "|(objectClass=%s)(objectClass=%s)",
1618 : map[SDAP_OC_GROUP].name,
1619 0 : map[SDAP_OC_GROUP_ALT].name);
1620 : }
1621 : }
1622 :
1623 4 : static bool sdap_object_in_domain(struct sdap_options *opts,
1624 : struct sysdb_attrs *obj,
1625 : struct sss_domain_info *dom)
1626 : {
1627 : errno_t ret;
1628 4 : const char *original_dn = NULL;
1629 4 : struct sdap_domain *sdmatch = NULL;
1630 :
1631 4 : ret = sysdb_attrs_get_string(obj, SYSDB_ORIG_DN, &original_dn);
1632 4 : if (ret) {
1633 0 : DEBUG(SSSDBG_FUNC_DATA,
1634 : "The group has no original DN, assuming our domain\n");
1635 0 : return true;
1636 : }
1637 :
1638 4 : sdmatch = sdap_domain_get_by_dn(opts, original_dn);
1639 4 : if (sdmatch == NULL) {
1640 0 : DEBUG(SSSDBG_FUNC_DATA,
1641 : "The group has no original DN, assuming our domain\n");
1642 0 : return true;
1643 : }
1644 :
1645 4 : return (sdmatch->dom == dom);
1646 : }
1647 :
1648 3 : size_t sdap_steal_objects_in_dom(struct sdap_options *opts,
1649 : struct sysdb_attrs **dom_objects,
1650 : size_t offset,
1651 : struct sss_domain_info *dom,
1652 : struct sysdb_attrs **all_objects,
1653 : size_t count,
1654 : bool filter)
1655 : {
1656 3 : size_t copied = 0;
1657 :
1658 : /* Own objects from all_objects by dom_objects in case they belong
1659 : * to domain dom.
1660 : *
1661 : * Don't copy objects from other domains in case
1662 : * the search was for parent domain but a child domain would match,
1663 : * too, such as:
1664 : * dc=example,dc=com
1665 : * dc=child,dc=example,dc=com
1666 : * while searching for an object from dc=example.
1667 : */
1668 9 : for (size_t i = 0; i < count; i++) {
1669 10 : if (filter &&
1670 4 : sdap_object_in_domain(opts, all_objects[i], dom) == false) {
1671 2 : continue;
1672 : }
1673 :
1674 8 : dom_objects[offset + copied] =
1675 4 : talloc_steal(dom_objects, all_objects[i]);
1676 4 : copied++;
1677 : }
1678 :
1679 3 : return copied;
1680 : }
|