From 864ed28ce0e2d4b6712cf742f2dadd2aee445b9d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 30 Jan 2024 10:27:58 +0100 Subject: [PATCH] s3:libads: add support for ADS_AUTH_SASL_{STARTTLS,LDAPS} Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- source3/libads/ads_struct.c | 15 +++++-- source3/libads/ldap.c | 84 +++++++++++++++++++++++++++++++++++++ source3/libads/sasl.c | 22 ++++++++-- 3 files changed, 115 insertions(+), 6 deletions(-) diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c index 97f84d124d0..55f55e7e364 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -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; diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 211a18472a8..e597f78597f 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -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); diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c index ee48b0781ed..32331d9ff6b 100644 --- a/source3/libads/sasl.c +++ b/source3/libads/sasl.c @@ -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 " -- 2.47.3