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) {