From e11fa61e75f6770353a1f575d4131f897a76bccd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 31 Jan 2014 14:10:26 +0100
Subject: [PATCH 04/13] ldap: move options related content from ldap_common.c
 to ldap_options.c

---
 Makefile.am                       |   1 +
 src/providers/ldap/ldap_common.c  | 759 ------------------------------------
 src/providers/ldap/ldap_options.c | 786 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 787 insertions(+), 759 deletions(-)
 create mode 100644 src/providers/ldap/ldap_options.c

diff --git a/Makefile.am b/Makefile.am
index ed568ef8a25c79f69d1e40d1f1cbd910a9036f64..1579fcc1688223561a97452fd3d7238b697dfa4d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1620,6 +1620,7 @@ libsss_ldap_common_la_SOURCES = \
     src/providers/ldap/ldap_id_services.c \
     src/providers/ldap/ldap_auth.c \
     src/providers/ldap/ldap_common.c \
+    src/providers/ldap/ldap_options.c \
     src/providers/ldap/sdap_access.c \
     src/providers/ldap/sdap_async.c \
     src/providers/ldap/sdap_async_users.c \
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 8855d1abaa11dbf06b4b65ec745d1e5bef838d5f..16226a352d52a3ec74479df93c7545b6c2131190 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -33,7 +33,6 @@
 #include "util/sss_krb5.h"
 #include "util/crypto/sss_crypto.h"
 
-#include "providers/ldap/ldap_opts.h"
 #include "providers/ldap/sdap_idmap.h"
 
 /* a fd the child process would log into */
@@ -215,764 +214,6 @@ sdap_domain_remove(struct sdap_options *opts,
     DLIST_REMOVE(*(sdom->head), sdom);
 }
 
