Hi An updated version with some logging is attached.
Philipp
From 9c80b1be27ea8de744bf2c7b0229441656cae22d 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 based on libtls, autohell is ugly ass hell --- configure.ac | 2 +- extras/tables/table-ldap/aldap.c | 26 ++++++++++-- extras/tables/table-ldap/aldap.h | 20 +++++---- extras/tables/table-ldap/ber.c | 35 ++++++++++++++- extras/tables/table-ldap/ber.h | 1 + extras/tables/table-ldap/table_ldap.c | 61 ++++++++++++++++++++++++++- 6 files changed, 127 insertions(+), 18 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 e5b99fa..dff6432 100644 --- a/extras/tables/table-ldap/aldap.c +++ b/extras/tables/table-ldap/aldap.c @@ -21,6 +21,7 @@ #include <inttypes.h> #include <string.h> #include <stdlib.h> +#include <tls.h> #include <unistd.h> #include "aldap.h" @@ -55,6 +56,14 @@ void ldap_debug_elements(struct ber_element *); int aldap_close(struct aldap *al) { + if (al->ber.tls_ctx) { + int ret; + do { + ret = tls_close(al->ber.tls_ctx); + } while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); + tls_free(al->ber.tls_ctx); + } + if (close(al->ber.fd) == -1) return (-1); @@ -65,13 +74,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; } @@ -574,10 +584,15 @@ aldap_parse_url(const 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) @@ -595,6 +610,9 @@ aldap_parse_url(const char *url, struct aldap_url *lu) } } else { lu->port = LDAP_PORT; + if (lu->protocol == LDAPS) { + lu->port = LDAPS_PORT; + } } /* 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 c1020dd..60159b4 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; - char *port; - char *dn; + enum aldap_protocol protocol; + char *host; + char *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..94e887a 100644 --- a/extras/tables/table-ldap/ber.c +++ b/extras/tables/table-ldap/ber.c @@ -24,10 +24,11 @@ #include <limits.h> #include <stdlib.h> #include <err.h> /* XXX for debug output */ +#include <stdarg.h> #include <stdio.h> /* XXX for debug output */ #include <string.h> +#include <tls.h> #include <unistd.h> -#include <stdarg.h> #include "ber.h" @@ -747,6 +748,26 @@ ber_scanf_elements(struct ber_element *ber, char *fmt, ...) } +static ssize_t +tls_write_wrapper(struct tls *ctx, const void *buf, size_t buflen) +{ + ssize_t ret; + do { + ret = tls_write(ctx, buf, buflen); + } while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); + return ret; +} + +static ssize_t +tls_read_wrapper(struct tls *ctx, void *buf, size_t buflen) +{ + ssize_t ret; + do { + ret = tls_read(ctx, buf, buflen); + } while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); + return ret; +} + /* * write ber elements to the socket * @@ -784,8 +805,13 @@ 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_wrapper(ber->tls_ctx, ber->br_wbuf, + len); + } return write(ber->fd, ber->br_wbuf, len); + } return (len); } @@ -1233,6 +1259,8 @@ ber_getc(struct ber *b, unsigned char *c) */ if (b->fd == -1) r = ber_readbuf(b, c, 1); + else if (b->tls_ctx) + r = tls_read_wrapper(b->tls_ctx, c, 1); else r = read(b->fd, c, 1); return r; @@ -1253,8 +1281,11 @@ ber_read(struct ber *ber, void *buf, size_t len) while (remain > 0) { if (ber->fd == -1) r = ber_readbuf(ber, b, remain); + else if (ber->tls_ctx) + r = tls_read_wrapper(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 076715e..d33c85c 100644 --- a/extras/tables/table-ldap/table_ldap.c +++ b/extras/tables/table-ldap/table_ldap.c @@ -26,6 +26,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <tls.h> #include <unistd.h> #include <smtpd-api.h> @@ -64,7 +65,7 @@ struct query { static int ldap_run_query(int type, const char *, char *, size_t); -static char *config, *url, *username, *password, *basedn; +static char *config, *url, *username, *password, *basedn, *ca_file; static struct aldap *aldap; static struct query queries[LDAP_MAX]; @@ -81,6 +82,52 @@ table_ldap_fetch(int service, struct dict *params, char *dst, size_t sz) return -1; } +static int +tls_handshake_wrapper(struct tls *ctx) +{ + int ret; + do { + ret = tls_handshake(ctx); + } while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); + return ret; +} + +static struct tls * +ldaps_connect(int fd, char *hostname) +{ + struct tls *ctx = NULL; + struct tls_config *config = tls_config_new(); + if (!config) { + log_warn("warn: can not get tls_config"); + goto fail; + } + if (ca_file && tls_config_set_ca_file(config, ca_file) == -1) { + log_warnx("warn: can not load ca file: %s", tls_config_error(config)); + goto fail; + } + if ((ctx = tls_client()) == NULL) { + log_warn("warn: can not get tls_client"); + goto fail; + } + if (tls_configure(ctx, config) == -1) + goto fail; + if (tls_connect_socket(ctx, fd, hostname) == -1) + goto fail; + if (tls_handshake_wrapper(ctx) == -1) + goto fail; + + tls_config_free(config); + return ctx; +fail: + if (ctx) { + log_warnx("warn: tls error: %s", tls_error(ctx)); + tls_close(ctx); + } + tls_free(ctx); + tls_config_free(config); + return NULL; +} + static struct aldap * ldap_connect(const char *addr) { @@ -112,8 +159,16 @@ ldap_connect(const char *addr) continue; if (connect(fd, res->ai_addr, res->ai_addrlen) == 0) { + struct tls *ctx = NULL; + if (lu.protocol == LDAPS) { + if ((ctx = ldaps_connect(fd, lu.host)) == NULL) { + close(fd); + fd = -1; + continue; + } + } aldap_free_url(&lu); - return aldap_init(fd); + return aldap_init(fd, ctx); } close(fd); @@ -224,6 +279,8 @@ ldap_config(void) read_value(&password, key, value); else if (!strcmp(key, "basedn")) read_value(&basedn, key, value); + else if (!strcmp(key, "ca_file")) + read_value(&ca_file, key, value); else if (!strcmp(key, "alias_filter")) read_value(&queries[LDAP_ALIAS].filter, key, value); else if (!strcmp(key, "alias_attributes")) { -- 2.39.2