From: Stefan Metzmacher Date: Tue, 30 Jan 2024 09:27:58 +0000 (+0100) Subject: s3:libads: add tls_wrapping into openldap X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=6a84552d5931e8822404ba346959f13242f870d1;p=jra%2Fsamba-autobuild%2F.git s3:libads: add tls_wrapping into openldap Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h index ceefcd6d807..2fb915996a6 100644 --- a/source3/libads/ads_proto.h +++ b/source3/libads/ads_proto.h @@ -212,6 +212,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); diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 1b7bdcf2d6e..84771f6a43e 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -849,6 +849,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; @@ -967,6 +968,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); @@ -1061,6 +1068,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); @@ -1069,6 +1079,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 index 00000000000..c25ab67a902 --- /dev/null +++ b/source3/libads/tls_wrapping.c @@ -0,0 +1,226 @@ +/* + 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 . +*/ + +#include "includes.h" +#include "ads.h" +#include "lib/param/param.h" +#include "../source4/lib/tls/tls.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++; + ndr_print_ptr(ndr, "mem_ctx", r->mem_ctx); + ndr_print_timeval(ndr, "endtime", &r->endtime); +#ifdef HAVE_ADS + ndr_print_ptr(ndr, "sbiod", r->sbiod); + ndr_print_ptr(ndr, "tls_params", r->tls_params); + ndr_print_ptr(ndr, "tls_sync", r->tls_sync); +#endif /* HAVE_ADS */ + ndr->depth--; +} + +#ifdef HAVE_ADS + +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_ADS */ diff --git a/source3/librpc/idl/ads.idl b/source3/librpc/idl/ads.idl index 4a63ace7c23..a706d355a5b 100644 --- a/source3/librpc/idl/ads.idl +++ b/source3/librpc/idl/ads.idl @@ -101,6 +101,16 @@ interface ads ads_ldap_buf_out out; } ads_saslwrap; + typedef [nopull,nopush] struct { + [ignore] TALLOC_CTX *mem_ctx; + [ignore] timeval endtime; +#ifdef HAVE_ADS + [ignore] struct sockbuf_io_desc *sbiod; /* lowlevel state for LDAP wrapping */ + [ignore] struct tstream_tls_params *tls_params; + [ignore] struct tstream_tls_sync *tls_sync; +#endif /* HAVE_ADS */ + } ads_tlswrap; + typedef [nopull,nopush] struct { [ignore] ldap *ld; sockaddr_storage ss; /* the ip of the active connection, if any */ @@ -120,6 +130,7 @@ interface ads #ifdef HAVE_ADS ads_saslwrap ldap_wrap_data; + ads_tlswrap ldap_tls_data; /* info about the current LDAP connection */ ads_ldap ldap; #endif /* HAVE_ADS */ diff --git a/source3/wscript_build b/source3/wscript_build index 16927880e47..8bb7f4e26d9 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -497,6 +497,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