Blob Blame History Raw
From b2aca1f7d7aa4a11f86d977ad00481aeb1f9a436 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 26 Sep 2019 20:27:09 +0200
Subject: [PATCH 107/109] 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>
---
 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 a7de476a1..00e588f1c 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -247,6 +247,7 @@ option_strings = {
     'ad_site' : _('a particular site to be used by the client'),
     '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_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 3976ec4e1..c3d8bd88f 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -454,6 +454,7 @@ option = ad_machine_account_password_renewal_opts
 option = ad_maximum_machine_account_password_age
 option = ad_server
 option = ad_site
+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 e3c8140b8..48522437f 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -20,6 +20,7 @@ ad_gpo_default_right = str, None, false
 ad_site = str, None, false
 ad_maximum_machine_account_password_age = int, None, false
 ad_machine_account_password_renewal_opts = str, 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 b14f07f7f..9e9e52eb3 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -903,6 +903,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 ca4d0665d..de8a0c8bb 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -729,6 +729,7 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
                  const char *ad_gc_service,
                  const char *ad_domain,
                  bool use_kdcinfo,
+                 bool ad_use_ldaps,
                  size_t n_lookahead_primary,
                  size_t n_lookahead_backup,
                  struct ad_service **_service)
@@ -746,6 +747,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) {
@@ -914,7 +925,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;
@@ -922,7 +934,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;
@@ -938,8 +950,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 44369288e..54245b9f8 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_KRB5_CONFD_PATH,
     AD_MAXIMUM_MACHINE_ACCOUNT_PASSWORD_AGE,
     AD_MACHINE_ACCOUNT_PASSWORD_RENEWAL_OPTS,
+    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 {
@@ -147,6 +152,7 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
                  const char *ad_gc_service,
                  const char *ad_domain,
                  bool use_kdcinfo,
+                 bool ad_use_ldaps,
                  size_t n_lookahead_primary,
                  size_t n_lookahead_backup,
                  struct ad_service **_service);
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index f5aea8904..09397852b 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,12 +155,14 @@ 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),
                            false, /* will be set in ad_get_auth_options() */
+                           ad_use_ldaps,
                            (size_t) -1,
                            (size_t) -1,
                            &ad_options->service);
@@ -184,11 +187,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) {
@@ -205,7 +210,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 9bd705445..cd898cbd2 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -54,6 +54,7 @@ struct dp_option ad_basic_opts[] = {
     { "krb5_confd_path", DP_OPT_STRING, { KRB5_MAPPING_DIR }, NULL_STRING },
     { "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_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 5fd25f60e..ca15d3715 100644
--- a/src/providers/ad/ad_srv.c
+++ b/src/providers/ad/ad_srv.c
@@ -244,6 +244,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;
@@ -264,6 +265,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)
 {
@@ -288,6 +290,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;
 
@@ -331,8 +334,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;
@@ -491,6 +497,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 *
@@ -501,7 +508,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;
@@ -515,6 +523,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) {
@@ -714,6 +723,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 e553d594d..8e410ec26 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 f0b5d59d2..bc10da5bc 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -282,6 +282,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
     bool use_kdcinfo = false;
     size_t n_lookahead_primary = SSS_KRB5_LOOKAHEAD_PRIMARY_DEFAULT;
     size_t n_lookahead_backup = SSS_KRB5_LOOKAHEAD_BACKUP_DEFAULT;
+    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);
@@ -312,6 +313,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,
@@ -344,6 +360,7 @@ 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);
 
     if (id_ctx->ad_options->auth_ctx != NULL
             && id_ctx->ad_options->auth_ctx->opts != NULL) {
@@ -362,7 +379,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
 
     ret = ad_failover_init(ad_options, be_ctx, servers, backup_servers,
                            subdom->realm, service_name, gc_service_name,
-                           subdom->name, use_kdcinfo,
+                           subdom->name, use_kdcinfo, ad_use_ldaps,
                            n_lookahead_primary,
                            n_lookahead_backup,
                            &ad_options->service);
@@ -386,7 +403,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 d0e89a4f9..e2037b59d 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -319,7 +319,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
     ret = ad_failover_init(ad_options, be_ctx, ad_servers, ad_backup_servers,
                            subdom->realm,
                            service_name, gc_service_name,
-                           subdom->name, use_kdcinfo,
+                           subdom->name, use_kdcinfo, false,
                            n_lookahead_primary, n_lookahead_backup,
                            &ad_options->service);
     if (ret != EOK) {
@@ -344,7 +344,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.20.1