File 0045-ldaps-for-ad-provider.patch of Package sssd.24165

From f2686beb33f1b70caf68b0d396219a67f8a08db3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Sun, 12 May 2019 16:38:43 +0200
Subject: [PATCH 1/7] SDAP: allow GSS-SPNEGO for LDAP SASL bind as well

From the LDAP client perspective GSS-SPNEGO and GSSAPI are quite
similar. To support GSS-SPNEGO SSSD must make sure that a Kerberos
ticket is available before the LDAP SASL bind is started.

Related to https://pagure.io/SSSD/sssd/issue/4006

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
(cherry picked from commit 3b89934e831fa4e575e398fee6e4c3d4d24854eb)
(cherry picked from commit f5d031ba41b1c297f95df61f013f1c7ef8bca275)
---
 src/man/sssd-ldap.5.xml                    | 26 ++++++++++++----------
 src/providers/ad/ad_common.c               |  6 ++---
 src/providers/ad/ad_init.c                 |  2 +-
 src/providers/ldap/ldap_common.h           |  2 +-
 src/providers/ldap/ldap_init.c             |  2 +-
 src/providers/ldap/sdap.c                  |  9 ++++++++
 src/providers/ldap/sdap.h                  |  2 ++
 src/providers/ldap/sdap_async_connection.c |  8 +++----
 8 files changed, 35 insertions(+), 22 deletions(-)

diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index f7617670c..acebe91cc 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1760,8 +1760,8 @@
                     <term>ldap_sasl_mech (string)</term>
                     <listitem>
                         <para>
-                            Specify the SASL mechanism to use.
-                            Currently only GSSAPI is tested and supported.
+                            Specify the SASL mechanism to use.  Currently only
+                            GSSAPI and GSS-SPNEGO are tested and supported.
                         </para>
                         <para>
                             Default: not set
@@ -1773,12 +1773,12 @@
                     <term>ldap_sasl_authid (string)</term>
                     <listitem>
                         <para>
-                            Specify the SASL authorization id to use.
-                            When GSSAPI is used, this represents the Kerberos
-                            principal used for authentication to the directory.
-                            This option can either contain the full principal (for
-                            example host/myhost@EXAMPLE.COM) or just the principal name
-                            (for example host/myhost).
+                            Specify the SASL authorization id to use.  When
+                            GSSAPI/GSS-SPNEGO are used, this represents the
+                            Kerberos principal used for authentication to the
+                            directory.  This option can either contain the full
+                            principal (for example host/myhost@EXAMPLE.COM) or
+                            just the principal name (for example host/myhost).
                         </para>
                         <para>
                             Default: host/hostname@REALM
@@ -1819,7 +1819,8 @@
                     <term>ldap_krb5_keytab (string)</term>
                     <listitem>
                         <para>
-                            Specify the keytab to use when using SASL/GSSAPI.
+                            Specify the keytab to use when using
+                            SASL/GSSAPI/GSS-SPNEGO.
                         </para>
                         <para>
                             Default: System keytab, normally <filename>/etc/krb5.keytab</filename>
@@ -1834,7 +1835,7 @@
                             Specifies that the id_provider should init
                             Kerberos credentials (TGT).
                             This action is performed only if SASL is used and
-                            the mechanism selected is GSSAPI.
+                            the mechanism selected is GSSAPI or GSS-SPNEGO.
                         </para>
                         <para>
                             Default: true
@@ -1847,7 +1848,7 @@
                     <listitem>
                         <para>
                             Specifies the lifetime in seconds of the TGT if
-                            GSSAPI is used.
+                            GSSAPI or GSS-SPNEGO is used.
                         </para>
                         <para>
                             Default: 86400 (24 hours)
@@ -1888,7 +1889,8 @@
                     <term>krb5_realm (string)</term>
                     <listitem>
                         <para>
-                            Specify the Kerberos REALM (for SASL/GSSAPI auth).
+                            Specify the Kerberos REALM (for
+                            SASL/GSSAPI/GSS-SPNEGO auth).
                         </para>
                         <para>
                             Default: System defaults, see <filename>/etc/krb5.conf</filename>
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 1708ca01f..aadd2bec9 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -611,7 +611,7 @@ _ad_servers_init(struct ad_service *service,
         if (resolv_is_address(list[j])) {
             DEBUG(SSSDBG_IMPORTANT_INFO,
                   "ad_server [%s] is detected as IP address, "
-                  "this can cause GSSAPI problems\n", list[j]);
+                  "this can cause GSSAPI/GSS-SPNEGO problems\n", list[j]);
         }
     }
 
@@ -1047,7 +1047,7 @@ ad_set_sdap_options(struct ad_options *ad_opts,
         goto done;
     }
 
