s3:libads: add support for ADS_AUTH_SASL_{STARTTLS,LDAPS}
authorStefan Metzmacher <metze@samba.org>
Tue, 30 Jan 2024 09:27:58 +0000 (10:27 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 23 Apr 2024 23:50:34 +0000 (23:50 +0000)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source3/libads/ads_struct.c
source3/libads/ldap.c
source3/libads/sasl.c

index 97f84d124d07f06a0453fd81b55c27aec5f82f70..55f55e7e3643a6b2b8ef055ab9c9b88d12657e2f 100644 (file)
@@ -196,8 +196,11 @@ ADS_STRUCT *ads_init(TALLOC_CTX *mem_ctx,
        }
 
        wrap_flags = lp_client_ldap_sasl_wrapping();
-       if (wrap_flags == -1) {
-               wrap_flags = 0;
+
+       if (wrap_flags & ADS_AUTH_SASL_LDAPS) {
+               sasl_state = ADS_SASL_PLAIN;
+       } else if (wrap_flags & ADS_AUTH_SASL_STARTTLS) {
+               sasl_state = ADS_SASL_PLAIN;
        }
 
        switch (sasl_state) {
@@ -225,13 +228,19 @@ ADS_STRUCT *ads_init(TALLOC_CTX *mem_ctx,
 
 bool ads_set_sasl_wrap_flags(ADS_STRUCT *ads, unsigned flags)
 {
+       unsigned reset_flags;
        unsigned other_flags;
 
        if (!ads) {
                return false;
        }
 
-       other_flags = ads->auth.flags & ~(ADS_AUTH_SASL_SIGN|ADS_AUTH_SASL_SEAL);
+       reset_flags = ADS_AUTH_SASL_SIGN |
+                     ADS_AUTH_SASL_SEAL |
+                     ADS_AUTH_SASL_LDAPS |
+                     ADS_AUTH_SASL_STARTTLS;
+
+       other_flags = ads->auth.flags & ~reset_flags;
 
        ads->auth.flags = flags | other_flags;
 
index 211a18472a8397d5e5866e2d9c3bb4fd3e77c984..e597f78597f007b08309b69348ad36ed989653ce 100644 (file)
@@ -822,6 +822,8 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
        NTSTATUS ntstatus;
        char addr[INET6_ADDRSTRLEN];
        struct sockaddr_storage existing_ss;
+       bool tls = false;
+       bool start_tls = false;
 
        zero_sockaddr(&existing_ss);
 
@@ -982,6 +984,17 @@ got_connection:
 
        /* Otherwise setup the TCP LDAP session */
 
+       if (ads->auth.flags & ADS_AUTH_SASL_LDAPS) {
+               tls = true;
+               ads->ldap.port = 636;
+       } else if (ads->auth.flags & ADS_AUTH_SASL_STARTTLS) {
+               tls = true;
+               start_tls = true;
+               ads->ldap.port = 389;
+       } else {
+               ads->ldap.port = 389;
+       }
+
        ads->ldap.ld = ldap_open_with_timeout(ads->config.ldap_server_name,
                                              &ads->ldap.ss,
                                              ads->ldap.port, lp_ldap_timeout());
@@ -993,6 +1006,77 @@ got_connection:
 
        ldap_set_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
 
+       if (start_tls) {
+               unsigned int to = lp_ldap_connection_timeout();
+               struct berval *rspdata = NULL;
+               char *rspoid = NULL;
+               int rc;
+
+               if (to) {
+                       /* Setup timeout */
+                       gotalarm = 0;
+                       CatchSignal(SIGALRM, gotalarm_sig);
+                       alarm(to);
+                       /* End setup timeout. */
+               }
+
+               rc = ldap_extended_operation_s(ads->ldap.ld,
+                                              LDAP_EXOP_START_TLS,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              &rspoid,
+                                              &rspdata);
+               if (gotalarm != 0 && rc == LDAP_SUCCESS) {
+                       rc = LDAP_TIMEOUT;
+               }
+
+               if (to) {
+                       /* Teardown timeout. */
+                       alarm(0);
+                       CatchSignal(SIGALRM, SIG_IGN);
+               }
+
+               if (rspoid != NULL) {
+                       ldap_memfree(rspoid);
+               }
+
+               if (rspdata != NULL) {
+                       ber_bvfree(rspdata);
+               }
+
+               if (rc != LDAP_SUCCESS) {
+                       status = ADS_ERROR_LDAP(rc);
+                       goto out;
+               }
+       }
+
+       if (tls) {
+               unsigned int to = lp_ldap_connection_timeout();
+
+               if (to) {
+                       /* Setup timeout */
+                       gotalarm = 0;
+                       CatchSignal(SIGALRM, gotalarm_sig);
+                       alarm(to);
+                       /* End setup timeout. */
+               }
+
+               status = ads_setup_tls_wrapping(&ads->ldap_tls_data,
+                                               ads->ldap.ld,
+                                               ads->config.ldap_server_name);
+
+               if (to) {
+                       /* Teardown timeout. */
+                       alarm(0);
+                       CatchSignal(SIGALRM, SIG_IGN);
+               }
+
+               if ( !ADS_ERR_OK(status) ) {
+                       goto out;
+               }
+       }
+
        /* cache the successful connection for workgroup and realm */
        if (ads_closest_dc(ads)) {
                saf_store( ads->server.workgroup, ads->config.ldap_server_name);
index ee48b0781ed90b7d934590b223f85e18a1d22ac9..32331d9ff6bd1575348b021ee60165e8b2d19d0a 100644 (file)
@@ -194,8 +194,6 @@ static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
                                    nt_errstr(nt_status));
                        return ADS_ERROR_NT(nt_status);
                }
-
-               wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
        }
 
        switch (wrap->wrap_type) {
@@ -607,8 +605,15 @@ ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
 {
        ADS_STATUS status;
        struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
+       bool tls = false;
 
-       if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
+       if (ads->auth.flags & ADS_AUTH_SASL_LDAPS) {
+               tls = true;
+               wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
+       } else if (ads->auth.flags & ADS_AUTH_SASL_STARTTLS) {
+               tls = true;
+               wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
+       } else if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
                wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
        } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
                wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
@@ -616,10 +621,21 @@ ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
                wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
        }
 
+       if (tls) {
+               const DATA_BLOB *tls_cb = NULL;
+
+               tls_cb = ads_tls_channel_bindings(&ads->ldap_tls_data);
+               if (tls_cb == NULL) {
+                       DBG_ERR("No TLS channel bindings available\n");
+                       return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+               }
+       }
+
 retry:
        status = ads_sasl_spnego_bind(ads);
        if (status.error_type == ENUM_ADS_ERROR_LDAP &&
            status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
+           !tls &&
            wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
        {
                DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "