s3:libads: add tls_wrapping into openldap
authorStefan Metzmacher <metze@samba.org>
Tue, 30 Jan 2024 09:27:58 +0000 (10:27 +0100)
committerStefan Metzmacher <metze@samba.org>
Thu, 15 Feb 2024 19:29:26 +0000 (20:29 +0100)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
source3/include/ads.h
source3/libads/ads_proto.h
source3/libads/ldap.c
source3/libads/tls_wrapping.c [new file with mode: 0644]
source3/wscript
source3/wscript_build

index 808554310a42dcdcf8b4d3941134717ec0895198..d2ed8860d3768755ea831875e50edf7b9a17d0e2 100644 (file)
@@ -55,6 +55,14 @@ struct ads_saslwrap {
        } out;
 };
 
+struct ads_tlswrap {
+       struct sockbuf_io_desc *sbiod;
+       struct TALLOC_CTX *mem_ctx;
+       struct timeval endtime;
+       struct tstream_tls_params *tls_params;
+       struct tstream_tls_sync *tls_sync;
+};
+
 typedef struct ads_struct {
        /* info needed to find the server */
        struct {
@@ -96,6 +104,7 @@ typedef struct ads_struct {
        /* info about the current LDAP connection */
 #ifdef HAVE_LDAP
        struct ads_saslwrap ldap_wrap_data;
+       struct ads_tlswrap ldap_tls_data;
        struct {
                LDAP *ld;
                struct sockaddr_storage ss; /* the ip of the active connection, if any */
index ce04ac2a2520882540a4ca415abfbd67659e3216..3f98e83fb9c7391b947a74b4cbbe7c79c52783af 100644 (file)
@@ -216,6 +216,16 @@ void ndr_print_ads_saslwrap_struct(struct ndr_print *ndr,
                                   const char *name,
                                   const struct ads_saslwrap *r);
 
+/* The following definitions come from libads/tls_wrapping.c  */
+
+void ndr_print_ads_tlswrap_struct(struct ndr_print *ndr,
+                                  const char *name,
+                                  const struct ads_tlswrap *r);
+ADS_STATUS ads_setup_tls_wrapping(struct ads_tlswrap *wrap,
+                                 LDAP *ld,
+                                 const char *server_name);
+const DATA_BLOB *ads_tls_channel_bindings(struct ads_tlswrap *wrap);
+
 /* The following definitions come from libads/util.c  */
 
 ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal);
index e7e34998f7414b4a4d5177943e8915cb9f8f6ace..ccbdd34ee0483ec60d854d0f26634e3b48ef96f5 100755 (executable)
@@ -676,6 +676,7 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
        }
 
        ads_zero_ldap(ads);
+       ZERO_STRUCT(ads->ldap_tls_data);
        ZERO_STRUCT(ads->ldap_wrap_data);
        ads->ldap.last_attempt  = time_mono(NULL);
        ads->ldap_wrap_data.wrap_type   = ADS_SASLWRAP_TYPE_PLAIN;
@@ -790,6 +791,12 @@ got_connection:
                goto out;
        }
 
+       ads->ldap_tls_data.mem_ctx = talloc_init("ads LDAP TLS connection memory");
+       if (!ads->ldap_tls_data.mem_ctx) {
+               status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+               goto out;
+       }
+
        ads->ldap_wrap_data.mem_ctx = talloc_init("ads LDAP connection memory");
        if (!ads->ldap_wrap_data.mem_ctx) {
                status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
@@ -889,6 +896,9 @@ void ads_disconnect(ADS_STRUCT *ads)
                ldap_unbind(ads->ldap.ld);
                ads->ldap.ld = NULL;
        }
+       if (ads->ldap_tls_data.mem_ctx) {
+               talloc_free(ads->ldap_tls_data.mem_ctx);
+       }
        if (ads->ldap_wrap_data.wrap_ops &&
                ads->ldap_wrap_data.wrap_ops->disconnect) {
                ads->ldap_wrap_data.wrap_ops->disconnect(&ads->ldap_wrap_data);
@@ -897,6 +907,7 @@ void ads_disconnect(ADS_STRUCT *ads)
                talloc_free(ads->ldap_wrap_data.mem_ctx);
        }
        ads_zero_ldap(ads);
+       ZERO_STRUCT(ads->ldap_tls_data);
        ZERO_STRUCT(ads->ldap_wrap_data);
 }
 
diff --git a/source3/libads/tls_wrapping.c b/source3/libads/tls_wrapping.c
new file mode 100644 (file)
index 0000000..12719e9
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+   Unix SMB/CIFS implementation.
+   ads tls wrapping code
+   Copyright (C) Stefan Metzmacher 2024
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ads.h"
+#include "lib/param/param.h"
+#include "../source4/lib/tls/tls.h"
+#include <gnutls/gnutls.h>
+
+void ndr_print_ads_tlswrap_struct(struct ndr_print *ndr, const char *name, const struct ads_tlswrap *r)
+{
+       ndr_print_struct(ndr, name, "tlswrap");
+       ndr->depth++;
+#ifdef HAVE_LDAP_TLS_WRAPPING
+       ndr_print_ptr(ndr, "sbiod", r->sbiod);
+       ndr_print_ptr(ndr, "mem_ctx", r->mem_ctx);
+       ndr_print_timeval(ndr, "endtime", &r->endtime);
+       ndr_print_ptr(ndr, "tls_params", r->tls_params);
+       ndr_print_ptr(ndr, "tls_sync", r->tls_sync);
+#endif /* HAVE_LDAP_TLS_WRAPPING */
+       ndr->depth--;
+}
+
+#ifdef HAVE_LDAP_TLS_WRAPPING
+
+static int ads_tlswrap_setup(Sockbuf_IO_Desc *sbiod, void *arg)
+{
+       struct ads_tlswrap *wrap = (struct ads_tlswrap *)arg;
+
+       wrap->sbiod = sbiod;
+
+       sbiod->sbiod_pvt = wrap;
+
+       return 0;
+}
+
+static int ads_tlswrap_remove(Sockbuf_IO_Desc *sbiod)
+{
+       struct ads_tlswrap *wrap =
+                       (struct ads_tlswrap *)sbiod->sbiod_pvt;
+
+       wrap->sbiod = NULL;
+
+       return 0;
+}
+
+static ssize_t ads_tlswrap_send_function(gnutls_transport_ptr_t ptr,
+                                        const uint8_t *buf, size_t size)
+{
+       struct ads_tlswrap *wrap = (struct ads_tlswrap *)ptr;
+
+       if (wrap->endtime.tv_sec != 0) {
+               if (timeval_expired(&wrap->endtime)) {
+                       errno = ECONNRESET;
+                       return -1;
+               }
+       }
+
+       return LBER_SBIOD_WRITE_NEXT(wrap->sbiod, discard_const(buf), size);
+}
+
+static ssize_t ads_tlswrap_recv_function(gnutls_transport_ptr_t ptr,
+                                        uint8_t *buf, size_t size)
+{
+       struct ads_tlswrap *wrap = (struct ads_tlswrap *)ptr;
+
+       if (wrap->endtime.tv_sec != 0) {
+               if (timeval_expired(&wrap->endtime)) {
+                       errno = ECONNRESET;
+                       return -1;
+               }
+       }
+
+       return LBER_SBIOD_READ_NEXT(wrap->sbiod, buf, size);
+}
+
+static ber_slen_t ads_tlswrap_read(Sockbuf_IO_Desc *sbiod,
+                                  void *buf, ber_len_t len)
+{
+       struct ads_tlswrap *wrap =
+                       (struct ads_tlswrap *)sbiod->sbiod_pvt;
+
+       return tstream_tls_sync_read(wrap->tls_sync, buf, len);
+}
+
+static ber_slen_t ads_tlswrap_write(Sockbuf_IO_Desc *sbiod,
+                                   void *buf, ber_len_t len)
+{
+       struct ads_tlswrap *wrap =
+                       (struct ads_tlswrap *)sbiod->sbiod_pvt;
+
+       return tstream_tls_sync_write(wrap->tls_sync, buf, len);
+}
+
+static int ads_tlswrap_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
+{
+       struct ads_tlswrap *wrap =
+                       (struct ads_tlswrap *)sbiod->sbiod_pvt;
+       int ret;
+
+       switch (opt) {
+       case LBER_SB_OPT_DATA_READY:
+               if (tstream_tls_sync_pending(wrap->tls_sync) > 0) {
+                       return 1;
+               }
+
+               ret = LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);
+               break;
+       default:
+               ret = LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);
+               break;
+       }
+
+       return ret;
+}
+
+static int ads_tlswrap_close(Sockbuf_IO_Desc *sbiod)
+{
+       struct ads_tlswrap *wrap =
+                       (struct ads_tlswrap *)sbiod->sbiod_pvt;
+
+       TALLOC_FREE(wrap->tls_sync);
+       TALLOC_FREE(wrap->tls_params);
+
+       return 0;
+}
+
+static const Sockbuf_IO ads_tlswrap_sockbuf_io = {
+       ads_tlswrap_setup,      /* sbi_setup */
+       ads_tlswrap_remove,     /* sbi_remove */
+       ads_tlswrap_ctrl,       /* sbi_ctrl */
+       ads_tlswrap_read,       /* sbi_read */
+       ads_tlswrap_write,      /* sbi_write */
+       ads_tlswrap_close       /* sbi_close */
+};
+
+ADS_STATUS ads_setup_tls_wrapping(struct ads_tlswrap *wrap,
+                                 LDAP *ld,
+                                 const char *server_name)
+{
+       Sockbuf_IO *io = discard_const_p(Sockbuf_IO, &ads_tlswrap_sockbuf_io);
+       Sockbuf *sb = NULL;
+       struct loadparm_context *lp_ctx = NULL;
+       ADS_STATUS status;
+       NTSTATUS ntstatus;
+       unsigned to;
+       int rc;
+
+       rc = ldap_get_option(ld, LDAP_OPT_SOCKBUF, &sb);
+       status = ADS_ERROR_LDAP(rc);
+       if (!ADS_ERR_OK(status)) {
+               return status;
+       }
+
+       lp_ctx = loadparm_init_s3(talloc_tos(), loadparm_s3_helpers());
+       if (lp_ctx == NULL) {
+               return ADS_ERROR(LDAP_NO_MEMORY);
+       }
+
+       ntstatus = tstream_tls_params_client_lpcfg(wrap->mem_ctx,
+                                                  lp_ctx,
+                                                  server_name,
+                                                  &wrap->tls_params);
+       if (!NT_STATUS_IS_OK(ntstatus)) {
+               return ADS_ERROR_NT(ntstatus);
+       }
+
+       /* setup the real wrapping callbacks */
+       rc = ber_sockbuf_add_io(sb, io, LBER_SBIOD_LEVEL_TRANSPORT, wrap);
+       status = ADS_ERROR_LDAP(rc);
+       if (!ADS_ERR_OK(status)) {
+               return status;
+       }
+
+       to = lpcfg_ldap_connection_timeout(lp_ctx);
+       wrap->endtime = timeval_current_ofs(to, 0);
+       ntstatus = tstream_tls_sync_setup(wrap->tls_params,
+                                         wrap,
+                                         ads_tlswrap_send_function,
+                                         ads_tlswrap_recv_function,
+                                         wrap->mem_ctx,
+                                         &wrap->tls_sync);
+       wrap->endtime = timeval_zero();
+       if (!NT_STATUS_IS_OK(ntstatus)) {
+               ber_sockbuf_remove_io(sb, io, LBER_SBIOD_LEVEL_TRANSPORT);
+               return ADS_ERROR_NT(ntstatus);
+       }
+
+       return ADS_SUCCESS;
+}
+
+const DATA_BLOB *ads_tls_channel_bindings(struct ads_tlswrap *wrap)
+{
+       if (wrap->tls_sync == NULL) {
+               return NULL;
+       }
+
+       return tstream_tls_sync_channel_bindings(wrap->tls_sync);
+}
+#else
+ADS_STATUS ads_setup_tls_wrapping(struct ads_tlswrap *wrap,
+                                 LDAP *ld,
+                                 const char *server_name)
+{
+       return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+}
+const DATA_BLOB *ads_tls_channel_bindings(struct ads_tlswrap *wrap)
+{
+       return NULL;
+}
+#endif /* HAVE_LDAP_TLS_WRAPPING */
index e77cd127e600f8c2cd17795a3976ea8c1e5c8d3e..3fec7eabbf8b25e8e3b5c6840be7a2d3c7773160 100644 (file)
@@ -681,6 +681,7 @@ msg.msg_accrightslen = sizeof(fd);
             if conf.CONFIG_SET('HAVE_BER_SOCKBUF_ADD_IO') and \
                     conf.CONFIG_SET('HAVE_LDAP_OPT_SOCKBUF'):
                 conf.DEFINE('HAVE_LDAP_SASL_WRAPPING', '1')
+                conf.DEFINE('HAVE_LDAP_TLS_WRAPPING', '1')
         else:
             conf.fatal("LDAP support not found. "
                        "Try installing libldap2-dev or openldap-devel. "
index c0bf22d6abc4e8e1b7261903b91f9a23394daf98..b868ffd3a1863f08caa6622f016b668e7995ea1a 100644 (file)
@@ -499,6 +499,7 @@ bld.SAMBA3_LIBRARY('ads',
                           libads/ldap.c
                           libads/sasl.c
                           libads/sasl_wrapping.c
+                          libads/tls_wrapping.c
                           libads/krb5_setpw.c
                           libads/kerberos_util.c
                           libads/ldap_user.c