-    /* Set the Kerberos Realm for GSSAPI */
+    /* Set the Kerberos Realm for GSSAPI or GSS-SPNEGO */
     krb5_realm = dp_opt_get_string(ad_opts->basic, AD_KRB5_REALM);
     if (!krb5_realm) {
         /* Should be impossible, this is set in ad_get_common_options() */
@@ -1292,7 +1292,7 @@ ad_get_auth_options(TALLOC_CTX *mem_ctx,
            ad_servers);
 
     /* Set krb5 realm */
-    /* Set the Kerberos Realm for GSSAPI */
+    /* Set the Kerberos Realm for GSSAPI/GSS-SPNEGO */
     krb5_realm = dp_opt_get_string(ad_opts->basic, AD_KRB5_REALM);
     if (!krb5_realm) {
         /* Should be impossible, this is set in ad_get_common_options() */
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 8c485a7c2..cbe61da80 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -56,7 +56,7 @@ static int ad_sasl_getopt(void *context, const char *plugin_name,
     if (!plugin_name || !result) {
         return SASL_FAIL;
     }
-    if (strcmp(plugin_name, "GSSAPI") != 0) {
+    if (!sdap_sasl_mech_needs_kinit(plugin_name)) {
         return SASL_FAIL;
     }
     if (strcmp(option, "ad_compat") != 0) {
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 288d72673..15b483b13 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -63,7 +63,7 @@ struct sdap_id_ctx {
     struct be_ctx *be;
     struct sdap_options *opts;
 
-    /* If using GSSAPI */
+    /* If using GSSAPI or GSS-SPNEGO */
     struct krb5_service *krb5_service;
     /* connection to a server */
     struct sdap_id_conn_ctx *conn;
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index 83075b5d3..263d85a26 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -365,7 +365,7 @@ static bool should_call_gssapi_init(struct sdap_options *opts)
         return false;
     }
 
-    if (strcasecmp(sasl_mech, "GSSAPI") != 0) {
+    if (!sdap_sasl_mech_needs_kinit(sasl_mech)) {
         return false;
     }
 
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index 0241a99e4..cb55de7f6 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -904,6 +904,15 @@ errno_t setup_tls_config(struct dp_option *basic_opts)
     return EOK;
 }
 
+bool sdap_sasl_mech_needs_kinit(const char *sasl_mech)
+{
+    if (strcasecmp(sasl_mech, "GSSAPI") == 0
+            || strcasecmp(sasl_mech, "GSS-SPNEGO") == 0) {
+        return true;
+    }
+
+    return false;
+}
 
 bool sdap_check_sup_list(struct sup_list *l, const char *val)
 {
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index ecf9c4d2e..0ee877b19 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -608,6 +608,8 @@ bool sdap_check_sup_list(struct sup_list *l, const char *val);
 #define sdap_is_extension_supported(sh, ext_oid) \
     sdap_check_sup_list(&((sh)->supported_extensions), ext_oid)
 
+bool sdap_sasl_mech_needs_kinit(const char *mech);
+
 int build_attrs_from_map(TALLOC_CTX *memctx,
                          struct sdap_attr_map *map,
                          size_t size,
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index a8d4262b5..f4ab8c1cc 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -1586,14 +1586,14 @@ 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) {
-        /* check if server claims to support GSSAPI */
+        /* 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);
             return;
         }
     }
 
-    if (state->do_auth && sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) {
+    if (state->do_auth && sasl_mech && sdap_sasl_mech_needs_kinit(sasl_mech)) {
         if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) {
             sdap_cli_kinit_step(req);
             return;
@@ -1671,14 +1671,14 @@ static void sdap_cli_rootdse_done(struct tevent_req *subreq)
     sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
 
     if (state->do_auth && sasl_mech && state->rootdse) {
-        /* check if server claims to support GSSAPI */
+        /* 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);
             return;
         }
     }
 
-    if (state->do_auth && sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) {
+    if (state->do_auth && sasl_mech && sdap_sasl_mech_needs_kinit(sasl_mech)) {
         if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) {
             sdap_cli_kinit_step(req);
             return;
-- 
2.32.0


From dfde084728e8f661ceb71ee66b58048fcf506fb3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 21 May 2019 10:22:04 +0200
Subject: [PATCH 2/7] sdap: inherit SDAP_SASL_MECH if not set explicitly

If ldap_sasl_mech is set for the configured domain in sssd.conf the
value is inherited automatically to all sub-domains. The can be
overwritten by setting ldap_sasl_mech for a given sub-domain explicitly
in sssd.conf.

Related to https://pagure.io/SSSD/sssd/issue/4006

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
(cherry picked from commit 070f22f896b909c140ed7598aed2393d61a834ae)
(cherry picked from commit 373b1136ccb3bf54f32d47473e8120d0258f8405)
---
 src/config/cfg_rules.ini                  |  1 +
 src/man/sssd-ldap.5.xml                   | 10 ++++++
 src/man/sssd.conf.5.xml                   |  1 +
 src/providers/ad/ad_common.c              | 38 +++++++++++++++++++++++
 src/providers/ad/ad_common.h              |  5 +++
 src/providers/ad/ad_subdomains.c          | 18 ++++++++++-
 src/providers/ipa/ipa_subdomains_server.c | 19 +++++++++++-
 7 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 22c8781ef..95898caa6 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -741,6 +741,7 @@ option = ldap_user_search_base
 option = ldap_group_search_base
 option = ldap_netgroup_search_base
 option = ldap_service_search_base
+option = ldap_sasl_mech
 option = ad_server
 option = ad_backup_server
 option = ad_site
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index acebe91cc..691678fc7 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1763,6 +1763,16 @@
                             Specify the SASL mechanism to use.  Currently only
                             GSSAPI and GSS-SPNEGO are tested and supported.
                         </para>
+                        <para>
+                            If the backend supports sub-domains the value of
+                            ldap_sasl_mech is automatically inherited to the
+                            sub-domains. If a different value is needed for a
+                            sub-domain it can be overwritten by setting
+                            ldap_sasl_mech for this sub-domain explicitly.
+                            Please see TRUSTED DOMAIN SECTION in
+                            <citerefentry><refentrytitle>sssd.conf</refentrytitle>
+                            <manvolnum>5</manvolnum></citerefentry> for details.
+                        </para>
                         <para>
                             Default: not set
                         </para>
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 50d4f6c8e..9b97fb062 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -3184,6 +3184,7 @@ ldap_user_extra_attrs = phone:telephoneNumber
             <para>ldap_group_search_base,</para>
             <para>ldap_netgroup_search_base,</para>
             <para>ldap_service_search_base,</para>
+            <para>ldap_sasl_mech,</para>
             <para>ad_server,</para>
             <para>ad_backup_server,</para>
             <para>ad_site,</para>
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index aadd2bec9..0aec66f70 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -1473,3 +1473,41 @@ ad_user_conn_list(TALLOC_CTX *mem_ctx,
 
     return clist;
 }
+
+errno_t ad_inherit_opts_if_needed(struct dp_option *parent_opts,
+                                  struct dp_option *suddom_opts,
+                                  struct confdb_ctx *cdb,
+                                  const char *subdom_conf_path,
+                                  int opt_id)
+{
+    int ret;
+    const char *parent_val = NULL;
+    char *dummy = NULL;
+    char *option_list[2] = { NULL, NULL };
+
+    parent_val = dp_opt_get_cstring(parent_opts, opt_id);
+    if (parent_val != NULL) {
+        ret = confdb_get_string(cdb, NULL, subdom_conf_path,
+                                parent_opts[opt_id].opt_name, NULL, &dummy);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "confdb_get_string failed.\n");
+            goto done;
+        }
+
+        if (dummy == NULL) {
+            DEBUG(SSSDBG_CONF_SETTINGS,
+                  "Option [%s] is set in parent domain but not set for "
+                  "sub-domain trying to set it to [%s].\n",
+                  parent_opts[opt_id].opt_name, parent_val);
+            option_list[0] = discard_const(parent_opts[opt_id].opt_name);
+            dp_option_inherit(option_list, opt_id, parent_opts, suddom_opts);
+        }
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(dummy);
+
+    return ret;
+}
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index cba693d65..82a58affe 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -209,4 +209,9 @@ errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
                                  char **_site,
                                  char **_forest);
 
+errno_t ad_inherit_opts_if_needed(struct dp_option *parent_opts,
+                                  struct dp_option *suddom_opts,
+                                  struct confdb_ctx *cdb,
+                                  const char *subdom_conf_path,
+                                  int opt_id);
 #endif /* AD_COMMON_H_ */
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index bd94ba8ea..3788b15ae 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -268,13 +268,29 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
     ad_options = ad_create_2way_trust_options(id_ctx, be_ctx->cdb,
                                               subdom_conf_path, realm, subdom,
                                               hostname, keytab);
-    talloc_free(subdom_conf_path);
     if (ad_options == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
         talloc_free(ad_options);
+        talloc_free(subdom_conf_path);
         return ENOMEM;
     }
 
+    ret = ad_inherit_opts_if_needed(id_ctx->sdap_id_ctx->opts->basic,
+                                    ad_options->id->basic,
+                                    be_ctx->cdb, subdom_conf_path,
+                                    SDAP_SASL_MECH);
+    talloc_free(subdom_conf_path);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Failed to inherit option [%s] to sub-domain [%s]. "
+              "This error is ignored but might cause issues or unexpected "
+              "behavior later on.\n",
+              id_ctx->ad_options->id->basic[SDAP_SASL_MECH].opt_name,
+              subdom->name);
+
+        return ret;
+    }
+
     ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
 
     gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->name);
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index d670a156b..9be726060 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -170,6 +170,7 @@ static struct ad_options *ipa_ad_options_new(struct be_ctx *be_ctx,
     const char *forest;
     const char *forest_realm;
     char *subdom_conf_path;
+    int ret;
 
     /* Trusts are only established with forest roots */
     direction = subdom->forest_root->trust_direction;
@@ -198,12 +199,28 @@ static struct ad_options *ipa_ad_options_new(struct be_ctx *be_ctx,
         DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported trust direction!\n");
         ad_options = NULL;
     }
-    talloc_free(subdom_conf_path);
 
     if (ad_options == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
+        talloc_free(subdom_conf_path);
         return NULL;
     }
+
+    ret = ad_inherit_opts_if_needed(id_ctx->ipa_options->id->basic,
+                                    ad_options->id->basic, be_ctx->cdb,
+                                    subdom_conf_path, SDAP_SASL_MECH);
+    talloc_free(subdom_conf_path);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Failed to inherit option [%s] to sub-domain [%s]. "
+              "This error is ignored but might cause issues or unexpected "
+              "behavior later on.\n",
+              id_ctx->ipa_options->id->basic[SDAP_SASL_MECH].opt_name,
+              subdom->name);
+
+        return NULL;
+    }
+
     return ad_options;
 }
 
-- 
2.32.0


From 31380e86d8b1acc6d11fb807277fa07d876eaefb Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 26 Sep 2019 20:24:34 +0200
Subject: [PATCH 3/7] ad: allow booleans for ad_inherit_opts_if_needed()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Currently ad_inherit_opts_if_needed() can only handle strings. With this
patch it can handle boolean options as well.

Related to https://pagure.io/SSSD/sssd/issue/4131

(cherry picked from commit 3dadb248440f2e7a02c68049001f848459dd1bdf)

Reviewed-by: Pavel Březina <pbrezina@redhat.com>
(cherry picked from commit 44e76055d4413e56a33a90185161b6cfa4062d03)
---
 src/providers/ad/ad_common.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 0aec66f70..de81b1735 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -1484,9 +1484,26 @@ errno_t ad_inherit_opts_if_needed(struct dp_option *parent_opts,
     const char *parent_val = NULL;
     char *dummy = NULL;
     char *option_list[2] = { NULL, NULL };
-
-    parent_val = dp_opt_get_cstring(parent_opts, opt_id);
-    if (parent_val != NULL) {
+    bool is_default = true;
+
+    switch (parent_opts[opt_id].type) {
+    case DP_OPT_STRING:
+        parent_val = dp_opt_get_cstring(parent_opts, opt_id);
+        break;
+    case DP_OPT_BOOL:
+        /* For booleans it is hard to say if the option is set or not since
+         * both possible values are valid ones. So we check if the value is
+         * different from the default and skip if it is the default. In this
+         * case the sub-domain option would either be the default as well or
+         * manully set and in both cases we do not have to change it. */
+        is_default = (parent_opts[opt_id].val.boolean
+                                == parent_opts[opt_id].def_val.boolean);
+        break;
+    default:
+        DEBUG(SSSDBG_TRACE_FUNC, "Unsupported type, skipping.\n");
+    }
+
+    if (parent_val != NULL || !is_default) {
         ret = confdb_get_string(cdb, NULL, subdom_conf_path,
                                 parent_opts[opt_id].opt_name, NULL, &dummy);
         if (ret != EOK) {
-- 
2.32.0


From 8eae4d550f9f4024166f4abe190a56c00ffa4c2b Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 26 Sep 2019 20:27:09 +0200
Subject: [PATCH 4/7] ad: add ad_use_ldaps
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

With this new boolean option the AD provider should only use the LDAPS
port 636 and the Global Catalog port 3629 which is TLS protected as
well.

Related to https://pagure.io/SSSD/sssd/issue/4131

(cherry picked from commit 33c8757087b8649926e53cf494e2a775ad100302)

Reviewed-by: Pavel Březina <pbrezina@redhat.com>
(cherry picked from commit b2aca1f7d7aa4a11f86d977ad00481aeb1f9a436)
---
 src/config/SSSDConfig/__init__.py.in      |  1 +
 src/config/cfg_rules.ini                  |  1 +
 src/config/etc/sssd.api.d/sssd-ad.conf    |  1 +
 src/man/sssd-ad.5.xml                     | 20 +++++++++++++++++++
 src/providers/ad/ad_common.c              | 24 +++++++++++++++++++----
 src/providers/ad/ad_common.h              |  8 +++++++-
 src/providers/ad/ad_init.c                |  8 +++++++-
 src/providers/ad/ad_opts.c                |  1 +
 src/providers/ad/ad_srv.c                 | 16 ++++++++++++---
 src/providers/ad/ad_srv.h                 |  3 ++-
 src/providers/ad/ad_subdomains.c          | 21 ++++++++++++++++++--
 src/providers/ipa/ipa_subdomains_server.c |  4 ++--
 12 files changed, 94 insertions(+), 14 deletions(-)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 6e6073f1c..e19d45101 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -247,6 +247,7 @@ option_strings = {
     'ad_maximum_machine_account_password_age' : _('Maximum age in days before the machine account password should be renewed'),
     'ad_machine_account_password_renewal_opts' : _('Option for tuning the machine account renewal task'),
     'ad_update_samba_machine_account_password' : _('Whether to update the machine account password in the Samba database'),
+    'ad_use_ldaps' : _('Use LDAPS port for LDAP and Global Catalog requests'),
 
     # [provider/krb5]
     'krb5_kdcip' : _('Kerberos server address'),
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 95898caa6..500271dae 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -451,6 +451,7 @@ option = ad_maximum_machine_account_password_age
 option = ad_server
 option = ad_site
 option = ad_update_samba_machine_account_password
+option = ad_use_ldaps
 
 # IPA provider specific options
 option = ipa_anchor_uuid
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index 9c6c6daad..0f98080a0 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -21,6 +21,7 @@ ad_site = str, None, false
 ad_maximum_machine_account_password_age = int, None, false
 ad_machine_account_password_renewal_opts = str, None, false
 ad_update_samba_machine_account_password = bool, None, false
+ad_use_ldaps = bool, None, false
 ldap_uri = str, None, false
 ldap_backup_uri = str, None, false
 ldap_search_base = str, None, false
diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
index 664f9eccb..34e1bb955 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -888,6 +888,26 @@ ad_gpo_map_deny = +my_pam_service
                     </listitem>
                 </varlistentry>
 
+                <varlistentry>
+                    <term>ad_use_ldaps (bool)</term>
+                    <listitem>
+                        <para>
+                            By default SSSD uses the plain LDAP port 389 and the
+                            Global Catalog port 3628. If this option is set to
+                            True SSSD will use the LDAPS port 636 and Global
+                            Catalog port 3629 with LDAPS protection. Since AD
+                            does not allow to have multiple encryption layers on
+                            a single connection and we still want to use
+                            SASL/GSSAPI or SASL/GSS-SPNEGO for authentication
+                            the SASL security property maxssf is set to 0 (zero)
+                            for those connections.
+                        </para>
+                        <para>
+                            Default: False
+                        </para>
+                    </listitem>
+                </varlistentry>
+
                 <varlistentry>
                     <term>dyndns_update (boolean)</term>
                     <listitem>
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index de81b1735..435524e5b 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -762,6 +762,7 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
                  const char *ad_service,
                  const char *ad_gc_service,
                  const char *ad_domain,
+                 bool ad_use_ldaps,
                  struct ad_service **_service)
 {
     errno_t ret;
@@ -777,6 +778,16 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
         goto done;
     }
 
+    if (ad_use_ldaps) {
+        service->ldap_scheme = "ldaps";
+        service->port = LDAPS_PORT;
+        service->gc_port = AD_GC_LDAPS_PORT;
+    } else {
+        service->ldap_scheme = "ldap";
+        service->port = LDAP_PORT;
+        service->gc_port = AD_GC_PORT;
+    }
+
     service->sdap = talloc_zero(service, struct sdap_service);
     service->gc = talloc_zero(service, struct sdap_service);
     if (!service->sdap || !service->gc) {
@@ -940,7 +951,8 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
         goto done;
     }
 
-    new_uri = talloc_asprintf(service->sdap, "ldap://%s", srv_name);
+    new_uri = talloc_asprintf(service->sdap, "%s://%s", service->ldap_scheme,
+                                                        srv_name);
     if (!new_uri) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy URI\n");
         ret = ENOMEM;
@@ -948,7 +960,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
     }
     DEBUG(SSSDBG_CONF_SETTINGS, "Constructed uri '%s'\n", new_uri);
 
-    sockaddr = resolv_get_sockaddr_address(tmp_ctx, srvaddr, LDAP_PORT);
+    sockaddr = resolv_get_sockaddr_address(tmp_ctx, srvaddr, service->port);
     if (sockaddr == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, "resolv_get_sockaddr_address failed.\n");
         ret = EIO;
@@ -964,8 +976,12 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
     talloc_zfree(service->gc->uri);
     talloc_zfree(service->gc->sockaddr);
     if (sdata && sdata->gc) {
-        new_port = fo_get_server_port(server);
-        new_port = (new_port == 0) ? AD_GC_PORT : new_port;
+        if (service->gc_port == AD_GC_LDAPS_PORT) {
+            new_port = service->gc_port;
+        } else {
+            new_port = fo_get_server_port(server);
+            new_port = (new_port == 0) ? service->gc_port : new_port;
+        }
 
         service->gc->uri = talloc_asprintf(service->gc, "%s:%d",
                                            new_uri, new_port);
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index 82a58affe..1eed0b0dd 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -29,7 +29,8 @@
 #define AD_SERVICE_NAME    "AD"
 #define AD_GC_SERVICE_NAME "AD_GC"
 /* The port the Global Catalog runs on */
-#define AD_GC_PORT      3268
+#define AD_GC_PORT         3268
+#define AD_GC_LDAPS_PORT   3269
 
 #define AD_AT_OBJECT_SID "objectSID"
 #define AD_AT_DNS_DOMAIN "DnsDomain"
@@ -67,6 +68,7 @@ enum ad_basic_opt {
     AD_MAXIMUM_MACHINE_ACCOUNT_PASSWORD_AGE,
     AD_MACHINE_ACCOUNT_PASSWORD_RENEWAL_OPTS,
     AD_UPDATE_SAMBA_MACHINE_ACCOUNT_PASSWORD,
+    AD_USE_LDAPS,
 
     AD_OPTS_BASIC /* opts counter */
 };
@@ -82,6 +84,9 @@ struct ad_service {
     struct sdap_service *sdap;
     struct sdap_service *gc;
     struct krb5_service *krb5_service;
+    const char *ldap_scheme;
+    int port;
+    int gc_port;
 };
 
 struct ad_options {
@@ -143,6 +148,7 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
                  const char *ad_service,
                  const char *ad_gc_service,
                  const char *ad_domain,
+                 bool ad_use_ldaps,
                  struct ad_service **_service);
 
 errno_t
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index cbe61da80..7f171cb5e 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -138,6 +138,7 @@ static errno_t ad_init_options(TALLOC_CTX *mem_ctx,
     char *ad_servers = NULL;
     char *ad_backup_servers = NULL;
     char *ad_realm;
+    bool ad_use_ldaps = false;
     errno_t ret;
 
     ad_sasl_initialize();
@@ -154,11 +155,13 @@ static errno_t ad_init_options(TALLOC_CTX *mem_ctx,
     ad_servers = dp_opt_get_string(ad_options->basic, AD_SERVER);
     ad_backup_servers = dp_opt_get_string(ad_options->basic, AD_BACKUP_SERVER);
     ad_realm = dp_opt_get_string(ad_options->basic, AD_KRB5_REALM);
+    ad_use_ldaps = dp_opt_get_bool(ad_options->basic, AD_USE_LDAPS);
 
     /* Set up the failover service */
     ret = ad_failover_init(ad_options, be_ctx, ad_servers, ad_backup_servers,
                            ad_realm, AD_SERVICE_NAME, AD_GC_SERVICE_NAME,
                            dp_opt_get_string(ad_options->basic, AD_DOMAIN),
+                           ad_use_ldaps,
                            &ad_options->service);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init AD failover service: "
@@ -181,11 +184,13 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx,
     const char *ad_site_override;
     bool sites_enabled;
     errno_t ret;
+    bool ad_use_ldaps;
 
     hostname = dp_opt_get_string(ad_options->basic, AD_HOSTNAME);
     ad_domain = dp_opt_get_string(ad_options->basic, AD_DOMAIN);
     ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
     sites_enabled = dp_opt_get_bool(ad_options->basic, AD_ENABLE_DNS_SITES);
+    ad_use_ldaps = dp_opt_get_bool(ad_options->basic, AD_USE_LDAPS);
 
 
     if (!sites_enabled) {
@@ -202,7 +207,8 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx,
     srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res,
                                      default_host_dbs, ad_options->id,
                                      hostname, ad_domain,
-                                     ad_site_override);
+                                     ad_site_override,
+                                     ad_use_ldaps);
     if (srv_ctx == NULL) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
         return ENOMEM;
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index d4fc811d9..8d1320d21 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -53,6 +53,7 @@ struct dp_option ad_basic_opts[] = {
     { "ad_maximum_machine_account_password_age", DP_OPT_NUMBER, { .number = 30 }, NULL_NUMBER },
     { "ad_machine_account_password_renewal_opts", DP_OPT_STRING, { "86400:750" }, NULL_STRING },
     { "ad_update_samba_machine_account_password", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+    { "ad_use_ldaps", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     DP_OPTION_TERMINATOR
 };
 
diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
index 4fa166860..4056d3e70 100644
--- a/src/providers/ad/ad_srv.c
+++ b/src/providers/ad/ad_srv.c
@@ -237,6 +237,7 @@ struct ad_get_client_site_state {
     enum host_database *host_db;
     struct sdap_options *opts;
     const char *ad_domain;
+    bool ad_use_ldaps;
     struct fo_server_info *dcs;
     size_t num_dcs;
     size_t dc_index;
@@ -257,6 +258,7 @@ struct tevent_req *ad_get_client_site_send(TALLOC_CTX *mem_ctx,
                                            enum host_database *host_db,
                                            struct sdap_options *opts,
                                            const char *ad_domain,
+                                           bool ad_use_ldaps,
                                            struct fo_server_info *dcs,
                                            size_t num_dcs)
 {
@@ -281,6 +283,7 @@ struct tevent_req *ad_get_client_site_send(TALLOC_CTX *mem_ctx,
     state->host_db = host_db;
     state->opts = opts;
     state->ad_domain = ad_domain;
+    state->ad_use_ldaps = ad_use_ldaps;
     state->dcs = dcs;
     state->num_dcs = num_dcs;
 
@@ -324,8 +327,11 @@ static errno_t ad_get_client_site_next_dc(struct tevent_req *req)
     subreq = sdap_connect_host_send(state, state->ev, state->opts,
                                     state->be_res->resolv,
                                     state->be_res->family_order,
-                                    state->host_db, "ldap", state->dc.host,
-                                    state->dc.port, false);
+                                    state->host_db,
+                                    state->ad_use_ldaps ? "ldaps" : "ldap",
+                                    state->dc.host,
+                                    state->ad_use_ldaps ? 636 : state->dc.port,
+                                    false);
     if (subreq == NULL) {
         ret = ENOMEM;
         goto done;
@@ -484,6 +490,7 @@ struct ad_srv_plugin_ctx {
     const char *ad_domain;
     const char *ad_site_override;
     const char *current_site;
+    bool ad_use_ldaps;
 };
 
 struct ad_srv_plugin_ctx *
@@ -494,7 +501,8 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
                        struct sdap_options *opts,
                        const char *hostname,
                        const char *ad_domain,
-                       const char *ad_site_override)
+                       const char *ad_site_override,
+                       bool ad_use_ldaps)
 {
     struct ad_srv_plugin_ctx *ctx = NULL;
     errno_t ret;
@@ -508,6 +516,7 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
     ctx->be_res = be_res;
     ctx->host_dbs = host_dbs;
     ctx->opts = opts;
+    ctx->ad_use_ldaps = ad_use_ldaps;
 
     ctx->hostname = talloc_strdup(ctx, hostname);
     if (ctx->hostname == NULL) {
@@ -707,6 +716,7 @@ static void ad_srv_plugin_dcs_done(struct tevent_req *subreq)
                                      state->ctx->host_dbs,
                                      state->ctx->opts,
                                      state->discovery_domain,
+                                     state->ctx->ad_use_ldaps,
                                      dcs, num_dcs);
     if (subreq == NULL) {
         ret = ENOMEM;
diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h
index fddef6867..59377e096 100644
--- a/src/providers/ad/ad_srv.h
+++ b/src/providers/ad/ad_srv.h
@@ -31,7 +31,8 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
                        struct sdap_options *opts,
                        const char *hostname,
                        const char *ad_domain,
-                       const char *ad_site_override);
+                       const char *ad_site_override,
+                       bool ad_use_ldaps);
 
 struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 3788b15ae..1205faea1 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -249,6 +249,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
     const char *hostname;
     const char *keytab;
     char *subdom_conf_path;
+    bool ad_use_ldaps = false;
 
     realm = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_KRB5_REALM);
     hostname = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_HOSTNAME);
@@ -275,6 +276,21 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
         return ENOMEM;
     }
 
+    ret = ad_inherit_opts_if_needed(id_ctx->ad_options->basic,
+                                    ad_options->basic,
+                                    be_ctx->cdb, subdom_conf_path,
+                                    AD_USE_LDAPS);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Failed to inherit option [%s] to sub-domain [%s]. "
+              "This error is ignored but might cause issues or unexpected "
+              "behavior later on.\n",
+              id_ctx->ad_options->basic[AD_USE_LDAPS].opt_name,
+              subdom->name);
+
+        return ret;
+    }
+
     ret = ad_inherit_opts_if_needed(id_ctx->sdap_id_ctx->opts->basic,
                                     ad_options->id->basic,
                                     be_ctx->cdb, subdom_conf_path,
@@ -307,10 +323,11 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
 
     servers = dp_opt_get_string(ad_options->basic, AD_SERVER);
     backup_servers = dp_opt_get_string(ad_options->basic, AD_BACKUP_SERVER);
+    ad_use_ldaps = dp_opt_get_bool(ad_options->basic, AD_USE_LDAPS);
 
     ret = ad_failover_init(ad_options, be_ctx, servers, backup_servers, realm,
                            service_name, gc_service_name,
-                           subdom->name, &ad_options->service);
+                           subdom->name, ad_use_ldaps, &ad_options->service);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
         talloc_free(ad_options);
@@ -331,7 +348,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
                                      ad_id_ctx->ad_options->id,
                                      hostname,
                                      ad_domain,
-                                     ad_site_override);
+                                     ad_site_override, ad_use_ldaps);
     if (srv_ctx == NULL) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
         return ENOMEM;
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index 9be726060..40ded9442 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -304,7 +304,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
     ret = ad_failover_init(ad_options, be_ctx, ad_servers, ad_backup_servers,
                            id_ctx->server_mode->realm,
                            service_name, gc_service_name,
-                           subdom->name, &ad_options->service);
+                           subdom->name, false, &ad_options->service);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
         talloc_free(ad_options);
@@ -327,7 +327,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
                                      ad_id_ctx->ad_options->id,
                                      id_ctx->server_mode->hostname,
                                      ad_domain,
-                                     ad_site_override);
+                                     ad_site_override, false);
     if (srv_ctx == NULL) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
         return ENOMEM;
