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