Line data Source code
1 : /*
2 : Authors:
3 : Simo Sorce <ssorce@redhat.com>
4 :
5 : Copyright (C) 2008-2010 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "providers/ldap/ldap_common.h"
22 : #include "providers/ldap/ldap_opts.h"
23 : #include "providers/ldap/sdap_async_private.h"
24 : #include "util/crypto/sss_crypto.h"
25 :
26 9 : int ldap_get_options(TALLOC_CTX *memctx,
27 : struct sss_domain_info *dom,
28 : struct confdb_ctx *cdb,
29 : const char *conf_path,
30 : struct sdap_options **_opts)
31 : {
32 : struct sdap_attr_map *default_attr_map;
33 : struct sdap_attr_map *default_user_map;
34 : struct sdap_attr_map *default_group_map;
35 : struct sdap_attr_map *default_netgroup_map;
36 : struct sdap_attr_map *default_service_map;
37 : struct sdap_options *opts;
38 : char *schema;
39 : const char *search_base;
40 : const char *pwd_policy;
41 : int ret;
42 : int account_cache_expiration;
43 : int offline_credentials_expiration;
44 : const char *ldap_deref;
45 : int ldap_deref_val;
46 : int o;
47 : const char *authtok_type;
48 : struct dp_opt_blob authtok_blob;
49 : char *cleartext;
50 9 : const int search_base_options[] = { SDAP_USER_SEARCH_BASE,
51 : SDAP_GROUP_SEARCH_BASE,
52 : SDAP_NETGROUP_SEARCH_BASE,
53 : SDAP_SERVICE_SEARCH_BASE,
54 : -1 };
55 :
56 9 : opts = talloc_zero(memctx, struct sdap_options);
57 9 : if (!opts) return ENOMEM;
58 :
59 9 : ret = sdap_domain_add(opts, dom, NULL);
60 9 : if (ret != EOK) {
61 0 : goto done;
62 : }
63 :
64 9 : ret = dp_get_options(opts, cdb, conf_path,
65 : default_basic_opts,
66 : SDAP_OPTS_BASIC,
67 : &opts->basic);
68 9 : if (ret != EOK) {
69 0 : goto done;
70 : }
71 :
72 : /* Handle search bases */
73 9 : search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
74 9 : if (search_base != NULL) {
75 : /* set user/group/netgroup search bases if they are not */
76 45 : for (o = 0; search_base_options[o] != -1; o++) {
77 36 : if (NULL == dp_opt_get_string(opts->basic, search_base_options[o])) {
78 18 : ret = dp_opt_set_string(opts->basic, search_base_options[o],
79 : search_base);
80 18 : if (ret != EOK) {
81 0 : goto done;
82 : }
83 18 : DEBUG(SSSDBG_TRACE_FUNC, "Option %s set to %s\n",
84 : opts->basic[search_base_options[o]].opt_name,
85 : dp_opt_get_string(opts->basic,
86 : search_base_options[o]));
87 : }
88 : }
89 : } else {
90 0 : DEBUG(SSSDBG_FUNC_DATA,
91 : "Search base not set, trying to discover it later when "
92 : "connecting to the LDAP server.\n");
93 : }
94 :
95 : /* Default search */
96 9 : ret = sdap_parse_search_base(opts, opts->basic,
97 : SDAP_SEARCH_BASE,
98 9 : &opts->sdom->search_bases);
99 9 : if (ret != EOK && ret != ENOENT) goto done;
100 :
101 : /* User search */
102 9 : ret = sdap_parse_search_base(opts, opts->basic,
103 : SDAP_USER_SEARCH_BASE,
104 9 : &opts->sdom->user_search_bases);
105 9 : if (ret != EOK && ret != ENOENT) goto done;
106 :
107 : /* Group search base */
108 9 : ret = sdap_parse_search_base(opts, opts->basic,
109 : SDAP_GROUP_SEARCH_BASE,
110 9 : &opts->sdom->group_search_bases);
111 9 : if (ret != EOK && ret != ENOENT) goto done;
112 :
113 : /* Netgroup search */
114 9 : ret = sdap_parse_search_base(opts, opts->basic,
115 : SDAP_NETGROUP_SEARCH_BASE,
116 9 : &opts->sdom->netgroup_search_bases);
117 9 : if (ret != EOK && ret != ENOENT) goto done;
118 :
119 : /* Service search */
120 9 : ret = sdap_parse_search_base(opts, opts->basic,
121 : SDAP_SERVICE_SEARCH_BASE,
122 9 : &opts->sdom->service_search_bases);
123 9 : if (ret != EOK && ret != ENOENT) goto done;
124 :
125 9 : pwd_policy = dp_opt_get_string(opts->basic, SDAP_PWD_POLICY);
126 9 : if (pwd_policy == NULL) {
127 0 : DEBUG(SSSDBG_CRIT_FAILURE,
128 : "Missing password policy, this may not happen.\n");
129 0 : ret = EINVAL;
130 0 : goto done;
131 : }
132 9 : if (strcasecmp(pwd_policy, PWD_POL_OPT_NONE) != 0 &&
133 0 : strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) != 0 &&
134 0 : strcasecmp(pwd_policy, PWD_POL_OPT_MIT) != 0) {
135 0 : DEBUG(SSSDBG_CRIT_FAILURE,
136 : "Unsupported password policy [%s].\n", pwd_policy);
137 0 : ret = EINVAL;
138 0 : goto done;
139 : }
140 :
141 : /* account_cache_expiration must be >= than offline_credentials_expiration */
142 9 : ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
143 : CONFDB_PAM_CRED_TIMEOUT, 0,
144 : &offline_credentials_expiration);
145 9 : if (ret != EOK) {
146 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get value of %s from confdb \n",
147 : CONFDB_PAM_CRED_TIMEOUT);
148 0 : goto done;
149 : }
150 :
151 9 : account_cache_expiration = dp_opt_get_int(opts->basic,
152 : SDAP_ACCOUNT_CACHE_EXPIRATION);
153 :
154 : /* account cache_expiration must not be smaller than
155 : * offline_credentials_expiration to prevent deleting entries that
156 : * still contain credentials valid for offline login.
157 : *
158 : * offline_credentials_expiration == 0 is a special case that says
159 : * that the cached credentials are valid forever. Therefore, the cached
160 : * entries must not be purged from cache.
161 : */
162 9 : if (!offline_credentials_expiration && account_cache_expiration) {
163 0 : DEBUG(SSSDBG_CRIT_FAILURE,
164 : "Conflicting values for options %s (unlimited) "
165 : "and %s (%d)\n",
166 : opts->basic[SDAP_ACCOUNT_CACHE_EXPIRATION].opt_name,
167 : CONFDB_PAM_CRED_TIMEOUT,
168 : offline_credentials_expiration);
169 0 : ret = EINVAL;
170 0 : goto done;
171 : }
172 9 : if (offline_credentials_expiration && account_cache_expiration &&
173 0 : offline_credentials_expiration > account_cache_expiration) {
174 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Value of %s (now %d) must be larger "
175 : "than value of %s (now %d)\n",
176 : opts->basic[SDAP_ACCOUNT_CACHE_EXPIRATION].opt_name,
177 : account_cache_expiration,
178 : CONFDB_PAM_CRED_TIMEOUT,
179 : offline_credentials_expiration);
180 0 : ret = EINVAL;
181 0 : goto done;
182 : }
183 :
184 9 : ldap_deref = dp_opt_get_string(opts->basic, SDAP_DEREF);
185 9 : if (ldap_deref != NULL) {
186 0 : ret = deref_string_to_val(ldap_deref, &ldap_deref_val);
187 0 : if (ret != EOK) {
188 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to verify ldap_deref option.\n");
189 0 : goto done;
190 : }
191 : }
192 :
193 : #ifndef HAVE_LDAP_CONNCB
194 : bool ldap_referrals;
195 :
196 : ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS);
197 : if (ldap_referrals) {
198 : DEBUG(SSSDBG_CRIT_FAILURE,
199 : "LDAP referrals are not supported, because the LDAP library "
200 : "is too old, see sssd-ldap(5) for details.\n");
201 : ret = dp_opt_set_bool(opts->basic, SDAP_REFERRALS, false);
202 : if (ret != EOK) {
203 : DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n");
204 : goto done;
205 : }
206 : }
207 : #endif
208 :
209 : /* schema type */
210 9 : schema = dp_opt_get_string(opts->basic, SDAP_SCHEMA);
211 9 : if (strcasecmp(schema, "rfc2307") == 0) {
212 0 : opts->schema_type = SDAP_SCHEMA_RFC2307;
213 0 : default_attr_map = generic_attr_map;
214 0 : default_user_map = rfc2307_user_map;
215 0 : default_group_map = rfc2307_group_map;
216 0 : default_netgroup_map = netgroup_map;
217 0 : default_service_map = service_map;
218 : } else
219 9 : if (strcasecmp(schema, "rfc2307bis") == 0) {
220 9 : opts->schema_type = SDAP_SCHEMA_RFC2307BIS;
221 9 : default_attr_map = generic_attr_map;
222 9 : default_user_map = rfc2307bis_user_map;
223 9 : default_group_map = rfc2307bis_group_map;
224 9 : default_netgroup_map = netgroup_map;
225 9 : default_service_map = service_map;
226 : } else
227 0 : if (strcasecmp(schema, "IPA") == 0) {
228 0 : opts->schema_type = SDAP_SCHEMA_IPA_V1;
229 0 : default_attr_map = gen_ipa_attr_map;
230 0 : default_user_map = rfc2307bis_user_map;
231 0 : default_group_map = rfc2307bis_group_map;
232 0 : default_netgroup_map = netgroup_map;
233 0 : default_service_map = service_map;
234 : } else
235 0 : if (strcasecmp(schema, "AD") == 0) {
236 0 : opts->schema_type = SDAP_SCHEMA_AD;
237 0 : default_attr_map = gen_ad_attr_map;
238 0 : default_user_map = gen_ad2008r2_user_map;
239 0 : default_group_map = gen_ad2008r2_group_map;
240 0 : default_netgroup_map = netgroup_map;
241 0 : default_service_map = service_map;
242 : } else {
243 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unrecognized schema type: %s\n", schema);
244 0 : ret = EINVAL;
245 0 : goto done;
246 : }
247 :
248 9 : ret = sdap_get_map(opts, cdb, conf_path,
249 : default_attr_map,
250 : SDAP_AT_GENERAL,
251 : &opts->gen_map);
252 9 : if (ret != EOK) {
253 0 : goto done;
254 : }
255 :
256 9 : ret = sdap_get_map(opts, cdb, conf_path,
257 : default_user_map,
258 : SDAP_OPTS_USER,
259 : &opts->user_map);
260 9 : if (ret != EOK) {
261 0 : goto done;
262 : }
263 :
264 9 : ret = sdap_extend_map_with_list(opts, opts, SDAP_USER_EXTRA_ATTRS,
265 : opts->user_map, SDAP_OPTS_USER,
266 : &opts->user_map, &opts->user_map_cnt);
267 9 : if (ret != EOK) {
268 0 : goto done;
269 : }
270 :
271 9 : ret = sdap_get_map(opts, cdb, conf_path,
272 : default_group_map,
273 : SDAP_OPTS_GROUP,
274 : &opts->group_map);
275 9 : if (ret != EOK) {
276 0 : goto done;
277 : }
278 :
279 9 : ret = sdap_get_map(opts, cdb, conf_path,
280 : default_netgroup_map,
281 : SDAP_OPTS_NETGROUP,
282 : &opts->netgroup_map);
283 9 : if (ret != EOK) {
284 0 : goto done;
285 : }
286 :
287 9 : ret = sdap_get_map(opts, cdb, conf_path,
288 : default_service_map,
289 : SDAP_OPTS_SERVICES,
290 : &opts->service_map);
291 9 : if (ret != EOK) {
292 0 : goto done;
293 : }
294 :
295 : /* If there is no KDC, try the deprecated krb5_kdcip option, too */
296 : /* FIXME - this can be removed in a future version */
297 9 : ret = krb5_try_kdcip(cdb, conf_path, opts->basic, SDAP_KRB5_KDC);
298 9 : if (ret != EOK) {
299 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sss_krb5_try_kdcip failed.\n");
300 0 : goto done;
301 : }
302 :
303 9 : authtok_type = dp_opt_get_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE);
304 18 : if (authtok_type != NULL &&
305 9 : strcasecmp(authtok_type,"obfuscated_password") == 0) {
306 0 : DEBUG(SSSDBG_TRACE_ALL, "Found obfuscated password, "
307 : "trying to convert to cleartext.\n");
308 :
309 0 : authtok_blob = dp_opt_get_blob(opts->basic, SDAP_DEFAULT_AUTHTOK);
310 0 : if (authtok_blob.data == NULL || authtok_blob.length == 0) {
311 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing obfuscated password string.\n");
312 0 : ret = EINVAL;
313 0 : goto done;
314 : }
315 :
316 0 : ret = sss_password_decrypt(memctx, (char *) authtok_blob.data,
317 : &cleartext);
318 0 : if (ret != EOK) {
319 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot convert the obfuscated "
320 : "password back to cleartext\n");
321 0 : goto done;
322 : }
323 :
324 0 : authtok_blob.data = (uint8_t *) cleartext;
325 0 : authtok_blob.length = strlen(cleartext);
326 0 : ret = dp_opt_set_blob(opts->basic, SDAP_DEFAULT_AUTHTOK, authtok_blob);
327 0 : talloc_free(cleartext);
328 0 : if (ret != EOK) {
329 0 : DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n");
330 0 : goto done;
331 : }
332 :
333 0 : ret = dp_opt_set_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE,
334 : "password");
335 0 : if (ret != EOK) {
336 0 : DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n");
337 0 : goto done;
338 : }
339 : }
340 :
341 9 : ret = EOK;
342 9 : *_opts = opts;
343 :
344 : done:
345 9 : if (ret != EOK) {
346 0 : talloc_zfree(opts);
347 : }
348 9 : return ret;
349 : }
350 :
351 0 : int ldap_get_sudo_options(struct confdb_ctx *cdb,
352 : const char *conf_path,
353 : struct sdap_options *opts,
354 : bool *use_host_filter,
355 : bool *include_regexp,
356 : bool *include_netgroups)
357 : {
358 : const char *search_base;
359 : int ret;
360 :
361 : /* search base */
362 0 : search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
363 0 : if (search_base != NULL) {
364 : /* set sudo search bases if they are not */
365 0 : if (dp_opt_get_string(opts->basic, SDAP_SUDO_SEARCH_BASE) == NULL) {
366 0 : ret = dp_opt_set_string(opts->basic, SDAP_SUDO_SEARCH_BASE,
367 : search_base);
368 0 : if (ret != EOK) {
369 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not set SUDO search base"
370 : "to default value\n");
371 0 : return ret;
372 : }
373 :
374 0 : DEBUG(SSSDBG_FUNC_DATA, "Option %s set to %s\n",
375 : opts->basic[SDAP_SUDO_SEARCH_BASE].opt_name,
376 : dp_opt_get_string(opts->basic, SDAP_SUDO_SEARCH_BASE));
377 : }
378 : } else {
379 0 : DEBUG(SSSDBG_TRACE_FUNC, "Search base not set, trying to discover it later "
380 : "connecting to the LDAP server.\n");
381 : }
382 :
383 0 : ret = sdap_parse_search_base(opts, opts->basic,
384 : SDAP_SUDO_SEARCH_BASE,
385 0 : &opts->sdom->sudo_search_bases);
386 0 : if (ret != EOK && ret != ENOENT) {
387 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not parse SUDO search base\n");
388 0 : return ret;
389 : }
390 :
391 : /* attrs map */
392 0 : ret = sdap_get_map(opts, cdb, conf_path,
393 : native_sudorule_map,
394 : SDAP_OPTS_SUDO,
395 : &opts->sudorule_map);
396 0 : if (ret != EOK) {
397 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not get SUDO attribute map\n");
398 0 : return ret;
399 : }
400 :
401 : /* host filter */
402 0 : *use_host_filter = dp_opt_get_bool(opts->basic, SDAP_SUDO_USE_HOST_FILTER);
403 0 : *include_netgroups = dp_opt_get_bool(opts->basic, SDAP_SUDO_INCLUDE_NETGROUPS);
404 0 : *include_regexp = dp_opt_get_bool(opts->basic, SDAP_SUDO_INCLUDE_REGEXP);
405 :
406 0 : return EOK;
407 : }
408 :
409 0 : int ldap_get_autofs_options(TALLOC_CTX *memctx,
410 : struct confdb_ctx *cdb,
411 : const char *conf_path,
412 : struct sdap_options *opts)
413 : {
414 : const char *search_base;
415 : struct sdap_attr_map *default_entry_map;
416 : struct sdap_attr_map *default_mobject_map;
417 : int ret;
418 :
419 : /* search base */
420 0 : search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
421 0 : if (search_base != NULL) {
422 : /* set autofs search bases if they are not */
423 0 : if (dp_opt_get_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE) == NULL) {
424 0 : ret = dp_opt_set_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE,
425 : search_base);
426 0 : if (ret != EOK) {
427 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not set autofs search base"
428 : "to default value\n");
429 0 : return ret;
430 : }
431 :
432 0 : DEBUG(SSSDBG_FUNC_DATA, "Option %s set to %s\n",
433 : opts->basic[SDAP_AUTOFS_SEARCH_BASE].opt_name,
434 : dp_opt_get_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE));
435 : }
436 : } else {
437 0 : DEBUG(SSSDBG_TRACE_FUNC, "Search base not set, trying to discover it later "
438 : "connecting to the LDAP server.\n");
439 : }
440 :
441 0 : ret = sdap_parse_search_base(opts, opts->basic,
442 : SDAP_AUTOFS_SEARCH_BASE,
443 0 : &opts->sdom->autofs_search_bases);
444 0 : if (ret != EOK && ret != ENOENT) {
445 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not parse autofs search base\n");
446 0 : return ret;
447 : }
448 :
449 : /* attribute maps */
450 0 : switch (opts->schema_type) {
451 : case SDAP_SCHEMA_RFC2307:
452 0 : default_mobject_map = rfc2307_autofs_mobject_map;
453 0 : default_entry_map = rfc2307_autofs_entry_map;
454 0 : break;
455 : case SDAP_SCHEMA_RFC2307BIS:
456 : case SDAP_SCHEMA_IPA_V1:
457 : case SDAP_SCHEMA_AD:
458 0 : default_mobject_map = rfc2307bis_autofs_mobject_map;
459 0 : default_entry_map = rfc2307bis_autofs_entry_map;
460 0 : break;
461 : default:
462 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown LDAP schema!\n");
463 0 : return EINVAL;
464 : }
465 :
466 0 : ret = sdap_get_map(opts, cdb, conf_path,
467 : default_mobject_map,
468 : SDAP_OPTS_AUTOFS_MAP,
469 : &opts->autofs_mobject_map);
470 0 : if (ret != EOK) {
471 0 : DEBUG(SSSDBG_OP_FAILURE,
472 : "Could not get autofs map object attribute map\n");
473 0 : return ret;
474 : }
475 :
476 0 : ret = sdap_get_map(opts, cdb, conf_path,
477 : default_entry_map,
478 : SDAP_OPTS_AUTOFS_ENTRY,
479 : &opts->autofs_entry_map);
480 0 : if (ret != EOK) {
481 0 : DEBUG(SSSDBG_OP_FAILURE,
482 : "Could not get autofs entry object attribute map\n");
483 0 : return ret;
484 : }
485 :
486 0 : return EOK;
487 : }
488 :
489 45 : errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx,
490 : struct dp_option *opts, int class,
491 : struct sdap_search_base ***_search_bases)
492 : {
493 : const char *class_name;
494 : char *unparsed_base;
495 45 : const char *old_filter = NULL;
496 :
497 45 : *_search_bases = NULL;
498 :
499 45 : switch (class) {
500 : case SDAP_SEARCH_BASE:
501 9 : class_name = "DEFAULT";
502 9 : break;
503 : case SDAP_USER_SEARCH_BASE:
504 9 : class_name = "USER";
505 9 : old_filter = dp_opt_get_string(opts, SDAP_USER_SEARCH_FILTER);
506 9 : break;
507 : case SDAP_GROUP_SEARCH_BASE:
508 9 : class_name = "GROUP";
509 9 : old_filter = dp_opt_get_string(opts, SDAP_GROUP_SEARCH_FILTER);
510 9 : break;
511 : case SDAP_NETGROUP_SEARCH_BASE:
512 9 : class_name = "NETGROUP";
513 9 : break;
514 : case SDAP_SUDO_SEARCH_BASE:
515 0 : class_name = "SUDO";
516 0 : break;
517 : case SDAP_SERVICE_SEARCH_BASE:
518 9 : class_name = "SERVICE";
519 9 : break;
520 : case SDAP_AUTOFS_SEARCH_BASE:
521 0 : class_name = "AUTOFS";
522 0 : break;
523 : default:
524 0 : DEBUG(SSSDBG_CONF_SETTINGS,
525 : "Unknown search base type: [%d]\n", class);
526 0 : class_name = "UNKNOWN";
527 : /* Non-fatal */
528 0 : break;
529 : }
530 :
531 45 : unparsed_base = dp_opt_get_string(opts, class);
532 45 : if (!unparsed_base || unparsed_base[0] == '\0') return ENOENT;
533 :
534 45 : return common_parse_search_base(mem_ctx, unparsed_base,
535 : class_name, old_filter,
536 : _search_bases);
537 : }
538 :
539 45 : errno_t common_parse_search_base(TALLOC_CTX *mem_ctx,
540 : const char *unparsed_base,
541 : const char *class_name,
542 : const char *old_filter,
543 : struct sdap_search_base ***_search_bases)
544 : {
545 : errno_t ret;
546 : struct sdap_search_base **search_bases;
547 : TALLOC_CTX *tmp_ctx;
548 : struct ldb_context *ldb;
549 : struct ldb_dn *ldn;
550 : struct ldb_parse_tree *tree;
551 : char **split_bases;
552 : char *filter;
553 : int count;
554 : int i, c;
555 :
556 45 : tmp_ctx = talloc_new(NULL);
557 45 : if (!tmp_ctx) {
558 0 : ret = ENOMEM;
559 0 : goto done;
560 : }
561 :
562 : /* Create a throwaway LDB context for validating the DN */
563 45 : ldb = ldb_init(tmp_ctx, NULL);
564 45 : if (!ldb) {
565 0 : ret = ENOMEM;
566 0 : goto done;
567 : }
568 :
569 45 : ret = split_on_separator(tmp_ctx, unparsed_base, '?', false, false,
570 : &split_bases, &count);
571 45 : if (ret != EOK) goto done;
572 :
573 : /* The split must be either exactly one value or a multiple of
574 : * three in order to be valid.
575 : * One value: just a base, backwards-compatible with pre-1.7.0 versions
576 : * Multiple: search_base?scope?filter[?search_base?scope?filter]*
577 : */
578 45 : if (count > 1 && (count % 3)) {
579 0 : DEBUG(SSSDBG_CRIT_FAILURE,
580 : "Unparseable search base: [%s][%d]\n", unparsed_base, count);
581 0 : ret = EINVAL;
582 0 : goto done;
583 : }
584 :
585 45 : if (count == 1) {
586 45 : search_bases = talloc_array(tmp_ctx, struct sdap_search_base *, 2);
587 45 : if (!search_bases) {
588 0 : ret = ENOMEM;
589 0 : goto done;
590 : }
591 :
592 45 : if (old_filter != NULL) {
593 : /* Using a deprecated ldap_{user,group}_search_filter */
594 0 : DEBUG(SSSDBG_IMPORTANT_INFO, "WARNING: Using a deprecated filter "
595 : "option for %s. Please see the documentation on LDAP search "
596 : "bases to see how the obsolete option can be migrated\n",
597 : class_name);
598 0 : sss_log(SSS_LOG_NOTICE, "WARNING: Using a deprecated filter option"
599 : "for %s. Please see the documentation on LDAP search bases "
600 : "to see how the obsolete option can be migrated\n",
601 : class_name);
602 : }
603 :
604 45 : ret = sdap_create_search_base(search_bases, unparsed_base,
605 : LDAP_SCOPE_SUBTREE, old_filter,
606 : &search_bases[0]);
607 45 : if (ret != EOK) {
608 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot create new sdap search base\n");
609 0 : goto done;
610 : }
611 :
612 45 : DEBUG(SSSDBG_CONF_SETTINGS,
613 : "Search base added: [%s][%s][%s][%s]\n",
614 : class_name,
615 : search_bases[0]->basedn,
616 : "SUBTREE",
617 : search_bases[0]->filter ? search_bases[0]->filter : "");
618 :
619 45 : search_bases[1] = NULL;
620 : } else {
621 0 : search_bases = talloc_array(tmp_ctx, struct sdap_search_base *,
622 : (count / 3) + 1);
623 0 : if (!search_bases) {
624 0 : ret = ENOMEM;
625 0 : goto done;
626 : }
627 :
628 0 : i = 0;
629 0 : for (c = 0; c < count; c += 3) {
630 0 : search_bases[i] = talloc_zero(search_bases,
631 : struct sdap_search_base);
632 0 : if (!search_bases[i]) {
633 0 : ret = ENOMEM;
634 0 : goto done;
635 : }
636 :
637 0 : if (split_bases[c][0] == '\0') {
638 0 : DEBUG(SSSDBG_CRIT_FAILURE,
639 : "Zero-length search base: [%s]\n", unparsed_base);
640 0 : ret = EINVAL;
641 0 : goto done;
642 : }
643 :
644 : /* Validate the basedn */
645 0 : ldn = ldb_dn_new(tmp_ctx, ldb, split_bases[c]);
646 0 : if (!ldn) {
647 0 : ret = ENOMEM;
648 0 : goto done;
649 : }
650 :
651 0 : if (!ldb_dn_validate(ldn)) {
652 0 : DEBUG(SSSDBG_CRIT_FAILURE,
653 : "Invalid base DN [%s]\n",
654 : split_bases[c]);
655 0 : ret = EINVAL;
656 0 : goto done;
657 : }
658 0 : talloc_zfree(ldn);
659 :
660 : /* Set the search base DN */
661 0 : search_bases[i]->basedn = talloc_strdup(search_bases[i],
662 0 : split_bases[c]);
663 0 : if (!search_bases[i]->basedn) {
664 0 : ret = ENOMEM;
665 0 : goto done;
666 : }
667 :
668 : /* Set the search scope for this base DN */
669 0 : if ((split_bases[c+1][0] == '\0')
670 0 : || strcasecmp(split_bases[c+1], "sub") == 0
671 0 : || strcasecmp(split_bases[c+1], "subtree") == 0) {
672 : /* If unspecified, default to subtree */
673 0 : search_bases[i]->scope = LDAP_SCOPE_SUBTREE;
674 0 : } else if (strcasecmp(split_bases[c+1], "one") == 0
675 0 : || strcasecmp(split_bases[c+1], "onelevel") == 0) {
676 0 : search_bases[i]->scope = LDAP_SCOPE_ONELEVEL;
677 0 : } else if (strcasecmp(split_bases[c+1], "base") == 0) {
678 0 : search_bases[i]->scope = LDAP_SCOPE_BASE;
679 : } else {
680 0 : DEBUG(SSSDBG_CRIT_FAILURE,
681 : "Unknown search scope: [%s]\n", split_bases[c+1]);
682 0 : ret = EINVAL;
683 0 : goto done;
684 : }
685 :
686 : /* Get a specialized filter if provided */
687 0 : if (split_bases[c+2][0] == '\0') {
688 0 : search_bases[i]->filter = NULL;
689 : } else {
690 0 : if (split_bases[c+2][0] != '(') {
691 : /* Filters need to be enclosed in parentheses
692 : * to be validated properly by ldb_parse_tree()
693 : */
694 0 : filter = talloc_asprintf(tmp_ctx, "(%s)",
695 0 : split_bases[c+2]);
696 : } else {
697 0 : filter = talloc_strdup(tmp_ctx, split_bases[c+2]);
698 : }
699 0 : if (!filter) {
700 0 : ret = ENOMEM;
701 0 : goto done;
702 : }
703 :
704 0 : tree = ldb_parse_tree(tmp_ctx, filter);
705 0 : if(!tree) {
706 0 : DEBUG(SSSDBG_CRIT_FAILURE,
707 : "Invalid search filter: [%s]\n", filter);
708 0 : ret = EINVAL;
709 0 : goto done;
710 : }
711 0 : talloc_zfree(tree);
712 :
713 0 : search_bases[i]->filter = talloc_steal(search_bases[i],
714 : filter);
715 : }
716 :
717 0 : DEBUG(SSSDBG_CONF_SETTINGS,
718 : "Search base added: [%s][%s][%s][%s]\n",
719 : class_name,
720 : search_bases[i]->basedn,
721 : split_bases[c+1][0] ? split_bases[c+1] : "SUBTREE",
722 : search_bases[i]->filter ? search_bases[i]->filter : "");
723 :
724 0 : i++;
725 : }
726 0 : search_bases[i] = NULL;
727 : }
728 :
729 45 : *_search_bases = talloc_steal(mem_ctx, search_bases);
730 45 : ret = EOK;
731 :
732 : done:
733 45 : talloc_free(tmp_ctx);
734 45 : return ret;
735 : }
|