-- 
2.32.0


From 065a8658952f82e4e73569fe362da02b8de7778c Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 27 Sep 2019 11:49:59 +0200
Subject: [PATCH 5/7] ldap: add new option ldap_sasl_maxssf
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

There is already the ldap_sasl_minssf option. To be able to control the
maximal security strength factor (ssf) e.g. when using SASL together
with TLS the option ldap_sasl_maxssf is added as well.

Related to https://pagure.io/SSSD/sssd/issue/4131

(cherry picked from commit 3b95c39819591428b1e535e5dc874268cf5630c5)

Reviewed-by: Pavel Březina <pbrezina@redhat.com>
(cherry picked from commit 07d19249a88d90135dce21e3d112caf70629ef02)
---
 src/config/SSSDConfig/__init__.py.in       |  1 +
 src/config/cfg_rules.ini                   |  1 +
 src/config/etc/sssd.api.d/sssd-ad.conf     |  1 +
 src/config/etc/sssd.api.d/sssd-ipa.conf    |  1 +
 src/config/etc/sssd.api.d/sssd-ldap.conf   |  1 +
 src/man/sssd-ldap.5.xml                    | 16 ++++++++++++++++
 src/providers/ad/ad_opts.c                 |  1 +
 src/providers/ipa/ipa_opts.c               |  1 +
 src/providers/ldap/ldap_opts.c             |  1 +
 src/providers/ldap/sdap.h                  |  1 +
 src/providers/ldap/sdap_async_connection.c | 14 ++++++++++++++
 11 files changed, 39 insertions(+)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index e19d45101..8b34acf6f 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -299,6 +299,7 @@ option_strings = {
     'ldap_sasl_authid' : _('Specify the sasl authorization id to use'),
     'ldap_sasl_realm' : _('Specify the sasl authorization realm to use'),
     'ldap_sasl_minssf' : _('Specify the minimal SSF for LDAP sasl authorization'),
+    'ldap_sasl_maxssf' : _('Specify the maximal SSF for LDAP sasl authorization'),
     'ldap_krb5_keytab' : _('Kerberos service keytab'),
     'ldap_krb5_init_creds' : _('Use Kerberos auth for LDAP connection'),
     'ldap_referrals' : _('Follow LDAP referrals'),
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 500271dae..074169389 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -652,6 +652,7 @@ option = ldap_sasl_authid
 option = ldap_sasl_canonicalize
 option = ldap_sasl_mech
 option = ldap_sasl_minssf
+option = ldap_sasl_maxssf
 option = ldap_schema
 option = ldap_search_base
 option = ldap_search_timeout
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index 0f98080a0..41bbd2014 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -41,6 +41,7 @@ ldap_tls_reqcert = str, None, false
 ldap_sasl_mech = str, None, false
 ldap_sasl_authid = str, None, false
 ldap_sasl_minssf = int, None, false
+ldap_sasl_maxssf = int, None, false
 krb5_kdcip = str, None, false
 krb5_server = str, None, false
 krb5_backup_server = str, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index ab9634c7a..427559f5d 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -31,6 +31,7 @@ ldap_tls_reqcert = str, None, false
 ldap_sasl_mech = str, None, false
 ldap_sasl_authid = str, None, false
 ldap_sasl_minssf = int, None, false
+ldap_sasl_maxssf = int, None, false
 krb5_kdcip = str, None, false
 krb5_server = str, None, false
 krb5_backup_server = str, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index 65b6407f6..bd6cc7d7f 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -34,6 +34,7 @@ ldap_page_size = int, None, false
 ldap_deref_threshold = int, None, false
 ldap_sasl_canonicalize = bool, None, false
 ldap_sasl_minssf = int, None, false
+ldap_sasl_maxssf = int, None, false
 ldap_connection_expire_timeout = int, None, false
 ldap_disable_paging = bool, None, false
 ldap_disable_range_retrieval = bool, None, false
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 691678fc7..a0f64cbfd 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1553,6 +1553,22 @@
                     </listitem>
                 </varlistentry>
 
+                <varlistentry>
+                    <term>ldap_sasl_maxssf (integer)</term>
+                    <listitem>
+                        <para>
+                            When communicating with an LDAP server using SASL,
+                            specify the maximal security level necessary to
+                            establish the connection. The values of this
+                            option are defined by OpenLDAP.
+                        </para>
+                        <para>
+                            Default: Use the system default (usually specified
+                            by ldap.conf)
+                        </para>
+                    </listitem>
+                </varlistentry>
+
                 <varlistentry>
                     <term>ldap_deref_threshold (integer)</term>
                     <listitem>
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index 8d1320d21..395d3fd58 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -103,6 +103,7 @@ struct dp_option ad_def_ldap_opts[] = {
     { "ldap_sasl_authid", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sasl_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sasl_minssf", DP_OPT_NUMBER, { .number = -1 }, NULL_NUMBER },
+    { "ldap_sasl_maxssf", DP_OPT_NUMBER, { .number = -1 }, NULL_NUMBER },
     { "ldap_krb5_keytab", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
     /* use the same parm name as the krb5 module so we set it only once */
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index 9419cdcc3..82b2f6312 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -112,6 +112,7 @@ struct dp_option ipa_def_ldap_opts[] = {
     { "ldap_sasl_authid", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sasl_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sasl_minssf", DP_OPT_NUMBER, { .number = 56 }, NULL_NUMBER },
+    { "ldap_sasl_maxssf", DP_OPT_NUMBER, { .number = -1 }, NULL_NUMBER },
     { "ldap_krb5_keytab", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
     /* use the same parm name as the krb5 module so we set it only once */
diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
index 8b82e92ee..b63f0a3a5 100644
--- a/src/providers/ldap/ldap_opts.c
+++ b/src/providers/ldap/ldap_opts.c
@@ -73,6 +73,7 @@ struct dp_option default_basic_opts[] = {
     { "ldap_sasl_authid", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sasl_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sasl_minssf", DP_OPT_NUMBER, { .number = -1 }, NULL_NUMBER },
+    { "ldap_sasl_maxssf", DP_OPT_NUMBER, { .number = -1 }, NULL_NUMBER },
     { "ldap_krb5_keytab", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
     /* use the same parm name as the krb5 module so we set it only once */
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 0ee877b19..6c6e5d770 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -190,6 +190,7 @@ enum sdap_basic_opt {
     SDAP_SASL_AUTHID,
     SDAP_SASL_REALM,
     SDAP_SASL_MINSSF,
+    SDAP_SASL_MAXSSF,
     SDAP_KRB5_KEYTAB,
     SDAP_KRB5_KINIT,
     SDAP_KRB5_KDC,
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index f4ab8c1cc..30eb5ff43 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -148,6 +148,8 @@ static void sdap_sys_connect_done(struct tevent_req *subreq)
     const char *sasl_mech;
     int sasl_minssf;
     ber_len_t ber_sasl_minssf;
+    int sasl_maxssf;
+    ber_len_t ber_sasl_maxssf;
 
     ret = sss_ldap_init_recv(subreq, &state->sh->ldap, &sd);
     talloc_zfree(subreq);
@@ -291,6 +293,18 @@ static void sdap_sys_connect_done(struct tevent_req *subreq)
                 goto fail;
             }
         }
+
+        sasl_maxssf = dp_opt_get_int(state->opts->basic, SDAP_SASL_MAXSSF);
+        if (sasl_maxssf >= 0) {
+            ber_sasl_maxssf = (ber_len_t)sasl_maxssf;
+            lret = ldap_set_option(state->sh->ldap, LDAP_OPT_X_SASL_SSF_MAX,
+                                   &ber_sasl_maxssf);
+            if (lret != LDAP_OPT_SUCCESS) {
+                DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set LDAP MAX SSF option "
+                                            "to %d\n", sasl_maxssf);
+                goto fail;
+            }
+        }
     }
 
     /* if we do not use start_tls the connection is not really connected yet
-- 
2.32.0


From b90dd8b7370d00379e76c12bc3c3a3069f73ca4e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 27 Sep 2019 13:45:13 +0200
Subject: [PATCH 6/7] ad: set min and max ssf for ldaps
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

AD does not allow to use encryption in the TLS and SASL layer at the
same time. To be able to use ldaps this patch sets min and max ssf to 0
if ldaps should be used.

Related to https://pagure.io/SSSD/sssd/issue/4131

(cherry picked from commit 50a92f65c4823d272240ef416f2b05874b2b7918)

Reviewed-by: Pavel Březina <pbrezina@redhat.com>
(cherry picked from commit 9b875b87fda7dab1c92022b5c2e3b11cd5fffa4f)
---
 src/providers/ad/ad_common.c     | 21 +++++++++++++++++++++
 src/providers/ad/ad_common.h     |  2 ++
 src/providers/ad/ad_subdomains.c |  4 ++++
 3 files changed, 27 insertions(+)

diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 435524e5b..e1d6d64df 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -1044,6 +1044,23 @@ done:
     return;
 }
 
+void ad_set_ssf_for_ldaps(struct sdap_options *id_opts)
+{
+    int ret;
+
+    DEBUG(SSSDBG_TRACE_ALL, "Setting ssf for ldaps usage.\n");
+    ret = dp_opt_set_int(id_opts->basic, SDAP_SASL_MINSSF, 0);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Failed to set SASL minssf for ldaps usage, ignored.\n");
+    }
+    ret = dp_opt_set_int(id_opts->basic, SDAP_SASL_MAXSSF, 0);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Failed to set SASL maxssf for ldaps usage, ignored.\n");
+    }
+}
+
 static errno_t
 ad_set_sdap_options(struct ad_options *ad_opts,
                     struct sdap_options *id_opts)
@@ -1101,6 +1118,10 @@ ad_set_sdap_options(struct ad_options *ad_opts,
         goto done;
     }
 
+    if (dp_opt_get_bool(ad_opts->basic, AD_USE_LDAPS)) {
+        ad_set_ssf_for_ldaps(id_opts);
+    }
+
     /* fix schema to AD  */
     id_opts->schema_type = SDAP_SCHEMA_AD;
 
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index 1eed0b0dd..348f14dff 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -170,6 +170,8 @@ errno_t
 ad_get_dyndns_options(struct be_ctx *be_ctx,
                       struct ad_options *ad_opts);
 
+void ad_set_ssf_for_ldaps(struct sdap_options *id_opts);
+
 struct ad_id_ctx *
 ad_id_ctx_init(struct ad_options *ad_opts, struct be_ctx *bectx);
 
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 1205faea1..727022b53 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -291,6 +291,10 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
         return ret;
     }
 
+    if (dp_opt_get_bool(ad_options->basic, AD_USE_LDAPS)) {
+        ad_set_ssf_for_ldaps(ad_options->id);
+    }
+
     ret = ad_inherit_opts_if_needed(id_ctx->sdap_id_ctx->opts->basic,
                                     ad_options->id->basic,
                                     be_ctx->cdb, subdom_conf_path,
-- 
2.32.0


From f2a089d77ec1c7706d92b3be1f1483098709034d Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 16 Mar 2020 17:49:02 +0100
Subject: [PATCH 7/7] ad: use GSSAPI with LDAPS
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

There is an issue in some cyrus-sasl versions with a max SSF of 0 (zero)
is not handled correctly when using GSS-SPNEGO. To be on the safe side
we switch to GSSAPI in that case.

Related to https://pagure.io/SSSD/sssd/issue/4007

Reviewed-by: Pavel Březina <pbrezina@redhat.com>
(cherry picked from commit ac7248e83a6d020d609d9a8433d45a684b98645a)
---
 src/providers/ad/ad_common.c     | 17 ++++++++++++++---
 src/providers/ad/ad_common.h     |  2 +-
 src/providers/ad/ad_subdomains.c |  2 +-
 3 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index e1d6d64df..b8daec216 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -1044,11 +1044,11 @@ done:
     return;
 }
 
-void ad_set_ssf_for_ldaps(struct sdap_options *id_opts)
+void ad_set_ssf_and_mech_for_ldaps(struct sdap_options *id_opts)
 {
     int ret;
 
-    DEBUG(SSSDBG_TRACE_ALL, "Setting ssf for ldaps usage.\n");
+    DEBUG(SSSDBG_TRACE_ALL, "Setting ssf and mech for ldaps usage.\n");
     ret = dp_opt_set_int(id_opts->basic, SDAP_SASL_MINSSF, 0);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
@@ -1059,6 +1059,17 @@ void ad_set_ssf_for_ldaps(struct sdap_options *id_opts)
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Failed to set SASL maxssf for ldaps usage, ignored.\n");
     }
+
+    /* There is an issue in cyrus-sasl with respect to GSS-SPNEGO and
+     * maxssf==0. Until the fix
+     * https://github.com/cyrusimap/cyrus-sasl/pull/603 is widely used we
+     * switch to GSSAPI by default when using AD with LDAPS where maxssf==0 is
+     * required. */
+    ret = dp_opt_set_string(id_opts->basic, SDAP_SASL_MECH, "GSSAPI");
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Failed to set SASL mech for ldaps usage, ignored.\n");
+    }
 }
 
 static errno_t
@@ -1119,7 +1130,7 @@ ad_set_sdap_options(struct ad_options *ad_opts,
     }
 
     if (dp_opt_get_bool(ad_opts->basic, AD_USE_LDAPS)) {
-        ad_set_ssf_for_ldaps(id_opts);
+        ad_set_ssf_and_mech_for_ldaps(id_opts);
     }
 
     /* fix schema to AD  */
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index 348f14dff..b59799a65 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -170,7 +170,7 @@ errno_t
 ad_get_dyndns_options(struct be_ctx *be_ctx,
                       struct ad_options *ad_opts);
 
-void ad_set_ssf_for_ldaps(struct sdap_options *id_opts);
+void ad_set_ssf_and_mech_for_ldaps(struct sdap_options *id_opts);
 
 struct ad_id_ctx *
 ad_id_ctx_init(struct ad_options *ad_opts, struct be_ctx *bectx);
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 727022b53..3ac34ed04 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -292,7 +292,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
     }
 
     if (dp_opt_get_bool(ad_options->basic, AD_USE_LDAPS)) {
-        ad_set_ssf_for_ldaps(ad_options->id);
+        ad_set_ssf_and_mech_for_ldaps(ad_options->id);
     }
 
     ret = ad_inherit_opts_if_needed(id_ctx->sdap_id_ctx->opts->basic,
-- 
2.32.0

openSUSE Build Service is sponsored by