diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py
index bd0d53228d..2b000c1b5b 100644
--- a/src/config/SSSDConfig/sssdoptions.py
+++ b/src/config/SSSDConfig/sssdoptions.py
@@ -358,6 +358,7 @@ def __init__(self):
'ldap_uri': _('ldap_uri, The URI of the LDAP server'),
'ldap_backup_uri': _('ldap_backup_uri, The URI of the LDAP server'),
'ldap_search_base': _('The default base DN'),
+ 'ldap_read_rootdse': _('How to read rootDSE from LDAP server'),
'ldap_schema': _('The Schema Type in use on the LDAP server, rfc2307'),
'ldap_pwmodify_mode': _('Mode used to change user password'),
'ldap_default_bind_dn': _('The default bind DN'),
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 87e01af016..b337d21a46 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -686,6 +686,7 @@ option = ldap_purge_cache_offset
option = ldap_pwd_attribute
option = ldap_pwdlockout_dn
option = ldap_pwd_policy
+option = ldap_read_rootdse
option = ldap_referrals
option = ldap_rfc2307_fallback_to_local_users
option = ldap_rootdse_last_usn
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 169d0c5719..49e266e85b 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -161,6 +161,45 @@
+
+ ldap_read_rootdse (string)
+
+
+ SSSD reads RootDSE to get information about LDAP and
+ its capabilities. By default, this is done
+ anonymously. However, this may not be permitted by
+ the LDAP server. In such cases we can use this option
+ to influence SSSD behavior.
+
+
+ Allowed values are:
+
+
+
+ anonymous
+
+
+
+
+ authenticated
+
+
+
+
+ never
+
+
+
+ Note that when using the "anonymous" option, SSSD
+ may attempt to read RootDSE after authentication
+ if anonymous access fails.
+
+
+ Default: anonymous
+
+
+
+
ldap_schema (string)
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index 5fb26c4f2c..2ee74136a5 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -68,6 +68,7 @@ struct dp_option ad_def_ldap_opts[] = {
{ "ldap_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_backup_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "ldap_read_rootdse", DP_OPT_STRING, { "anonymous" }, NULL_STRING },
{ "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_default_authtok_type", DP_OPT_STRING, NULL_STRING, NULL_STRING},
{ "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index 5bfd65a671..0a5f75f832 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -79,6 +79,7 @@ struct dp_option ipa_def_ldap_opts[] = {
{ "ldap_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_backup_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "ldap_read_rootdse", DP_OPT_STRING, { "anonymous" }, NULL_STRING },
{ "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_default_authtok_type", DP_OPT_STRING, NULL_STRING, NULL_STRING},
{ "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },
diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
index d0d2b9e748..c6ea741e4f 100644
--- a/src/providers/ldap/ldap_opts.c
+++ b/src/providers/ldap/ldap_opts.c
@@ -33,6 +33,7 @@ struct dp_option default_basic_opts[] = {
{ "ldap_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_backup_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "ldap_read_rootdse", DP_OPT_STRING, { "anonymous" }, NULL_STRING },
{ "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_default_authtok_type", DP_OPT_STRING, { "password" }, NULL_STRING},
{ "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 35a4d5e1c9..8ed5e24ffc 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -140,6 +140,7 @@ enum sdap_basic_opt {
SDAP_URI = 0,
SDAP_BACKUP_URI,
SDAP_SEARCH_BASE,
+ SDAP_READ_ROOTDSE,
SDAP_DEFAULT_BIND_DN,
SDAP_DEFAULT_AUTHTOK_TYPE,
SDAP_DEFAULT_AUTHTOK,
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index 67c09835b7..30829c29c5 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -41,6 +41,13 @@ struct sdap_rebind_proc_params {
bool use_ppolicy;
};
+enum sdap_rootdse_read_opts {
+ SDAP_ROOTDSE_READ_ANONYMOUS,
+ SDAP_ROOTDSE_READ_AUTHENTICATED,
+ SDAP_ROOTDSE_READ_NEVER,
+ SDAP_ROOTDSE_READ_INVALID,
+};
+
static int sdap_rebind_proc(LDAP *ldap, LDAP_CONST char *url, ber_tag_t request,
ber_int_t msgid, void *params);
@@ -1496,6 +1503,7 @@ struct sdap_cli_connect_state {
struct be_ctx *be;
bool use_rootdse;
+ enum sdap_rootdse_read_opts rootdse_access;
struct sysdb_attrs *rootdse;
struct sdap_handle *sh;
@@ -1525,6 +1533,35 @@ static errno_t sdap_cli_auth_reconnect(struct tevent_req *subreq);
static void sdap_cli_auth_reconnect_done(struct tevent_req *subreq);
static void sdap_cli_rootdse_auth_done(struct tevent_req *subreq);
+
+enum sdap_rootdse_read_opts
+decide_rootdse_access(struct dp_option *basic)
+{
+ int i;
+ char *str;
+ struct read_rootdse_enum_str {
+ enum sdap_rootdse_read_opts option_enum;
+ const char *option_str;
+ };
+ static struct read_rootdse_enum_str read_rootdse_enum_str[] = {
+ { SDAP_ROOTDSE_READ_ANONYMOUS, "anonymous"},
+ { SDAP_ROOTDSE_READ_AUTHENTICATED, "authenticated"},
+ { SDAP_ROOTDSE_READ_NEVER, "never"},
+ { SDAP_ROOTDSE_READ_INVALID, NULL}
+ };
+
+ str = dp_opt_get_string (basic, SDAP_READ_ROOTDSE);
+ for (i = 0; read_rootdse_enum_str[i].option_str != NULL; i++) {
+ if (strcasecmp(read_rootdse_enum_str[i].option_str, str) == 0) {
+ return read_rootdse_enum_str[i].option_enum;
+ }
+ }
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "The ldap_read_rootdse option has an invalid value [%s], "
+ "using [anonymous]\n", str);
+ return SDAP_ROOTDSE_READ_ANONYMOUS;
+}
+
static errno_t
decide_tls_usage(enum connect_tls force_tls, struct dp_option *basic,
const char *uri, bool *_use_tls)
@@ -1579,6 +1616,7 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
state->srv = NULL;
state->srv_opts = NULL;
state->use_rootdse = !skip_rootdse;
+ state->rootdse_access = decide_rootdse_access (opts->basic);
state->force_tls = force_tls;
state->do_auth = !skip_auth;
@@ -1695,7 +1733,9 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
}
state->retry_attempts = 0;
- if (state->use_rootdse) {
+ if (state->use_rootdse &&
+ state->rootdse_access == SDAP_ROOTDSE_READ_ANONYMOUS) {
+
/* fetch the rootDSE this time */
sdap_cli_rootdse_step(req);
return;
@@ -1703,7 +1743,9 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
- if (state->do_auth && sasl_mech && state->use_rootdse) {
+ if (state->do_auth && sasl_mech && state->use_rootdse &&
+ state->rootdse_access == SDAP_ROOTDSE_READ_ANONYMOUS) {
+
/* check if server claims to support the configured SASL MECH */
if (!sdap_is_sasl_mech_supported(state->sh, sasl_mech)) {
tevent_req_error(req, ENOTSUP);
@@ -2097,9 +2139,12 @@ static void sdap_cli_auth_done(struct tevent_req *subreq)
return;
}
- if (state->use_rootdse && !state->rootdse) {
- /* We weren't able to read rootDSE during unauthenticated bind.
- * Let's try again now that we are authenticated */
+ if (state->use_rootdse && !state->rootdse &&
+ state->rootdse_access != SDAP_ROOTDSE_READ_NEVER) {
+ /* We did not read rootDSE during unauthenticated bind becase
+ * it is unaccessible for anonymous user or because
+ * ldap_read_rootdse is set to "authenticated"
+ * Let's try to read it now */
subreq = sdap_get_rootdse_send(state, state->ev,
state->opts, state->sh);
if (!subreq) {