-int ldap_get_options(TALLOC_CTX *memctx,
-                     struct sss_domain_info *dom,
-                     struct confdb_ctx *cdb,
-                     const char *conf_path,
-                     struct sdap_options **_opts)
-{
-    struct sdap_attr_map *default_attr_map;
-    struct sdap_attr_map *default_user_map;
-    struct sdap_attr_map *default_group_map;
-    struct sdap_attr_map *default_netgroup_map;
-    struct sdap_attr_map *default_service_map;
-    struct sdap_options *opts;
-    char *schema;
-    const char *search_base;
-    const char *pwd_policy;
-    int ret;
-    int account_cache_expiration;
-    int offline_credentials_expiration;
-    const char *ldap_deref;
-    int ldap_deref_val;
-    int o;
-    const char *authtok_type;
-    struct dp_opt_blob authtok_blob;
-    char *cleartext;
-    const int search_base_options[] = { SDAP_USER_SEARCH_BASE,
-                                        SDAP_GROUP_SEARCH_BASE,
-                                        SDAP_NETGROUP_SEARCH_BASE,
-                                        SDAP_SERVICE_SEARCH_BASE,
-                                        -1 };
-
-    opts = talloc_zero(memctx, struct sdap_options);
-    if (!opts) return ENOMEM;
-
-    ret = sdap_domain_add(opts, dom, NULL);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    ret = dp_get_options(opts, cdb, conf_path,
-                         default_basic_opts,
-                         SDAP_OPTS_BASIC,
-                         &opts->basic);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    /* Handle search bases */
-    search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
-    if (search_base != NULL) {
-        /* set user/group/netgroup search bases if they are not */
-        for (o = 0; search_base_options[o] != -1; o++) {
-            if (NULL == dp_opt_get_string(opts->basic, search_base_options[o])) {
-                ret = dp_opt_set_string(opts->basic, search_base_options[o],
-                                        search_base);
-                if (ret != EOK) {
-                    goto done;
-                }
-                DEBUG(6, ("Option %s set to %s\n",
-                          opts->basic[search_base_options[o]].opt_name,
-                          dp_opt_get_string(opts->basic,
-                                            search_base_options[o])));
-            }
-        }
-    } else {
-        DEBUG(5, ("Search base not set, trying to discover it later when "
-                  "connecting to the LDAP server.\n"));
-    }
-
-    /* Default search */
-    ret = sdap_parse_search_base(opts, opts->basic,
-                                 SDAP_SEARCH_BASE,
-                                 &opts->sdom->search_bases);
-    if (ret != EOK && ret != ENOENT) goto done;
-
-    /* User search */
-    ret = sdap_parse_search_base(opts, opts->basic,
-                                 SDAP_USER_SEARCH_BASE,
-                                 &opts->sdom->user_search_bases);
-    if (ret != EOK && ret != ENOENT) goto done;
-
-    /* Group search base */
-    ret = sdap_parse_search_base(opts, opts->basic,
-                                 SDAP_GROUP_SEARCH_BASE,
-                                 &opts->sdom->group_search_bases);
-    if (ret != EOK && ret != ENOENT) goto done;
-
-    /* Netgroup search */
-    ret = sdap_parse_search_base(opts, opts->basic,
-                                 SDAP_NETGROUP_SEARCH_BASE,
-                                 &opts->sdom->netgroup_search_bases);
-    if (ret != EOK && ret != ENOENT) goto done;
-
-    /* Service search */
-    ret = sdap_parse_search_base(opts, opts->basic,
-                                 SDAP_SERVICE_SEARCH_BASE,
-                                 &opts->sdom->service_search_bases);
-    if (ret != EOK && ret != ENOENT) goto done;
-
-    pwd_policy = dp_opt_get_string(opts->basic, SDAP_PWD_POLICY);
-    if (pwd_policy == NULL) {
-        DEBUG(1, ("Missing password policy, this may not happen.\n"));
-        ret = EINVAL;
-        goto done;
-    }
-    if (strcasecmp(pwd_policy, PWD_POL_OPT_NONE) != 0 &&
-        strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) != 0 &&
-        strcasecmp(pwd_policy, PWD_POL_OPT_MIT) != 0) {
-        DEBUG(1, ("Unsupported password policy [%s].\n", pwd_policy));
-        ret = EINVAL;
-        goto done;
-    }
-
-    /* account_cache_expiration must be >= than offline_credentials_expiration */
-    ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
-                         CONFDB_PAM_CRED_TIMEOUT, 0,
-                         &offline_credentials_expiration);
-    if (ret != EOK) {
-        DEBUG(1, ("Cannot get value of %s from confdb \n",
-                  CONFDB_PAM_CRED_TIMEOUT));
-        goto done;
-    }
-
-    account_cache_expiration = dp_opt_get_int(opts->basic,
-                                              SDAP_ACCOUNT_CACHE_EXPIRATION);
-
-    /* account cache_expiration must not be smaller than
-     * offline_credentials_expiration to prevent deleting entries that
-     * still contain credentials valid for offline login.
-     *
-     * offline_credentials_expiration == 0 is a special case that says
-     * that the cached credentials are valid forever. Therefore, the cached
-     * entries must not be purged from cache.
-     */
-    if (!offline_credentials_expiration && account_cache_expiration) {
-        DEBUG(1, ("Conflicting values for options %s (unlimited) "
-                  "and %s (%d)\n",
-                  opts->basic[SDAP_ACCOUNT_CACHE_EXPIRATION].opt_name,
-                  CONFDB_PAM_CRED_TIMEOUT,
-                  offline_credentials_expiration));
-        ret = EINVAL;
-        goto done;
-    }
-    if (offline_credentials_expiration && account_cache_expiration &&
-        offline_credentials_expiration > account_cache_expiration) {
-        DEBUG(1, ("Value of %s (now %d) must be larger "
-                  "than value of %s (now %d)\n",
-                  opts->basic[SDAP_ACCOUNT_CACHE_EXPIRATION].opt_name,
-                  account_cache_expiration,
-                  CONFDB_PAM_CRED_TIMEOUT,
-                  offline_credentials_expiration));
-        ret = EINVAL;
-        goto done;
-    }
-
-    ldap_deref = dp_opt_get_string(opts->basic, SDAP_DEREF);
-    if (ldap_deref != NULL) {
-        ret = deref_string_to_val(ldap_deref, &ldap_deref_val);
-        if (ret != EOK) {
-            DEBUG(1, ("Failed to verify ldap_deref option.\n"));
-            goto done;
-        }
-    }
-
-#ifndef HAVE_LDAP_CONNCB
-    bool ldap_referrals;
-
-    ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS);
-    if (ldap_referrals) {
-        DEBUG(1, ("LDAP referrals are not supported, because the LDAP library "
-                  "is too old, see sssd-ldap(5) for details.\n"));
-        ret = dp_opt_set_bool(opts->basic, SDAP_REFERRALS, false);
-    }
-#endif
-
-    /* schema type */
-    schema = dp_opt_get_string(opts->basic, SDAP_SCHEMA);
-    if (strcasecmp(schema, "rfc2307") == 0) {
-        opts->schema_type = SDAP_SCHEMA_RFC2307;
-        default_attr_map = generic_attr_map;
-        default_user_map = rfc2307_user_map;
-        default_group_map = rfc2307_group_map;
-        default_netgroup_map = netgroup_map;
-        default_service_map = service_map;
-    } else
-    if (strcasecmp(schema, "rfc2307bis") == 0) {
-        opts->schema_type = SDAP_SCHEMA_RFC2307BIS;
-        default_attr_map = generic_attr_map;
-        default_user_map = rfc2307bis_user_map;
-        default_group_map = rfc2307bis_group_map;
-        default_netgroup_map = netgroup_map;
-        default_service_map = service_map;
-    } else
-    if (strcasecmp(schema, "IPA") == 0) {
-        opts->schema_type = SDAP_SCHEMA_IPA_V1;
-        default_attr_map = gen_ipa_attr_map;
-        default_user_map = rfc2307bis_user_map;
-        default_group_map = rfc2307bis_group_map;
-        default_netgroup_map = netgroup_map;
-        default_service_map = service_map;
-    } else
-    if (strcasecmp(schema, "AD") == 0) {
-        opts->schema_type = SDAP_SCHEMA_AD;
-        default_attr_map = gen_ad_attr_map;
-        default_user_map = gen_ad2008r2_user_map;
-        default_group_map = gen_ad2008r2_group_map;
-        default_netgroup_map = netgroup_map;
-        default_service_map = service_map;
-    } else {
-        DEBUG(0, ("Unrecognized schema type: %s\n", schema));
-        ret = EINVAL;
-        goto done;
-    }
-
-    ret = sdap_get_map(opts, cdb, conf_path,
-                       default_attr_map,
-                       SDAP_AT_GENERAL,
-                       &opts->gen_map);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    ret = sdap_get_map(opts, cdb, conf_path,
-                       default_user_map,
-                       SDAP_OPTS_USER,
-                       &opts->user_map);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    ret = sdap_get_map(opts, cdb, conf_path,
-                       default_group_map,
-                       SDAP_OPTS_GROUP,
-                       &opts->group_map);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    ret = sdap_get_map(opts, cdb, conf_path,
-                       default_netgroup_map,
-                       SDAP_OPTS_NETGROUP,
-                       &opts->netgroup_map);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    ret = sdap_get_map(opts, cdb, conf_path,
-                       default_service_map,
-                       SDAP_OPTS_SERVICES,
-                       &opts->service_map);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    /* If there is no KDC, try the deprecated krb5_kdcip option, too */
-    /* FIXME - this can be removed in a future version */
-    ret = krb5_try_kdcip(cdb, conf_path, opts->basic, SDAP_KRB5_KDC);
-    if (ret != EOK) {
-        DEBUG(1, ("sss_krb5_try_kdcip failed.\n"));
-        goto done;
-    }
-
-    authtok_type = dp_opt_get_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE);
-    if (authtok_type != NULL &&
-        strcasecmp(authtok_type,"obfuscated_password") == 0) {
-        DEBUG(9, ("Found obfuscated password, "
-                  "trying to convert to cleartext.\n"));
-
-        authtok_blob = dp_opt_get_blob(opts->basic, SDAP_DEFAULT_AUTHTOK);
-        if (authtok_blob.data == NULL || authtok_blob.length == 0) {
-            DEBUG(1, ("Missing obfuscated password string.\n"));
-            return EINVAL;
-        }
-
-        ret = sss_password_decrypt(memctx, (char *) authtok_blob.data,
-                                   &cleartext);
-        if (ret != EOK) {
-            DEBUG(1, ("Cannot convert the obfuscated "
-                      "password back to cleartext\n"));
-            return ret;
-        }
-
-        authtok_blob.data = (uint8_t *) cleartext;
-        authtok_blob.length = strlen(cleartext);
-        ret = dp_opt_set_blob(opts->basic, SDAP_DEFAULT_AUTHTOK, authtok_blob);
-        talloc_free(cleartext);
-        if (ret != EOK) {
-            DEBUG(1, ("dp_opt_set_string failed.\n"));
-            return ret;
-        }
-
-        ret = dp_opt_set_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE,
-                                "password");
-        if (ret != EOK) {
-            DEBUG(1, ("dp_opt_set_string failed.\n"));
-            return ret;
-        }
-    }
-
-    ret = EOK;
-    *_opts = opts;
-
-done:
-    if (ret != EOK) {
-        talloc_zfree(opts);
-    }
-    return ret;
-}
-
-int ldap_get_sudo_options(TALLOC_CTX *memctx,
-                          struct confdb_ctx *cdb,
-                          const char *conf_path,
-                          struct sdap_options *opts,
-                          bool *use_host_filter,
-                          bool *include_regexp,
-                          bool *include_netgroups)
-{
-    const char *search_base;
-    int ret;
-
-    /* search base */
-    search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
-    if (search_base != NULL) {
-        /* set sudo search bases if they are not */
-        if (dp_opt_get_string(opts->basic, SDAP_SUDO_SEARCH_BASE) == NULL) {
-            ret = dp_opt_set_string(opts->basic, SDAP_SUDO_SEARCH_BASE,
-                                    search_base);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_OP_FAILURE, ("Could not set SUDO search base"
-                      "to default value\n"));
-                return ret;
-            }
-
-            DEBUG(SSSDBG_FUNC_DATA, ("Option %s set to %s\n",
-                  opts->basic[SDAP_SUDO_SEARCH_BASE].opt_name,
-                  dp_opt_get_string(opts->basic, SDAP_SUDO_SEARCH_BASE)));
-        }
-    } else {
-        DEBUG(SSSDBG_TRACE_FUNC, ("Search base not set, trying to discover it later "
-              "connecting to the LDAP server.\n"));
-    }
-
-    ret = sdap_parse_search_base(opts, opts->basic,
-                                 SDAP_SUDO_SEARCH_BASE,
-                                 &opts->sdom->sudo_search_bases);
-    if (ret != EOK && ret != ENOENT) {
-        DEBUG(SSSDBG_OP_FAILURE, ("Could not parse SUDO search base\n"));
-        return ret;
-    }
-
-    /* attrs map */
-    ret = sdap_get_map(opts, cdb, conf_path,
-                       native_sudorule_map,
-                       SDAP_OPTS_SUDO,
-                       &opts->sudorule_map);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, ("Could not get SUDO attribute map\n"));
-        return ret;
-    }
-
-    /* host filter */
-    *use_host_filter = dp_opt_get_bool(opts->basic, SDAP_SUDO_USE_HOST_FILTER);
-    *include_netgroups = dp_opt_get_bool(opts->basic, SDAP_SUDO_INCLUDE_NETGROUPS);
-    *include_regexp = dp_opt_get_bool(opts->basic, SDAP_SUDO_INCLUDE_REGEXP);
-
-    return EOK;
-}
-
-int ldap_get_autofs_options(TALLOC_CTX *memctx,
-                            struct confdb_ctx *cdb,
-                            const char *conf_path,
-                            struct sdap_options *opts)
-{
-    const char *search_base;
-    struct sdap_attr_map *default_entry_map;
-    struct sdap_attr_map *default_mobject_map;
-    int ret;
-
-    /* search base */
-    search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
-    if (search_base != NULL) {
-        /* set autofs search bases if they are not */
-        if (dp_opt_get_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE) == NULL) {
-            ret = dp_opt_set_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE,
-                                    search_base);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_OP_FAILURE, ("Could not set autofs search base"
-                      "to default value\n"));
-                return ret;
-            }
-
-            DEBUG(SSSDBG_FUNC_DATA, ("Option %s set to %s\n",
-                  opts->basic[SDAP_AUTOFS_SEARCH_BASE].opt_name,
-                  dp_opt_get_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE)));
-        }
-    } else {
-        DEBUG(SSSDBG_TRACE_FUNC, ("Search base not set, trying to discover it later "
-              "connecting to the LDAP server.\n"));
-    }
-
-    ret = sdap_parse_search_base(opts, opts->basic,
-                                 SDAP_AUTOFS_SEARCH_BASE,
-                                 &opts->sdom->autofs_search_bases);
-    if (ret != EOK && ret != ENOENT) {
-        DEBUG(SSSDBG_OP_FAILURE, ("Could not parse autofs search base\n"));
-        return ret;
-    }
-
-    /* attribute maps */
-    switch (opts->schema_type) {
-        case SDAP_SCHEMA_RFC2307:
-            default_mobject_map = rfc2307_autofs_mobject_map;
-            default_entry_map = rfc2307_autofs_entry_map;
-            break;
-        case SDAP_SCHEMA_RFC2307BIS:
-        case SDAP_SCHEMA_IPA_V1:
-        case SDAP_SCHEMA_AD:
-            default_mobject_map = rfc2307bis_autofs_mobject_map;
-            default_entry_map = rfc2307bis_autofs_entry_map;
-            break;
-        default:
-            DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown LDAP schema!\n"));
-            return EINVAL;
-    }
-
-    ret = sdap_get_map(opts, cdb, conf_path,
-                       default_mobject_map,
-                       SDAP_OPTS_AUTOFS_MAP,
-                       &opts->autofs_mobject_map);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              ("Could not get autofs map object attribute map\n"));
-        return ret;
-    }
-
-    ret = sdap_get_map(opts, cdb, conf_path,
-                       default_entry_map,
-                       SDAP_OPTS_AUTOFS_ENTRY,
-                       &opts->autofs_entry_map);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              ("Could not get autofs entry object attribute map\n"));
-        return ret;
-    }
-
-    return EOK;
-}
-
-errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx,
-                               struct dp_option *opts, int class,
-                               struct sdap_search_base ***_search_bases)
-{
-    const char *class_name;
-    char *unparsed_base;
-    const char *old_filter = NULL;
-
-    *_search_bases = NULL;
-
-    switch (class) {
-    case SDAP_SEARCH_BASE:
-        class_name = "DEFAULT";
-        break;
-    case SDAP_USER_SEARCH_BASE:
-        class_name = "USER";
-        old_filter = dp_opt_get_string(opts, SDAP_USER_SEARCH_FILTER);
-        break;
-    case SDAP_GROUP_SEARCH_BASE:
-        class_name = "GROUP";
-        old_filter = dp_opt_get_string(opts, SDAP_GROUP_SEARCH_FILTER);
-        break;
-    case SDAP_NETGROUP_SEARCH_BASE:
-        class_name = "NETGROUP";
-        break;
-    case SDAP_SUDO_SEARCH_BASE:
-        class_name = "SUDO";
-        break;
-    case SDAP_SERVICE_SEARCH_BASE:
-        class_name = "SERVICE";
-        break;
-    case SDAP_AUTOFS_SEARCH_BASE:
-        class_name = "AUTOFS";
-        break;
-    default:
-        DEBUG(SSSDBG_CONF_SETTINGS,
-              ("Unknown search base type: [%d]\n", class));
-        class_name = "UNKNOWN";
-        /* Non-fatal */
-        break;
-    }
-
-    unparsed_base = dp_opt_get_string(opts, class);
-    if (!unparsed_base || unparsed_base[0] == '\0') return ENOENT;
-
-    return common_parse_search_base(mem_ctx, unparsed_base,
-                                    class_name, old_filter,
-                                    _search_bases);
-}
-
-errno_t
-sdap_create_search_base(TALLOC_CTX *mem_ctx,
-                        const char *unparsed_base,
-                        int scope,
-                        const char *filter,
-                        struct sdap_search_base **_base)
-{
-    struct sdap_search_base *base;
-    TALLOC_CTX *tmp_ctx;
-    errno_t ret;
-    struct ldb_dn *ldn;
-    struct ldb_context *ldb;
-
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    /* Create a throwaway LDB context for validating the DN */
-    ldb = ldb_init(tmp_ctx, NULL);
-    if (!ldb) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    base = talloc_zero(tmp_ctx, struct sdap_search_base);
-    if (base == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    base->basedn = talloc_strdup(base, unparsed_base);
-    if (base->basedn == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    /* Validate the basedn */
-    ldn = ldb_dn_new(tmp_ctx, ldb, unparsed_base);
-    if (!ldn) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    if (!ldb_dn_validate(ldn)) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-                ("Invalid base DN [%s]\n",
-                 unparsed_base));
-        ret = EINVAL;
-        goto done;
-    }
-
-    base->scope = scope;
-    base->filter = filter;
-
-    *_base = talloc_steal(mem_ctx, base);
-    ret = EOK;
-done:
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-errno_t common_parse_search_base(TALLOC_CTX *mem_ctx,
-                                 const char *unparsed_base,
-                                 const char *class_name,
-                                 const char *old_filter,
-                                 struct sdap_search_base ***_search_bases)
-{
-    errno_t ret;
-    struct sdap_search_base **search_bases;
-    TALLOC_CTX *tmp_ctx;
-    struct ldb_context *ldb;
-    struct ldb_dn *ldn;
-    struct ldb_parse_tree *tree;
-    char **split_bases;
-    char *filter;
-    int count;
-    int i, c;
-
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    /* Create a throwaway LDB context for validating the DN */
-    ldb = ldb_init(tmp_ctx, NULL);
-    if (!ldb) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    ret = split_on_separator(tmp_ctx, unparsed_base, '?', false, false,
-                             &split_bases, &count);
-    if (ret != EOK) goto done;
-
-    /* The split must be either exactly one value or a multiple of
-     * three in order to be valid.
-     * One value: just a base, backwards-compatible with pre-1.7.0 versions
-     * Multiple: search_base?scope?filter[?search_base?scope?filter]*
-     */
-    if (count > 1 && (count % 3)) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              ("Unparseable search base: [%s][%d]\n", unparsed_base, count));
-        ret = EINVAL;
-        goto done;
-    }
-
-    if (count == 1) {
-        search_bases = talloc_array(tmp_ctx, struct sdap_search_base *, 2);
-        if (!search_bases) {
-            ret = ENOMEM;
-            goto done;
-        }
-
-        if (old_filter != NULL) {
-            /* Using a deprecated ldap_{user,group}_search_filter */
-            DEBUG(SSSDBG_IMPORTANT_INFO, ("WARNING: Using a deprecated filter "
-                  "option for %s. Please see the documentation on LDAP search "
-                  "bases to see how the obsolete option can be migrated\n",
-                  class_name));
-            sss_log(SSS_LOG_NOTICE, "WARNING: Using a deprecated filter option"
-                    "for %s. Please see the documentation on LDAP search bases "
-                    "to see how the obsolete option can be migrated\n",
-                    class_name);
-        }
-
-        ret = sdap_create_search_base(search_bases, unparsed_base,
-                                      LDAP_SCOPE_SUBTREE, old_filter,
-                                      &search_bases[0]);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_OP_FAILURE, ("Cannot create new sdap search base\n"));
-            goto done;
-        }
-
-        DEBUG(SSSDBG_CONF_SETTINGS,
-              ("Search base added: [%s][%s][%s][%s]\n",
-               class_name,
-               search_bases[0]->basedn,
-               "SUBTREE",
-               search_bases[0]->filter ? search_bases[0]->filter : ""));
-
-        search_bases[1] = NULL;
-    } else {
-        search_bases = talloc_array(tmp_ctx, struct sdap_search_base *,
-                                    (count / 3) + 1);
-        if (!search_bases) {
-            ret = ENOMEM;
-            goto done;
-        }
-
-        i = 0;
-        for (c = 0; c < count; c += 3) {
-            search_bases[i] = talloc_zero(search_bases,
-                                          struct sdap_search_base);
-            if (!search_bases[i]) {
-                ret = ENOMEM;
-                goto done;
-            }
-
-            if (split_bases[c][0] == '\0') {
-                DEBUG(SSSDBG_CRIT_FAILURE,
-                      ("Zero-length search base: [%s]\n", unparsed_base));
-                ret = EINVAL;
-                goto done;
-            }
-
-            /* Validate the basedn */
-            ldn = ldb_dn_new(tmp_ctx, ldb, split_bases[c]);
-            if (!ldn) {
-                ret = ENOMEM;
-                goto done;
-            }
-
-            if (!ldb_dn_validate(ldn)) {
-                DEBUG(SSSDBG_CRIT_FAILURE,
-                      ("Invalid base DN [%s]\n",
-                       split_bases[c]));
-                ret = EINVAL;
-                goto done;
-            }
-            talloc_zfree(ldn);
-
-            /* Set the search base DN */
-            search_bases[i]->basedn = talloc_strdup(search_bases[i],
-                                                    split_bases[c]);
-            if (!search_bases[i]->basedn) {
-                ret = ENOMEM;
-                goto done;
-            }
-
-            /* Set the search scope for this base DN */
-            if ((split_bases[c+1][0] == '\0')
-                    || strcasecmp(split_bases[c+1], "sub") == 0
-                    || strcasecmp(split_bases[c+1], "subtree") == 0) {
-                /* If unspecified, default to subtree */
-                search_bases[i]->scope = LDAP_SCOPE_SUBTREE;
-            } else if (strcasecmp(split_bases[c+1], "one") == 0
-                    || strcasecmp(split_bases[c+1], "onelevel") == 0) {
-                search_bases[i]->scope = LDAP_SCOPE_ONELEVEL;
-            } else if (strcasecmp(split_bases[c+1], "base") == 0) {
-                search_bases[i]->scope = LDAP_SCOPE_BASE;
-            } else {
-                DEBUG(SSSDBG_CRIT_FAILURE,
-                      ("Unknown search scope: [%s]\n", split_bases[c+1]));
-                ret = EINVAL;
-                goto done;
-            }
-
-            /* Get a specialized filter if provided */
-            if (split_bases[c+2][0] == '\0') {
-                search_bases[i]->filter = NULL;
-            } else {
-                if (split_bases[c+2][0] != '(') {
-                    /* Filters need to be enclosed in parentheses
-                     * to be validated properly by ldb_parse_tree()
-                     */
-                    filter = talloc_asprintf(tmp_ctx, "(%s)",
-                                             split_bases[c+2]);
-                } else {
-                    filter = talloc_strdup(tmp_ctx, split_bases[c+2]);
-                }
-                if (!filter) {
-                    ret = ENOMEM;
-                    goto done;
-                }
-
-                tree = ldb_parse_tree(tmp_ctx, filter);
-                if(!tree) {
-                    DEBUG(SSSDBG_CRIT_FAILURE,
-                          ("Invalid search filter: [%s]\n", filter));
-                    ret = EINVAL;
-                    goto done;
-                }
-                talloc_zfree(tree);
-
-                search_bases[i]->filter = talloc_steal(search_bases[i],
-                                                       filter);
-            }
-
-            DEBUG(SSSDBG_CONF_SETTINGS,
-                  ("Search base added: [%s][%s][%s][%s]\n",
-                   class_name,
-                   search_bases[i]->basedn,
-                   split_bases[c+1][0] ? split_bases[c+1] : "SUBTREE",
-                   search_bases[i]->filter ? search_bases[i]->filter : ""));
-
-            i++;
-        }
-        search_bases[i] = NULL;
-    }
-
-    *_search_bases = talloc_steal(mem_ctx, search_bases);
-    ret = EOK;
-
-done:
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
 void sdap_handler_done(struct be_req *req, int dp_err,
                        int error, const char *errstr)
 {
diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c
new file mode 100644
index 0000000000000000000000000000000000000000..69780d46273856c4129130dee22d346eccde567d
--- /dev/null
+++ b/src/providers/ldap/ldap_options.c
@@ -0,0 +1,786 @@
+/*
+    SSSD
+
+    LDAP Provider Common Functions
+
+    Authors:
+        Simo Sorce <ssorce@redhat.com>
+
+    Copyright (C) 2008-2010 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "providers/ldap/ldap_common.h"
+#include "providers/ldap/ldap_opts.h"
+#include "providers/ldap/sdap_async_private.h"
+#include "util/crypto/sss_crypto.h"
+
+int ldap_get_options(TALLOC_CTX *memctx,
+                     struct sss_domain_info *dom,
+                     struct confdb_ctx *cdb,
+                     const char *conf_path,
+                     struct sdap_options **_opts)
+{
+    struct sdap_attr_map *default_attr_map;
+    struct sdap_attr_map *default_user_map;
+    struct sdap_attr_map *default_group_map;
+    struct sdap_attr_map *default_netgroup_map;
+    struct sdap_attr_map *default_service_map;
+    struct sdap_options *opts;
+    char *schema;
+    const char *search_base;
+    const char *pwd_policy;
+    int ret;
+    int account_cache_expiration;
+    int offline_credentials_expiration;
+    const char *ldap_deref;
+    int ldap_deref_val;
+    int o;
+    const char *authtok_type;
+    struct dp_opt_blob authtok_blob;
+    char *cleartext;
+    const int search_base_options[] = { SDAP_USER_SEARCH_BASE,
+                                        SDAP_GROUP_SEARCH_BASE,
+                                        SDAP_NETGROUP_SEARCH_BASE,
+                                        SDAP_SERVICE_SEARCH_BASE,
+                                        -1 };
+
+    opts = talloc_zero(memctx, struct sdap_options);
+    if (!opts) return ENOMEM;
+
+    ret = sdap_domain_add(opts, dom, NULL);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = dp_get_options(opts, cdb, conf_path,
+                         default_basic_opts,
+                         SDAP_OPTS_BASIC,
+                         &opts->basic);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* Handle search bases */
+    search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
+    if (search_base != NULL) {
+        /* set user/group/netgroup search bases if they are not */
+        for (o = 0; search_base_options[o] != -1; o++) {
+            if (NULL == dp_opt_get_string(opts->basic, search_base_options[o])) {
+                ret = dp_opt_set_string(opts->basic, search_base_options[o],
+                                        search_base);
+                if (ret != EOK) {
+                    goto done;
+                }
+                DEBUG(6, ("Option %s set to %s\n",
+                          opts->basic[search_base_options[o]].opt_name,
+                          dp_opt_get_string(opts->basic,
+                                            search_base_options[o])));
+            }
+        }
+    } else {
+        DEBUG(5, ("Search base not set, trying to discover it later when "
+                  "connecting to the LDAP server.\n"));
+    }
+
+    /* Default search */
+    ret = sdap_parse_search_base(opts, opts->basic,
+                                 SDAP_SEARCH_BASE,
+                                 &opts->sdom->search_bases);
+    if (ret != EOK && ret != ENOENT) goto done;
+
+    /* User search */
+    ret = sdap_parse_search_base(opts, opts->basic,
+                                 SDAP_USER_SEARCH_BASE,
+                                 &opts->sdom->user_search_bases);
+    if (ret != EOK && ret != ENOENT) goto done;
+
+    /* Group search base */
+    ret = sdap_parse_search_base(opts, opts->basic,
+                                 SDAP_GROUP_SEARCH_BASE,
+                                 &opts->sdom->group_search_bases);
+    if (ret != EOK && ret != ENOENT) goto done;
+
+    /* Netgroup search */
+    ret = sdap_parse_search_base(opts, opts->basic,
+                                 SDAP_NETGROUP_SEARCH_BASE,
+                                 &opts->sdom->netgroup_search_bases);
+    if (ret != EOK && ret != ENOENT) goto done;
+
+    /* Service search */
+    ret = sdap_parse_search_base(opts, opts->basic,
+                                 SDAP_SERVICE_SEARCH_BASE,
+                                 &opts->sdom->service_search_bases);
+    if (ret != EOK && ret != ENOENT) goto done;
+
+    pwd_policy = dp_opt_get_string(opts->basic, SDAP_PWD_POLICY);
+    if (pwd_policy == NULL) {
+        DEBUG(1, ("Missing password policy, this may not happen.\n"));
+        ret = EINVAL;
+        goto done;
+    }
+    if (strcasecmp(pwd_policy, PWD_POL_OPT_NONE) != 0 &&
+        strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) != 0 &&
+        strcasecmp(pwd_policy, PWD_POL_OPT_MIT) != 0) {
+        DEBUG(1, ("Unsupported password policy [%s].\n", pwd_policy));
+        ret = EINVAL;
+        goto done;
+    }
+
+    /* account_cache_expiration must be >= than offline_credentials_expiration */
+    ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
+                         CONFDB_PAM_CRED_TIMEOUT, 0,
+                         &offline_credentials_expiration);
+    if (ret != EOK) {
+        DEBUG(1, ("Cannot get value of %s from confdb \n",
+                  CONFDB_PAM_CRED_TIMEOUT));
+        goto done;
+    }
+
+    account_cache_expiration = dp_opt_get_int(opts->basic,
+                                              SDAP_ACCOUNT_CACHE_EXPIRATION);
+
+    /* account cache_expiration must not be smaller than
+     * offline_credentials_expiration to prevent deleting entries that
+     * still contain credentials valid for offline login.
+     *
+     * offline_credentials_expiration == 0 is a special case that says
+     * that the cached credentials are valid forever. Therefore, the cached
+     * entries must not be purged from cache.
+     */
+    if (!offline_credentials_expiration && account_cache_expiration) {
+        DEBUG(1, ("Conflicting values for options %s (unlimited) "
+                  "and %s (%d)\n",
+                  opts->basic[SDAP_ACCOUNT_CACHE_EXPIRATION].opt_name,
+                  CONFDB_PAM_CRED_TIMEOUT,
+                  offline_credentials_expiration));
+        ret = EINVAL;
+        goto done;
+    }
+    if (offline_credentials_expiration && account_cache_expiration &&
+        offline_credentials_expiration > account_cache_expiration) {
+        DEBUG(1, ("Value of %s (now %d) must be larger "
+                  "than value of %s (now %d)\n",
+                  opts->basic[SDAP_ACCOUNT_CACHE_EXPIRATION].opt_name,
+                  account_cache_expiration,
+                  CONFDB_PAM_CRED_TIMEOUT,
+                  offline_credentials_expiration));
+        ret = EINVAL;
+        goto done;
+    }
+
+    ldap_deref = dp_opt_get_string(opts->basic, SDAP_DEREF);
+    if (ldap_deref != NULL) {
+        ret = deref_string_to_val(ldap_deref, &ldap_deref_val);
+        if (ret != EOK) {
+            DEBUG(1, ("Failed to verify ldap_deref option.\n"));
+            goto done;
+        }
+    }
+
+#ifndef HAVE_LDAP_CONNCB
+    bool ldap_referrals;
+
+    ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS);
+    if (ldap_referrals) {
+        DEBUG(1, ("LDAP referrals are not supported, because the LDAP library "
+                  "is too old, see sssd-ldap(5) for details.\n"));
+        ret = dp_opt_set_bool(opts->basic, SDAP_REFERRALS, false);
+    }
+#endif
+
+    /* schema type */
+    schema = dp_opt_get_string(opts->basic, SDAP_SCHEMA);
+    if (strcasecmp(schema, "rfc2307") == 0) {
+        opts->schema_type = SDAP_SCHEMA_RFC2307;
+        default_attr_map = generic_attr_map;
+        default_user_map = rfc2307_user_map;
+        default_group_map = rfc2307_group_map;
+        default_netgroup_map = netgroup_map;
+        default_service_map = service_map;
+    } else
+    if (strcasecmp(schema, "rfc2307bis") == 0) {
+        opts->schema_type = SDAP_SCHEMA_RFC2307BIS;
+        default_attr_map = generic_attr_map;
+        default_user_map = rfc2307bis_user_map;
+        default_group_map = rfc2307bis_group_map;
+        default_netgroup_map = netgroup_map;
+        default_service_map = service_map;
+    } else
+    if (strcasecmp(schema, "IPA") == 0) {
+        opts->schema_type = SDAP_SCHEMA_IPA_V1;
+        default_attr_map = gen_ipa_attr_map;
+        default_user_map = rfc2307bis_user_map;
+        default_group_map = rfc2307bis_group_map;
+        default_netgroup_map = netgroup_map;
+        default_service_map = service_map;
+    } else
+    if (strcasecmp(schema, "AD") == 0) {
+        opts->schema_type = SDAP_SCHEMA_AD;
+        default_attr_map = gen_ad_attr_map;
+        default_user_map = gen_ad2008r2_user_map;
+        default_group_map = gen_ad2008r2_group_map;
+        default_netgroup_map = netgroup_map;
+        default_service_map = service_map;
+    } else {
+        DEBUG(0, ("Unrecognized schema type: %s\n", schema));
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = sdap_get_map(opts, cdb, conf_path,
+                       default_attr_map,
+                       SDAP_AT_GENERAL,
+                       &opts->gen_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sdap_get_map(opts, cdb, conf_path,
+                       default_user_map,
+                       SDAP_OPTS_USER,
+                       &opts->user_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sdap_get_map(opts, cdb, conf_path,
+                       default_group_map,
+                       SDAP_OPTS_GROUP,
+                       &opts->group_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sdap_get_map(opts, cdb, conf_path,
+                       default_netgroup_map,
+                       SDAP_OPTS_NETGROUP,
+                       &opts->netgroup_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sdap_get_map(opts, cdb, conf_path,
+                       default_service_map,
+                       SDAP_OPTS_SERVICES,
+                       &opts->service_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* If there is no KDC, try the deprecated krb5_kdcip option, too */
+    /* FIXME - this can be removed in a future version */
+    ret = krb5_try_kdcip(cdb, conf_path, opts->basic, SDAP_KRB5_KDC);
+    if (ret != EOK) {
+        DEBUG(1, ("sss_krb5_try_kdcip failed.\n"));
+        goto done;
+    }
+
+    authtok_type = dp_opt_get_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE);
+    if (authtok_type != NULL &&
+        strcasecmp(authtok_type,"obfuscated_password") == 0) {
+        DEBUG(9, ("Found obfuscated password, "
+                  "trying to convert to cleartext.\n"));
+
+        authtok_blob = dp_opt_get_blob(opts->basic, SDAP_DEFAULT_AUTHTOK);
+        if (authtok_blob.data == NULL || authtok_blob.length == 0) {
+            DEBUG(1, ("Missing obfuscated password string.\n"));
+            return EINVAL;
+        }
+
+        ret = sss_password_decrypt(memctx, (char *) authtok_blob.data,
+                                   &cleartext);
+        if (ret != EOK) {
+            DEBUG(1, ("Cannot convert the obfuscated "
+                      "password back to cleartext\n"));
+            return ret;
+        }
+
+        authtok_blob.data = (uint8_t *) cleartext;
+        authtok_blob.length = strlen(cleartext);
+        ret = dp_opt_set_blob(opts->basic, SDAP_DEFAULT_AUTHTOK, authtok_blob);
+        talloc_free(cleartext);
+        if (ret != EOK) {
+            DEBUG(1, ("dp_opt_set_string failed.\n"));
+            return ret;
+        }
+
+        ret = dp_opt_set_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE,
+                                "password");
+        if (ret != EOK) {
+            DEBUG(1, ("dp_opt_set_string failed.\n"));
+            return ret;
+        }
+    }
+
+    ret = EOK;
+    *_opts = opts;
+
+done:
+    if (ret != EOK) {
+        talloc_zfree(opts);
+    }
+    return ret;
+}
+
+int ldap_get_sudo_options(TALLOC_CTX *memctx,
+                          struct confdb_ctx *cdb,
+                          const char *conf_path,
+                          struct sdap_options *opts,
+                          bool *use_host_filter,
+                          bool *include_regexp,
+                          bool *include_netgroups)
+{
+    const char *search_base;
+    int ret;
+
+    /* search base */
+    search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
+    if (search_base != NULL) {
+        /* set sudo search bases if they are not */
+        if (dp_opt_get_string(opts->basic, SDAP_SUDO_SEARCH_BASE) == NULL) {
+            ret = dp_opt_set_string(opts->basic, SDAP_SUDO_SEARCH_BASE,
+                                    search_base);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, ("Could not set SUDO search base"
+                      "to default value\n"));
+                return ret;
+            }
+
+            DEBUG(SSSDBG_FUNC_DATA, ("Option %s set to %s\n",
+                  opts->basic[SDAP_SUDO_SEARCH_BASE].opt_name,
+                  dp_opt_get_string(opts->basic, SDAP_SUDO_SEARCH_BASE)));
+        }
+    } else {
+        DEBUG(SSSDBG_TRACE_FUNC, ("Search base not set, trying to discover it later "
+              "connecting to the LDAP server.\n"));
+    }
+
+    ret = sdap_parse_search_base(opts, opts->basic,
+                                 SDAP_SUDO_SEARCH_BASE,
+                                 &opts->sdom->sudo_search_bases);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not parse SUDO search base\n"));
+        return ret;
+    }
+
+    /* attrs map */
+    ret = sdap_get_map(opts, cdb, conf_path,
+                       native_sudorule_map,
+                       SDAP_OPTS_SUDO,
+                       &opts->sudorule_map);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not get SUDO attribute map\n"));
+        return ret;
+    }
+
+    /* host filter */
+    *use_host_filter = dp_opt_get_bool(opts->basic, SDAP_SUDO_USE_HOST_FILTER);
+    *include_netgroups = dp_opt_get_bool(opts->basic, SDAP_SUDO_INCLUDE_NETGROUPS);
+    *include_regexp = dp_opt_get_bool(opts->basic, SDAP_SUDO_INCLUDE_REGEXP);
+
+    return EOK;
+}
+
+int ldap_get_autofs_options(TALLOC_CTX *memctx,
+                            struct confdb_ctx *cdb,
+                            const char *conf_path,
+                            struct sdap_options *opts)
+{
+    const char *search_base;
+    struct sdap_attr_map *default_entry_map;
+    struct sdap_attr_map *default_mobject_map;
+    int ret;
+
+    /* search base */
+    search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
+    if (search_base != NULL) {
+        /* set autofs search bases if they are not */
+        if (dp_opt_get_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE) == NULL) {
+            ret = dp_opt_set_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE,
+                                    search_base);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, ("Could not set autofs search base"
+                      "to default value\n"));
+                return ret;
+            }
+
+            DEBUG(SSSDBG_FUNC_DATA, ("Option %s set to %s\n",
+                  opts->basic[SDAP_AUTOFS_SEARCH_BASE].opt_name,
+                  dp_opt_get_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE)));
+        }
+    } else {
+        DEBUG(SSSDBG_TRACE_FUNC, ("Search base not set, trying to discover it later "
+              "connecting to the LDAP server.\n"));
+    }
+
+    ret = sdap_parse_search_base(opts, opts->basic,
+                                 SDAP_AUTOFS_SEARCH_BASE,
+                                 &opts->sdom->autofs_search_bases);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not parse autofs search base\n"));
+        return ret;
+    }
+
+    /* attribute maps */
+    switch (opts->schema_type) {
+        case SDAP_SCHEMA_RFC2307:
+            default_mobject_map = rfc2307_autofs_mobject_map;
+            default_entry_map = rfc2307_autofs_entry_map;
+            break;
+        case SDAP_SCHEMA_RFC2307BIS:
+        case SDAP_SCHEMA_IPA_V1:
+        case SDAP_SCHEMA_AD:
+            default_mobject_map = rfc2307bis_autofs_mobject_map;
+            default_entry_map = rfc2307bis_autofs_entry_map;
+            break;
+        default:
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown LDAP schema!\n"));
+            return EINVAL;
+    }
+
+    ret = sdap_get_map(opts, cdb, conf_path,
+                       default_mobject_map,
+                       SDAP_OPTS_AUTOFS_MAP,
+                       &opts->autofs_mobject_map);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Could not get autofs map object attribute map\n"));
+        return ret;
+    }
+
+    ret = sdap_get_map(opts, cdb, conf_path,
+                       default_entry_map,
+                       SDAP_OPTS_AUTOFS_ENTRY,
+                       &opts->autofs_entry_map);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Could not get autofs entry object attribute map\n"));
+        return ret;
+    }
+
+    return EOK;
+}
+
+errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx,
+                               struct dp_option *opts, int class,
+                               struct sdap_search_base ***_search_bases)
+{
+    const char *class_name;
+    char *unparsed_base;
+    const char *old_filter = NULL;
+
+    *_search_bases = NULL;
+
+    switch (class) {
+    case SDAP_SEARCH_BASE:
+        class_name = "DEFAULT";
+        break;
+    case SDAP_USER_SEARCH_BASE:
+        class_name = "USER";
+        old_filter = dp_opt_get_string(opts, SDAP_USER_SEARCH_FILTER);
+        break;
+    case SDAP_GROUP_SEARCH_BASE:
+        class_name = "GROUP";
+        old_filter = dp_opt_get_string(opts, SDAP_GROUP_SEARCH_FILTER);
+        break;
+    case SDAP_NETGROUP_SEARCH_BASE:
+        class_name = "NETGROUP";
+        break;
+    case SDAP_SUDO_SEARCH_BASE:
+        class_name = "SUDO";
+        break;
+    case SDAP_SERVICE_SEARCH_BASE:
+        class_name = "SERVICE";
+        break;
+    case SDAP_AUTOFS_SEARCH_BASE:
+        class_name = "AUTOFS";
+        break;
+    default:
+        DEBUG(SSSDBG_CONF_SETTINGS,
+              ("Unknown search base type: [%d]\n", class));
+        class_name = "UNKNOWN";
+        /* Non-fatal */
+        break;
+    }
+
+    unparsed_base = dp_opt_get_string(opts, class);
+    if (!unparsed_base || unparsed_base[0] == '\0') return ENOENT;
+
+    return common_parse_search_base(mem_ctx, unparsed_base,
+                                    class_name, old_filter,
+                                    _search_bases);
+}
+
+errno_t
+sdap_create_search_base(TALLOC_CTX *mem_ctx,
+                        const char *unparsed_base,
+                        int scope,
+                        const char *filter,
+                        struct sdap_search_base **_base)
+{
+    struct sdap_search_base *base;
+    TALLOC_CTX *tmp_ctx;
+    errno_t ret;
+    struct ldb_dn *ldn;
+    struct ldb_context *ldb;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* Create a throwaway LDB context for validating the DN */
+    ldb = ldb_init(tmp_ctx, NULL);
+    if (!ldb) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    base = talloc_zero(tmp_ctx, struct sdap_search_base);
+    if (base == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    base->basedn = talloc_strdup(base, unparsed_base);
+    if (base->basedn == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* Validate the basedn */
+    ldn = ldb_dn_new(tmp_ctx, ldb, unparsed_base);
+    if (!ldn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    if (!ldb_dn_validate(ldn)) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+                ("Invalid base DN [%s]\n",
+                 unparsed_base));
+        ret = EINVAL;
+        goto done;
+    }
+
+    base->scope = scope;
+    base->filter = filter;
+
+    *_base = talloc_steal(mem_ctx, base);
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t common_parse_search_base(TALLOC_CTX *mem_ctx,
+                                 const char *unparsed_base,
+                                 const char *class_name,
+                                 const char *old_filter,
+                                 struct sdap_search_base ***_search_bases)
+{
+    errno_t ret;
+    struct sdap_search_base **search_bases;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_context *ldb;
+    struct ldb_dn *ldn;
+    struct ldb_parse_tree *tree;
+    char **split_bases;
+    char *filter;
+    int count;
+    int i, c;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* Create a throwaway LDB context for validating the DN */
+    ldb = ldb_init(tmp_ctx, NULL);
+    if (!ldb) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = split_on_separator(tmp_ctx, unparsed_base, '?', false, false,
+                             &split_bases, &count);
+    if (ret != EOK) goto done;
+
+    /* The split must be either exactly one value or a multiple of
+     * three in order to be valid.
+     * One value: just a base, backwards-compatible with pre-1.7.0 versions
+     * Multiple: search_base?scope?filter[?search_base?scope?filter]*
+     */
+    if (count > 1 && (count % 3)) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Unparseable search base: [%s][%d]\n", unparsed_base, count));
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (count == 1) {
+        search_bases = talloc_array(tmp_ctx, struct sdap_search_base *, 2);
+        if (!search_bases) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        if (old_filter != NULL) {
+            /* Using a deprecated ldap_{user,group}_search_filter */
+            DEBUG(SSSDBG_IMPORTANT_INFO, ("WARNING: Using a deprecated filter "
+                  "option for %s. Please see the documentation on LDAP search "
+                  "bases to see how the obsolete option can be migrated\n",
+                  class_name));
+            sss_log(SSS_LOG_NOTICE, "WARNING: Using a deprecated filter option"
+                    "for %s. Please see the documentation on LDAP search bases "
+                    "to see how the obsolete option can be migrated\n",
+                    class_name);
+        }
+
+        ret = sdap_create_search_base(search_bases, unparsed_base,
+                                      LDAP_SCOPE_SUBTREE, old_filter,
+                                      &search_bases[0]);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Cannot create new sdap search base\n"));
+            goto done;
+        }
+
+        DEBUG(SSSDBG_CONF_SETTINGS,
+              ("Search base added: [%s][%s][%s][%s]\n",
+               class_name,
+               search_bases[0]->basedn,
+               "SUBTREE",
+               search_bases[0]->filter ? search_bases[0]->filter : ""));
+
+        search_bases[1] = NULL;
+    } else {
+        search_bases = talloc_array(tmp_ctx, struct sdap_search_base *,
+                                    (count / 3) + 1);
+        if (!search_bases) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        i = 0;
+        for (c = 0; c < count; c += 3) {
+            search_bases[i] = talloc_zero(search_bases,
+                                          struct sdap_search_base);
+            if (!search_bases[i]) {
+                ret = ENOMEM;
+                goto done;
+            }
+
+            if (split_bases[c][0] == '\0') {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Zero-length search base: [%s]\n", unparsed_base));
+                ret = EINVAL;
+                goto done;
+            }
+
+            /* Validate the basedn */
+            ldn = ldb_dn_new(tmp_ctx, ldb, split_bases[c]);
+            if (!ldn) {
+                ret = ENOMEM;
+                goto done;
+            }
+
+            if (!ldb_dn_validate(ldn)) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Invalid base DN [%s]\n",
+                       split_bases[c]));
+                ret = EINVAL;
+                goto done;
+            }
+            talloc_zfree(ldn);
+
+            /* Set the search base DN */
+            search_bases[i]->basedn = talloc_strdup(search_bases[i],
+                                                    split_bases[c]);
+            if (!search_bases[i]->basedn) {
+                ret = ENOMEM;
+                goto done;
+            }
+
+            /* Set the search scope for this base DN */
+            if ((split_bases[c+1][0] == '\0')
+                    || strcasecmp(split_bases[c+1], "sub") == 0
+                    || strcasecmp(split_bases[c+1], "subtree") == 0) {
+                /* If unspecified, default to subtree */
+                search_bases[i]->scope = LDAP_SCOPE_SUBTREE;
+            } else if (strcasecmp(split_bases[c+1], "one") == 0
+                    || strcasecmp(split_bases[c+1], "onelevel") == 0) {
+                search_bases[i]->scope = LDAP_SCOPE_ONELEVEL;
+            } else if (strcasecmp(split_bases[c+1], "base") == 0) {
+                search_bases[i]->scope = LDAP_SCOPE_BASE;
+            } else {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Unknown search scope: [%s]\n", split_bases[c+1]));
+                ret = EINVAL;
+                goto done;
+            }
+
+            /* Get a specialized filter if provided */
+            if (split_bases[c+2][0] == '\0') {
+                search_bases[i]->filter = NULL;
+            } else {
+                if (split_bases[c+2][0] != '(') {
+                    /* Filters need to be enclosed in parentheses
+                     * to be validated properly by ldb_parse_tree()
+                     */
+                    filter = talloc_asprintf(tmp_ctx, "(%s)",
+                                             split_bases[c+2]);
+                } else {
+                    filter = talloc_strdup(tmp_ctx, split_bases[c+2]);
+                }
+                if (!filter) {
+                    ret = ENOMEM;
+                    goto done;
+                }
+
+                tree = ldb_parse_tree(tmp_ctx, filter);
+                if(!tree) {
+                    DEBUG(SSSDBG_CRIT_FAILURE,
+                          ("Invalid search filter: [%s]\n", filter));
+                    ret = EINVAL;
+                    goto done;
+                }
+                talloc_zfree(tree);
+
+                search_bases[i]->filter = talloc_steal(search_bases[i],
+                                                       filter);
+            }
+
+            DEBUG(SSSDBG_CONF_SETTINGS,
+                  ("Search base added: [%s][%s][%s][%s]\n",
+                   class_name,
+                   search_bases[i]->basedn,
+                   split_bases[c+1][0] ? split_bases[c+1] : "SUBTREE",
+                   search_bases[i]->filter ? search_bases[i]->filter : ""));
+
+            i++;
+        }
+        search_bases[i] = NULL;
+    }
+
+    *_search_bases = talloc_steal(mem_ctx, search_bases);
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
-- 
1.7.11.7

