summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2011-09-13 09:07:26 -0400
committerStephen Gallagher <sgallagh@redhat.com>2011-11-02 11:12:12 -0400
commit09b663e6dfd2ed09cead04f926d3e99e9ac01894 (patch)
treec5764cb1f1c5e59099a37478dd2e3fe35f289054
parent82962098e3848ed039a57522d74fc500bc6df8ad (diff)
downloadsssd-09b663e6dfd2ed09cead04f926d3e99e9ac01894.tar.gz
sssd-09b663e6dfd2ed09cead04f926d3e99e9ac01894.tar.bz2
sssd-09b663e6dfd2ed09cead04f926d3e99e9ac01894.zip
LDAP: Add parser for multiple search bases
-rw-r--r--src/providers/ipa/ipa_common.c20
-rw-r--r--src/providers/ldap/ldap_common.c261
-rw-r--r--src/providers/ldap/ldap_common.h5
-rw-r--r--src/providers/ldap/sdap.c109
-rw-r--r--src/providers/ldap/sdap.h11
5 files changed, 380 insertions, 26 deletions
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index c6229456..12c0bb67 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -332,10 +332,15 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
if (ret != EOK) {
goto done;
}
+
DEBUG(6, ("Option %s set to %s\n",
ipa_opts->id->basic[SDAP_SEARCH_BASE].opt_name,
dp_opt_get_string(ipa_opts->id->basic, SDAP_SEARCH_BASE)));
}
+ ret = sdap_parse_search_base(ipa_opts->id, ipa_opts->id,
+ SDAP_SEARCH_BASE,
+ &ipa_opts->id->search_bases);
+ if (ret != EOK) goto done;
/* set krb realm */
if (NULL == dp_opt_get_string(ipa_opts->id->basic, SDAP_KRB5_REALM)) {
@@ -414,11 +419,16 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
if (ret != EOK) {
goto done;
}
+
DEBUG(6, ("Option %s set to %s\n",
ipa_opts->id->basic[SDAP_USER_SEARCH_BASE].opt_name,
dp_opt_get_string(ipa_opts->id->basic,
SDAP_USER_SEARCH_BASE)));
}
+ ret = sdap_parse_search_base(ipa_opts->id, ipa_opts->id,
+ SDAP_USER_SEARCH_BASE,
+ &ipa_opts->id->user_search_bases);
+ if (ret != EOK) goto done;
if (NULL == dp_opt_get_string(ipa_opts->id->basic,
SDAP_GROUP_SEARCH_BASE)) {
@@ -428,11 +438,16 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
if (ret != EOK) {
goto done;
}
+
DEBUG(6, ("Option %s set to %s\n",
ipa_opts->id->basic[SDAP_GROUP_SEARCH_BASE].opt_name,
dp_opt_get_string(ipa_opts->id->basic,
SDAP_GROUP_SEARCH_BASE)));
}
+ ret = sdap_parse_search_base(ipa_opts->id, ipa_opts->id,
+ SDAP_GROUP_SEARCH_BASE,
+ &ipa_opts->id->group_search_bases);
+ if (ret != EOK) goto done;
if (NULL == dp_opt_get_string(ipa_opts->id->basic,
SDAP_NETGROUP_SEARCH_BASE)) {
@@ -461,11 +476,16 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
goto done;
}
#endif
+
DEBUG(6, ("Option %s set to %s\n",
ipa_opts->id->basic[SDAP_NETGROUP_SEARCH_BASE].opt_name,
dp_opt_get_string(ipa_opts->id->basic,
SDAP_NETGROUP_SEARCH_BASE)));
}
+ ret = sdap_parse_search_base(ipa_opts->id, ipa_opts->id,
+ SDAP_NETGROUP_SEARCH_BASE,
+ &ipa_opts->id->netgroup_search_bases);
+ if (ret != EOK) goto done;
value = dp_opt_get_string(ipa_opts->id->basic, SDAP_DEREF);
if (value != NULL) {
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 5a375bf0..233d0194 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -249,6 +249,7 @@ int ldap_get_options(TALLOC_CTX *memctx,
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 */
@@ -270,6 +271,30 @@ int ldap_get_options(TALLOC_CTX *memctx,
"connecting to the LDAP server.\n"));
}
+ /* Default search */
+ ret = sdap_parse_search_base(opts, opts,
+ SDAP_SEARCH_BASE,
+ &opts->search_bases);
+ if (ret != EOK && ret != ENOENT) goto done;
+
+ /* User search */
+ ret = sdap_parse_search_base(opts, opts,
+ SDAP_USER_SEARCH_BASE,
+ &opts->user_search_bases);
+ if (ret != EOK && ret != ENOENT) goto done;
+
+ /* Group search base */
+ ret = sdap_parse_search_base(opts, opts,
+ SDAP_GROUP_SEARCH_BASE,
+ &opts->group_search_bases);
+ if (ret != EOK && ret != ENOENT) goto done;
+
+ /* Netgroup search */
+ ret = sdap_parse_search_base(opts, opts,
+ SDAP_NETGROUP_SEARCH_BASE,
+ &opts->netgroup_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"));
@@ -468,6 +493,242 @@ done:
return ret;
}
+errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx,
+ struct sdap_options *opts,
+ enum sdap_basic_opt class,
+ 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;
+ const char *class_name;
+ char *unparsed_base;
+ char **split_bases;
+ char *filter;
+ int count;
+ int i, c;
+
+ *_search_bases = NULL;
+
+ switch (class) {
+ case SDAP_SEARCH_BASE:
+ class_name = "DEFAULT";
+ break;
+ case SDAP_USER_SEARCH_BASE:
+ class_name = "USER";
+ break;
+ case SDAP_GROUP_SEARCH_BASE:
+ class_name = "GROUP";
+ break;
+ case SDAP_NETGROUP_SEARCH_BASE:
+ class_name = "NETGROUP";
+ break;
+ default:
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ ("Unknown search base type: [%d]\n", class));
+ class_name = "UNKNOWN";
+ /* Non-fatal */
+ }
+
+ unparsed_base = dp_opt_get_string(opts->basic, class);
+ if (!unparsed_base || unparsed_base[0] == '\0') return ENOENT;
+
+ 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,
+ &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;
+ }
+ search_bases[0] = talloc_zero(search_bases, struct sdap_search_base);
+ if (!search_bases[0]) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ search_bases[0]->basedn = talloc_strdup(search_bases[0],
+ unparsed_base);
+ if (!search_bases[0]->basedn) {
+ 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;
+ }
+ talloc_zfree(ldn);
+
+ search_bases[0]->scope = LDAP_SCOPE_SUBTREE;
+ search_bases[0]->filter = NULL;
+
+
+ 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_common.h b/src/providers/ldap/ldap_common.h
index e08a65bb..e64b65c2 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -170,4 +170,9 @@ errno_t msgs2attrs_array(TALLOC_CTX *mem_ctx, size_t count,
struct ldb_message **msgs,
struct sysdb_attrs ***attrs);
+errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx,
+ struct sdap_options *opts,
+ enum sdap_basic_opt class,
+ struct sdap_search_base ***_search_bases);
+
#endif /* _LDAP_COMMON_H_ */
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index 02504a4f..c3f507bb 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -690,42 +690,99 @@ static char *get_naming_context(TALLOC_CTX *mem_ctx,
return naming_context;
}
+static errno_t sdap_set_search_base(struct sdap_options *opts,
+ enum sdap_basic_opt class,
+ char *naming_context)
+{
+ errno_t ret;
+ struct sdap_search_base ***bases;
+
+ switch(class) {
+ case SDAP_SEARCH_BASE:
+ bases = &opts->search_bases;
+ break;
+ case SDAP_USER_SEARCH_BASE:
+ bases = &opts->user_search_bases;
+ break;
+ case SDAP_GROUP_SEARCH_BASE:
+ bases = &opts->group_search_bases;
+ break;
+ case SDAP_NETGROUP_SEARCH_BASE:
+ bases = &opts->netgroup_search_bases;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ ("Setting option [%s] to [%s].\n",
+ opts->basic[class].opt_name, naming_context));
+
+ ret = dp_opt_set_string(opts->basic, class, naming_context);
+ if (ret != EOK) {
+ DEBUG(1, ("dp_opt_set_string failed.\n"));
+ goto done;
+ }
+
+ ret = sdap_parse_search_base(opts, opts, class, bases);
+ if (ret != EOK) goto done;
+
+ ret = EOK;
+done:
+ return ret;
+}
+
errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
struct sdap_handle *sh,
struct sdap_options *opts)
{
int ret;
char *naming_context = NULL;
- const int search_base_options[] = { SDAP_SEARCH_BASE,
- SDAP_USER_SEARCH_BASE,
- SDAP_GROUP_SEARCH_BASE,
- SDAP_NETGROUP_SEARCH_BASE,
- -1 };
- size_t c;
-
- for (c = 0; search_base_options[c] != -1; c++) {
- if (dp_opt_get_string(opts->basic, search_base_options[c]) == NULL) {
- if (naming_context == NULL) {
- naming_context = get_naming_context(opts->basic, rootdse);
- if (naming_context == NULL) {
- DEBUG(1, ("get_naming_context failed.\n"));
- ret = EINVAL;
- goto done;
- }
- }
- DEBUG(3, ("Setting option [%s] to [%s].\n",
- opts->basic[search_base_options[c]].opt_name,
- naming_context));
- ret = dp_opt_set_string(opts->basic, search_base_options[c],
- naming_context);
- if (ret != EOK) {
- DEBUG(1, ("dp_opt_set_string failed.\n"));
- goto done;
- }
+ if (!opts->search_bases
+ ||!opts->user_search_bases
+ || !opts->group_search_bases
+ || !opts->netgroup_search_bases) {
+ naming_context = get_naming_context(opts->basic, rootdse);
+ if (naming_context == NULL) {
+ DEBUG(1, ("get_naming_context failed.\n"));
+ ret = EINVAL;
+ goto done;
}
}
+ /* Default */
+ if (!opts->search_bases) {
+ ret = sdap_set_search_base(opts,
+ SDAP_SEARCH_BASE,
+ naming_context);
+ if (ret != EOK) goto done;
+ }
+
+ /* Users */
+ if (!opts->user_search_bases) {
+ ret = sdap_set_search_base(opts,
+ SDAP_USER_SEARCH_BASE,
+ naming_context);
+ if (ret != EOK) goto done;
+ }
+
+ /* Groups */
+ if (!opts->group_search_bases) {
+ ret = sdap_set_search_base(opts,
+ SDAP_GROUP_SEARCH_BASE,
+ naming_context);
+ if (ret != EOK) goto done;
+ }
+
+ /* Netgroups */
+ if (!opts->netgroup_search_bases) {
+ ret = sdap_set_search_base(opts,
+ SDAP_NETGROUP_SEARCH_BASE,
+ naming_context);
+ if (ret != EOK) goto done;
+ }
+
ret = EOK;
done:
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index cfa9b1f3..1ea57082 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -286,6 +286,12 @@ struct sdap_attr_map {
char *name;
};
+struct sdap_search_base {
+ const char *basedn;
+ int scope;
+ const char *filter;
+};
+
struct sdap_options {
struct dp_option *basic;
struct sdap_attr_map *gen_map;
@@ -300,6 +306,11 @@ struct sdap_options {
SDAP_SCHEMA_IPA_V1 = 3, /* member/memberof */
SDAP_SCHEMA_AD = 4 /* AD's member/memberof */
} schema_type;
+
+ struct sdap_search_base **search_bases;
+ struct sdap_search_base **user_search_bases;
+ struct sdap_search_base **group_search_bases;
+ struct sdap_search_base **netgroup_search_bases;
};
struct sdap_server_opts {