On 2024/01/23 01:24:57 +0100, Philipp <phil...@bureaucracy.de> wrote: > Hi > > I have had a bit of time and implemented ldaps support for table-ldap. > It is currently untested and has some todos. But I would say it's > complete enough to share. So other can comment on the code. A patch > is attached
I don't use ldap and completely lack the experience with it, so I can only provide some feedback on the code itself, not if it makes sense to have TLS in here nor provide testing. > In general it would be nice, if the extras repo could get reactivated. > Most imported would be some documentation for the existing staff. I agree with that sentiment. There's a lot of useful stuff in there. > From 2a2671ea2a88868ec91e24803db30935d18c081d Mon Sep 17 00:00:00 2001 > From: Philipp Takacs <phil...@bureaucracy.de> > Date: Tue, 23 Jan 2024 00:55:23 +0100 > Subject: [PATCH] table-ldap add ldaps support > > untested > > based on libtls, autohell is ugly ass hell don't worry about the autoconf/automake part of this. I can fix it as a follow-up eventually (still have to take a proper look at how this repo is built.) > need also some log messages > --- > configure.ac | 2 +- > extras/tables/table-ldap/aldap.c | 32 ++++++++++++++--- > extras/tables/table-ldap/aldap.h | 20 ++++++----- > extras/tables/table-ldap/ber.c | 23 ++++++++++--- > extras/tables/table-ldap/ber.h | 1 + > extras/tables/table-ldap/table_ldap.c | 49 ++++++++++++++++++++++++--- > 6 files changed, 103 insertions(+), 24 deletions(-) > > diff --git a/configure.ac b/configure.ac > index 410a61b..14608b1 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -577,7 +577,7 @@ AC_ARG_WITH([libssl], > ] > ) > ## XXX chl -lssl manually added > -LIBS="-lcrypto -lssl $LIBS" > +LIBS="-lcrypto -lssl -ltls $LIBS" > AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1], > [Define if your ssl headers are included > with #include <openssl/header.h>])], > diff --git a/extras/tables/table-ldap/aldap.c > b/extras/tables/table-ldap/aldap.c > index d54a90c..9cefe1c 100644 > --- a/extras/tables/table-ldap/aldap.c > +++ b/extras/tables/table-ldap/aldap.c > @@ -22,6 +22,7 @@ > #include <string.h> > #include <stdlib.h> > #include <unistd.h> > +#include <tls.h> nit: I'd keep the include sorted when possible, so tls.h should go between stdlib.h and unistd.h > #include "aldap.h" > > @@ -55,6 +56,12 @@ void ldap_debug_elements(struct > ber_element *); > int > aldap_close(struct aldap *al) > { > + if (al->ber.tls_ctx) { > + if (tls_close(al->ber.tls_ctx) == -1) > + return (-1); > + tls_free(al->ber.tls_ctx); > + } > + > if (close(al->ber.fd) == -1) > return (-1); > > @@ -65,13 +72,14 @@ aldap_close(struct aldap *al) > } > > struct aldap * > -aldap_init(int fd) > +aldap_init(int fd, struct tls *ctx) > { > struct aldap *a; > > if ((a = calloc(1, sizeof(*a))) == NULL) > return NULL; > a->ber.fd = fd; > + a->ber.tls_ctx = ctx; > > return a; > } > @@ -575,10 +583,15 @@ aldap_parse_url(char *url, struct aldap_url *lu) > p = lu->buffer; > > /* protocol */ > - if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) != 0) > + if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) == 0) { > + lu->protocol = LDAP; > + p += strlen(LDAP_URL); > + } else if (strncasecmp(LDAPS_URL, p, strlen(LDAP_URL)) == 0) { > + lu->protocol = LDAPS; > + p += strlen(LDAPS_URL); > + } else { > goto fail; > - lu->protocol = LDAP; > - p += strlen(LDAP_URL); > + } > > /* host and optional port */ > if ((forward = strchr(p, '/')) != NULL) > @@ -594,7 +607,16 @@ aldap_parse_url(char *url, struct aldap_url *lu) > goto fail; > } > } else { > - lu->port = LDAP_PORT; nit: a switch here is a bit over overly-verbose. just lu->port = LDAP_PORT; if (lu->protocol == LDAPS) lp->port = LDAPS_PORT; should do it. > + switch (lu->protocol) { > + case LDAP: > + lu->port = LDAP_PORT; > + break; > + case LDAPS: > + lu->port = LDAPS_PORT; > + break; > + default: > + goto fail; > + } > } > /* fail if no host is given */ > if (strlen(p) == 0) > diff --git a/extras/tables/table-ldap/aldap.h > b/extras/tables/table-ldap/aldap.h > index 7cfd637..fec106b 100644 > --- a/extras/tables/table-ldap/aldap.h > +++ b/extras/tables/table-ldap/aldap.h > @@ -20,6 +20,8 @@ > > #define LDAP_URL "ldap://" > #define LDAP_PORT 389 > +#define LDAPS_URL "ldaps://" > +#define LDAPS_PORT 636 > #define LDAP_PAGED_OID "1.2.840.113556.1.4.319" > > struct aldap { > @@ -69,15 +71,15 @@ enum aldap_protocol { > }; > > struct aldap_url { > - int protocol; > - char *host; > - in_port_t port; > - char *dn; > + enum aldap_protocol protocol; tbh I would have just kept 'int protocol' here. not sure if specifying the enum and re-indent everything really helps. but i don't object it :) > + char *host; > + in_port_t port; > + char *dn; > #define MAXATTR 1024 > - char *attributes[MAXATTR]; > - int scope; > - char *filter; > - char *buffer; > + char *attributes[MAXATTR]; > + int scope; > + char *filter; > + char *buffer; > }; > > enum protocol_op { > @@ -186,7 +188,7 @@ enum ldap_subfilter { > LDAP_FILT_SUBS_FIN = 2, > }; > > -struct aldap *aldap_init(int fd); > +struct aldap *aldap_init(int fd, struct tls *ctx); > int aldap_close(struct aldap *); > struct aldap_message *aldap_parse(struct aldap *); > void aldap_freemsg(struct aldap_message *); > diff --git a/extras/tables/table-ldap/ber.c b/extras/tables/table-ldap/ber.c > index 0f92bb2..9bb06aa 100644 > --- a/extras/tables/table-ldap/ber.c > +++ b/extras/tables/table-ldap/ber.c > @@ -28,6 +28,7 @@ > #include <string.h> > #include <unistd.h> > #include <stdarg.h> > +#include <tls.h> same nit about header order. > #include "ber.h" > > @@ -784,8 +785,12 @@ ber_write_elements(struct ber *ber, struct ber_element > *root) > return -1; > > /* XXX this should be moved to a different function */ > - if (ber->fd != -1) > + if (ber->fd != -1) { > + if (ber->tls_ctx) { > + return tls_write(ber->tls_ctx, ber->br_wbuf, len); This, and the other calls to tls_read are wrong. Even in the blocking case, we need to wrap these in a loop to handle TLS_WANT_POLLIN and TLS_WANT_POLLOUT, as per the manpage example. I remember being bitten by this, as libretls (libtls over openssl) returns the TLS_WANT_* more often than LibreSSL' libtls. > + } > return write(ber->fd, ber->br_wbuf, len); > + } > > return (len); > } > @@ -1233,8 +1238,12 @@ ber_getc(struct ber *b, unsigned char *c) > */ > if (b->fd == -1) > r = ber_readbuf(b, c, 1); > - else > - r = read(b->fd, c, 1); > + else { > + if (b->tls_ctx) > + r = tls_read(b->tls_ctx, c, 1); > + else > + r = read(b->fd, c, 1); > + } > return r; > } > > @@ -1253,8 +1262,12 @@ ber_read(struct ber *ber, void *buf, size_t len) > while (remain > 0) { > if (ber->fd == -1) > r = ber_readbuf(ber, b, remain); > - else > - r = read(ber->fd, b, remain); > + else { > + if (ber->tls_ctx) > + r = tls_read(ber->tls_ctx, b, remain); > + else > + r = read(ber->fd, b, remain); > + } > if (r == -1) { > if (errno == EINTR || errno == EAGAIN) > continue; > diff --git a/extras/tables/table-ldap/ber.h b/extras/tables/table-ldap/ber.h > index d656508..4987fc2 100644 > --- a/extras/tables/table-ldap/ber.h > +++ b/extras/tables/table-ldap/ber.h > @@ -34,6 +34,7 @@ struct ber_element { > > struct ber { > int fd; > + struct tls *tls_ctx; > unsigned char *br_wbuf; > unsigned char *br_wptr; > unsigned char *br_wend; > diff --git a/extras/tables/table-ldap/table_ldap.c > b/extras/tables/table-ldap/table_ldap.c > index 090cfb4..bdfb13b 100644 > --- a/extras/tables/table-ldap/table_ldap.c > +++ b/extras/tables/table-ldap/table_ldap.c > @@ -27,6 +27,7 @@ > #include <stdio.h> > #include <string.h> > #include <unistd.h> > +#include <tls.h> same nit :) > #include <smtpd-api.h> > #include "aldap.h" > @@ -80,6 +81,34 @@ table_ldap_fetch(int service, struct dict *params, char > *dst, size_t sz) > return -1; > } > > +static struct tls * > +ldaps_connect(int fd, char *hostname) > +{ > + /* XXX log */ > + struct tls *ctx = NULL; > + struct tls_config *config = tls_config_new(); > + if (!config) > + goto fail; > + if (tls_config_set_ca_path(config, "/etc/ssl/certs") == -1) > + goto fail; Is this needed? out-of-the-box on OpenBSD this directory doesn't exist, but don't know if it's the "de-facto" place to store certs for ldap. In any case, I think it should be at least configurable. > + if ((ctx = tls_client()) == NULL) > + goto fail; > + if (tls_configure(ctx, config) == -1) > + goto fail; > + if (tls_connect_socket(ctx, fd, hostname) == -1) > + goto fail; > + if (tls_handshake(ctx) == -1) > + goto fail; tls_handshake() needs almost the same loop as tls_write and tls_read to handle TLS_WANT_POLLIN/OUT. > + tls_config_free(config); > + return ctx; > +fail: > + tls_close(ctx); > + tls_free(ctx); > + tls_config_free(config); these close/free calls needs to be guarded since ctx and config may be NULL when here and these functions will deference the argument. > + return NULL; > +} > + > static struct aldap * > ldap_connect(const char *addr) > { > @@ -121,13 +150,25 @@ ldap_connect(const char *addr) ouch... ldap_connect is really a bit over-complicate. I'd prefer if we simplify this a bit first. I'll soon send a diff for this.