out-of-memory error, instead of letting the PCRE2 library
silently skip a rule. File: util/dict_pcre.c.
+20260416
+
+ Code health: verified zero functionality change. Factored
+ out the tlsproxy support for the server role. Next up is
+ to make server role support consistent with client role
+ support. Files: tlsproxy/tlsproxy.c, tlsproxy/tlsproxy_server.[hc].
+
+ Cleanup: defensive comment for code scanner, fixed an
+ almost-correct overflow defense. File: util/argv.c.
+
+ Added #ifdef guards to un-break non-TLS builds. Files:
+ tlsproxy/tlsproxy_diff.c, tlsproxy/tlsproxy.h.
+
+ Added missing text to manpages. Files: tls/tls_proxy_*_proto.c.
+
TODO
Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc.
Files tlsproxy tlsproxy c tlsproxy tlsproxy h
Files tlsproxy tlsproxy c tlsproxy tlsproxy h
for consistency Files tlsproxy tlsproxy hc
+ tlsproxy tlsproxy_diff c tlsproxy tlsproxy h
deref
openUTS
xff
+nameN
+valueN
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20260415"
+#define MAIL_RELEASE_DATE "20260416"
#define MAIL_VERSION_NUMBER "3.12"
#ifdef SNAPSHOT
/* SYNOPSIS
/* #include <tls_proxy_client_init_proto.h>
/*
+/* TLS_PROXY_CLIENT_INIT_PROPS(props, name1 = value1, ..., nameN = valueN)
+/*
/* char *tls_proxy_client_init_serialize(print_fn, buf, init_props)
/* ATTR_PRINT_COMMON_FN print_fn;
/* VSTRING *buf;
/* void tls_proxy_client_init_free(init_props)
/* TLS_CLIENT_INIT_PROPS *init_props;
/* DESCRIPTION
+/* TLS_PROXY_CLIENT_INIT_PROPS() makes shallow copies of the form
+/* (props)->name1 = value1, ..., (props)->nameN = valueN. The result
+/* should not be passed to tls_proxy_client_init_free().
+/*
/* tls_proxy_client_init_serialize() serializes the specified
/* object to a memory buffer, using the specified print function
/* (typically, attr_print_plain). The result can be used
/* SYNOPSIS
/* #include <tls_proxy_client_param_proto.h>
/*
+/* TLS_PROXY_CLIENT_PARAMS(params, name1 = value1, ..., nameN = valueN)
+/*
/* TLS_CLIENT_PARAMS *tls_proxy_client_param_from_config(params)
/* TLS_CLIENT_PARAMS *params;
/*
/* argument. Strings are not copied. The result must therefore
/* not be passed to tls_proxy_client_param_free().
/*
+/* TLS_PROXY_CLIENT_PARAMS() makes shallow copies of the form
+/* (params)->name1 = value1, ..., (params)->nameN = valueN. As with
+/* tls_proxy_client_param_from_config(), the result should not be
+/* passed to tls_proxy_client_param_free().
+/*
/* tls_proxy_client_param_serialize() serializes the specified
/* object to a memory buffer, using the specified print function
/* (typically, attr_print_plain). The result can be used
/* SYNOPSIS
/* #include <tls_proxy_client_start_proto.h>
/*
+/* TLS_PROXY_CLIENT_START_PROPS(props, name1 = value1, ..., nameN = valueN)
+/*
/* int tls_proxy_client_start_print(print_fn, stream, flags, ptr)
/* ATTR_PRINT_COMMON_FN print_fn;
/* VSTREAM *stream;
/* void tls_proxy_client_start_free(start_props)
/* TLS_CLIENT_START_PROPS *start_props;
/* DESCRIPTION
+/* TLS_PROXY_CLIENT_START_PROPS() makes shallow copies of the form
+/* (props)->name1 = value1, ..., (props)->nameN = valueN. The result
+/* should not be passed to tls_proxy_client_start_free().
+/*
/* tls_proxy_client_start_print() writes a TLS_CLIENT_START_PROPS
/* structure, without stream or file descriptor members, to
/* the named stream using the specified attribute print routine.
/* SYNOPSIS
/* #include <tls_proxy_server_init_proto.h>
/*
+/* TLS_PROXY_SERVER_INIT_PROPS(props, name1 = value1, ..., nameN = valueN)
+/*
/* char *tls_proxy_server_init_serialize(print_fn, buf, init_props)
/* ATTR_PRINT_COMMON_FN print_fn;
/* VSTRING *buf;
/* tls_proxy_server_init_free(init_props)
/* TLS_SERVER_INIT_PROPS *init_props;
/* DESCRIPTION
+/* TLS_PROXY_SERVER_INIT_PROPS() makes shallow copies of the form
+/* (props)->name1 = value1, ..., (props)->nameN = valueN. The result
+/* should not be passed to tls_proxy_server_init_free().
+/*
/* tls_proxy_server_init_serialize() serializes the specified object
/* to a memory buffer, using the specified print function (typically,
/* attr_print_plain). The result can be used determine whether
/* TLS_SERVER_PARAMS *tls_proxy_server_param_from_config(params)
/* TLS_SERVER_PARAMS *params;
/*
+/* TLS_PROXY_SERVER_PARAMS(params, name1 = value1, ..., nameN = valueN)
+/*
/* char *tls_proxy_server_param_serialize(print_fn, buf, params)
/* ATTR_PRINT_COMMON_FN print_fn;
/* VSTRING *buf;
/* returns its argument. Strings are not copied. The result must
/* therefore not be passed to tls_proxy_server_param_free().
/*
+/* TLS_PROXY_SERVER_PARAMS() makes shallow copies of the form
+/* (params)->name1 = value1, ..., (params)->nameN = valueN. As with
+/* tls_proxy_server_param_from_config(), the result should not be
+/* passed to tls_proxy_server_param_free().
+/*
/* tls_proxy_server_param_serialize() serializes the specified object
/* to a memory buffer, using the specified print function (typically,
/* attr_print_plain). The result can be used determine whether
/* SYNOPSIS
/* #include <tls_proxy_server_start_proto.h>
/*
+/* TLS_PROXY_SERVER_START_PROPS(props, name1 = value1, ..., nameN = valueN)
+/*
/* int tls_proxy_server_start_print(print_fn, stream, flags, ptr)
/* ATTR_PRINT_COMMON_FN print_fn;
/* VSTREAM *stream;
/* void tls_proxy_server_start_free(start_props)
/* TLS_SERVER_START_PROPS *start_props;
/* DESCRIPTION
+/* TLS_PROXY_SERVER_START_PROPS() makes shallow copies of the form
+/* (props)->name1 = value1, ..., (props)->nameN = valueN. The result
+/* should not be passed to tls_proxy_server_start_free().
+/*
/* tls_proxy_server_start_print() writes a TLS_SERVER_START_PROPS
/* structure to the named stream using the specified attribute print
/* routine. tls_proxy_server_start_print() is meant to be passed as
/* a call-back to attr_print(), thusly:
/*
/* ... SEND_ATTR_FUNC(tls_proxy_server_start_print, (const void *) start_props), ...
+/*
+/* tls_proxy_server_start_scan() reads a TLS_SERVER_START_PROPS
+/* structure from the named stream using the specified attribute
+/* scan routine. tls_proxy_server_start_scan() is meant to be passed
+/* as a call-back function to attr_scan(), as shown below.
+/*
+/* tls_proxy_server_start_free() destroys a TLS_SERVER_START_PROPS
+/* structure that was created by tls_proxy_server_start_scan().
+/*
+/* TLS_SERVER_START_PROPS *start_props = 0;
+/* ...
+/* ... RECV_ATTR_FUNC(tls_proxy_server_start_scan, (void *) &start_props)
+/* ...
+/* if (start_props)
+/* tls_proxy_server_start_free(start_props);
/* DIAGNOSTICS
/* Fatal: out of memory.
/* LICENSE
SHELL = /bin/sh
-SRCS = tlsproxy.c tlsproxy_state.c tlsproxy_client.c tlsproxy_diff.c
-OBJS = tlsproxy.o tlsproxy_state.o tlsproxy_client.o tlsproxy_diff.o
-HDRS = tlsproxy.h tlsproxy_client.h tlsproxy_diff.h
+SRCS = tlsproxy.c tlsproxy_state.c tlsproxy_client.c tlsproxy_diff.c \
+ tlsproxy_server.c
+OBJS = tlsproxy.o tlsproxy_state.o tlsproxy_client.o tlsproxy_diff.o \
+ tlsproxy_server.o
+HDRS = tlsproxy.h tlsproxy_client.h tlsproxy_diff.h tlsproxy_server.h
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
tlsproxy.o: tlsproxy.c
tlsproxy.o: tlsproxy.h
tlsproxy.o: tlsproxy_client.h
+tlsproxy.o: tlsproxy_server.h
tlsproxy_client.o: ../../include/argv.h
tlsproxy_client.o: ../../include/attr.h
tlsproxy_client.o: ../../include/been_here.h
tlsproxy_diff.o: tlsproxy.h
tlsproxy_diff.o: tlsproxy_diff.c
tlsproxy_diff.o: tlsproxy_diff.h
+tlsproxy_server.o: ../../include/argv.h
+tlsproxy_server.o: ../../include/attr.h
+tlsproxy_server.o: ../../include/check_arg.h
+tlsproxy_server.o: ../../include/dns.h
+tlsproxy_server.o: ../../include/events.h
+tlsproxy_server.o: ../../include/htable.h
+tlsproxy_server.o: ../../include/mail_params.h
+tlsproxy_server.o: ../../include/msg.h
+tlsproxy_server.o: ../../include/myaddrinfo.h
+tlsproxy_server.o: ../../include/mymalloc.h
+tlsproxy_server.o: ../../include/name_code.h
+tlsproxy_server.o: ../../include/name_mask.h
+tlsproxy_server.o: ../../include/nbbio.h
+tlsproxy_server.o: ../../include/nvtable.h
+tlsproxy_server.o: ../../include/sock_addr.h
+tlsproxy_server.o: ../../include/sys_defs.h
+tlsproxy_server.o: ../../include/tls.h
+tlsproxy_server.o: ../../include/tls_proxy.h
+tlsproxy_server.o: ../../include/tls_proxy_attr.h
+tlsproxy_server.o: ../../include/tls_proxy_client_init_proto.h
+tlsproxy_server.o: ../../include/tls_proxy_client_param_proto.h
+tlsproxy_server.o: ../../include/tls_proxy_client_start_proto.h
+tlsproxy_server.o: ../../include/tls_proxy_server_init_proto.h
+tlsproxy_server.o: ../../include/tls_proxy_server_param_proto.h
+tlsproxy_server.o: ../../include/tls_proxy_server_start_proto.h
+tlsproxy_server.o: ../../include/vbuf.h
+tlsproxy_server.o: ../../include/vstream.h
+tlsproxy_server.o: ../../include/vstring.h
+tlsproxy_server.o: tlsproxy.h
+tlsproxy_server.o: tlsproxy_server.c
+tlsproxy_server.o: tlsproxy_server.h
tlsproxy_state.o: ../../include/argv.h
tlsproxy_state.o: ../../include/attr.h
tlsproxy_state.o: ../../include/check_arg.h
*/
#include <tlsproxy.h>
#include <tlsproxy_client.h>
+#include <tlsproxy_server.h>
/*
* Tunable parameters. We define our clones of the smtpd(8) parameters to
char *var_tlsp_clnt_per_site;
char *var_tlsp_clnt_policy;
- /*
- * TLS per-process status.
- */
-static TLS_APPL_STATE *tlsp_server_ctx;
-static int ask_client_cert;
-static const char *server_role_disabled;
-
/*
* The code that implements the TLS engine looks simpler than expected. That
* is the result of a great deal of effort, mainly in design and analysis.
}
}
-/* tlsp_server_start_pre_handshake - turn on TLS or force disconnect */
-
-static int tlsp_server_start_pre_handshake(TLSP_STATE *state)
-{
- TLS_SERVER_START_PROPS props;
- static char *cipher_grade;
- static VSTRING *cipher_exclusions;
-
- /*
- * The code in this routine is pasted literally from smtpd(8). I am not
- * going to sanitize this because doing so surely will break things in
- * unexpected ways.
- */
-
- /*
- * Perform the before-handshake portion of per-session initialization.
- * Pass a null VSTREAM to indicate that this program will do the
- * ciphertext I/O, not libtls.
- *
- * The cipher grade and exclusions don't change between sessions. Compute
- * just once and cache.
- */
-#define ADD_EXCLUDE(vstr, str) \
- do { \
- if (*(str)) \
- vstring_sprintf_append((vstr), "%s%s", \
- VSTRING_LEN(vstr) ? " " : "", (str)); \
- } while (0)
-
- if (cipher_grade == 0) {
- cipher_grade =
- var_tlsp_enforce_tls ? var_tlsp_tls_mand_ciph : var_tlsp_tls_ciph;
- cipher_exclusions = vstring_alloc(10);
- ADD_EXCLUDE(cipher_exclusions, var_tlsp_tls_excl_ciph);
- if (var_tlsp_enforce_tls)
- ADD_EXCLUDE(cipher_exclusions, var_tlsp_tls_mand_excl);
- if (ask_client_cert)
- ADD_EXCLUDE(cipher_exclusions, "aNULL");
- }
- state->tls_context =
- TLS_SERVER_START(&props,
- ctx = tlsp_server_ctx,
- stream = (VSTREAM *) 0,/* unused */
- fd = state->ciphertext_fd,
- timeout = 0, /* unused */
- requirecert = (var_tlsp_tls_req_ccert
- && var_tlsp_enforce_tls),
- enable_rpk = var_tlsp_tls_enable_rpk,
- serverid = state->server_id,
- namaddr = state->remote_endpt,
- cipher_grade = cipher_grade,
- cipher_exclusions = STR(cipher_exclusions),
- mdalg = var_tlsp_tls_fpt_dgst);
-
- if (state->tls_context == 0) {
- tlsp_state_free(state);
- return (TLSP_STAT_ERR);
- }
-
- /*
- * XXX Do we care about TLS session rate limits? Good postscreen(8)
- * clients will occasionally require the tlsproxy to renew their
- * allowlist status, but bad clients hammering the server can suck up
- * lots of CPU cycles. Per-client concurrency limits in postscreen(8)
- * will divert only naive security "researchers".
- */
- return (TLSP_STAT_OK);
-}
-
/*
* From here on down is low-level code that sets up the plumbing before
* passing control to the TLS engine above.
TLSP_INIT_TIMEOUT, (void *) state);
}
-/* pre_jail_init_server - pre-jail initialization */
-
-static void pre_jail_init_server(void)
-{
- TLS_SERVER_INIT_PROPS props;
- const char *cert_file;
- int have_server_cert;
- int no_server_cert_ok;
- int require_server_cert;
-
- /*
- * The code in this routine is pasted literally from smtpd(8). I am not
- * going to sanitize this because doing so surely will break things in
- * unexpected ways.
- */
- if (*var_tlsp_tls_level) {
- switch (tls_level_lookup(var_tlsp_tls_level)) {
- default:
- msg_fatal("Invalid TLS level \"%s\"", var_tlsp_tls_level);
- /* NOTREACHED */
- break;
- case TLS_LEV_SECURE:
- case TLS_LEV_VERIFY:
- case TLS_LEV_FPRINT:
- msg_warn("%s: unsupported TLS level \"%s\", using \"encrypt\"",
- VAR_TLSP_TLS_LEVEL, var_tlsp_tls_level);
- /* FALLTHROUGH */
- case TLS_LEV_ENCRYPT:
- var_tlsp_enforce_tls = var_tlsp_use_tls = 1;
- break;
- case TLS_LEV_MAY:
- var_tlsp_enforce_tls = 0;
- var_tlsp_use_tls = 1;
- break;
- case TLS_LEV_NONE:
- var_tlsp_enforce_tls = var_tlsp_use_tls = 0;
- break;
- }
- }
- var_tlsp_use_tls = var_tlsp_use_tls || var_tlsp_enforce_tls;
- if (!var_tlsp_use_tls) {
- server_role_disabled = "TLS server role is disabled by configuration";
- return;
- }
-
- /*
- * Load TLS keys before dropping privileges.
- *
- * Can't use anonymous ciphers if we want client certificates. Must use
- * anonymous ciphers if we have no certificates.
- */
- ask_client_cert = require_server_cert =
- (var_tlsp_tls_ask_ccert
- || (var_tlsp_enforce_tls && var_tlsp_tls_req_ccert));
- if (strcasecmp(var_tlsp_tls_cert_file, "none") == 0) {
- no_server_cert_ok = 1;
- cert_file = "";
- } else {
- no_server_cert_ok = 0;
- cert_file = var_tlsp_tls_cert_file;
- }
- have_server_cert =
- (*cert_file || *var_tlsp_tls_dcert_file || *var_tlsp_tls_eccert_file);
-
- if (*var_tlsp_tls_chain_files != 0) {
- if (!have_server_cert)
- have_server_cert = 1;
- else
- msg_warn("Both %s and one or more of the legacy "
- " %s, %s or %s are non-empty; the legacy "
- " parameters will be ignored",
- VAR_TLSP_TLS_CHAIN_FILES,
- VAR_TLSP_TLS_CERT_FILE,
- VAR_TLSP_TLS_ECCERT_FILE,
- VAR_TLSP_TLS_DCERT_FILE);
- }
- /* Some TLS configuration errors are not show stoppers. */
- if (!have_server_cert && require_server_cert)
- msg_warn("Need a server cert to request client certs");
- if (!var_tlsp_enforce_tls && var_tlsp_tls_req_ccert)
- msg_warn("Can't require client certs unless TLS is required");
- /* After a show-stopper error, log a warning. */
- if (have_server_cert || (no_server_cert_ok && !require_server_cert)) {
-
- tls_pre_jail_init(TLS_ROLE_SERVER);
-
- /*
- * Large parameter lists are error-prone, so we emulate a language
- * feature that C does not have natively: named parameter lists.
- */
- tlsp_server_ctx =
- TLS_SERVER_INIT(&props,
- log_param = VAR_TLSP_TLS_LOGLEVEL,
- log_level = var_tlsp_tls_loglevel,
- verifydepth = var_tlsp_tls_ccert_vd,
- cache_type = TLS_MGR_SCACHE_SMTPD,
- set_sessid = var_tlsp_tls_set_sessid,
- chain_files = var_tlsp_tls_chain_files,
- cert_file = cert_file,
- key_file = var_tlsp_tls_key_file,
- dcert_file = var_tlsp_tls_dcert_file,
- dkey_file = var_tlsp_tls_dkey_file,
- eccert_file = var_tlsp_tls_eccert_file,
- eckey_file = var_tlsp_tls_eckey_file,
- CAfile = var_tlsp_tls_CAfile,
- CApath = var_tlsp_tls_CApath,
- dh1024_param_file
- = var_tlsp_tls_dh1024_param_file,
- dh512_param_file
- = var_tlsp_tls_dh512_param_file,
- eecdh_grade = var_tlsp_tls_eecdh,
- protocols = var_tlsp_enforce_tls ?
- var_tlsp_tls_mand_proto :
- var_tlsp_tls_proto,
- ask_ccert = ask_client_cert,
- mdalg = var_tlsp_tls_fpt_dgst);
- } else {
- msg_warn("No server certs available. TLS can't be enabled");
- }
-
- /*
- * To maintain sanity, allow partial SSL_write() operations, and allow
- * SSL_write() buffer pointers to change after a WANT_READ or WANT_WRITE
- * result. This is based on OpenSSL developers talking on a mailing list,
- * but is not supported by documentation. If this code stops working then
- * no-one can be held responsible.
- */
- if (tlsp_server_ctx)
- SSL_CTX_set_mode(tlsp_server_ctx->ssl_ctx,
- SSL_MODE_ENABLE_PARTIAL_WRITE
- | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-}
-
/* pre_jail_init - pre-jail initialization */
static void pre_jail_init(char *unused_name, char **unused_argv)
/*
* TLS library.
*/
+#ifdef USE_TLS
+
#include <tls.h>
#include <tls_proxy.h>
/*--*/
#endif
+
+#endif
/*
* System library.
*/
+#ifdef USE_TLS
+
#include <sys_defs.h>
+#include <string.h>
/*
* Utility library.
*/
#include <msg.h>
+#include <mymalloc.h>
#include <split_at.h>
+#include <vstring.h>
/*
* Internal API.
myfree(saved_client);
myfree(saved_server);
}
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* tlsproxy_server 3
+/* SUMMARY
+/* Postfix TLS proxy server role support
+/* SYNOPSIS
+/* #include <tlsproxy_server.h>
+/*
+/* void pre_jail_init_server(void)
+/*Begin TODO
+/* TLS_APPL_STATE *tlsp_server_init(
+/* TLS_SERVER_PARAMS *tls_params,
+/* TLS_SERVER_INIT_PROPS *init_props)
+/*End TODO
+/* int tlsp_server_start_pre_handshake(TLSP_STATE *state)
+/* DESCRIPTION
+/* This module implements TLS proxy server role support. The legacy
+/* implementation uses the same tlsproxy(8) configuration for all
+/* tls_server_init() and tls_server_start() calls.
+/*
+/* pre_jail_init_server() creates an SSL context based on tlsproxy(8)
+/* server configuration.
+/*Begin TODO
+/* A future version will save a copy of serialized TLS_SERVER_PARAMS
+/* and TLS_SERVER_INIT_PROPS based on tlsproxy(8) server
+/* configuration. These will be used as a reference when receiving
+/* a request for the server role.
+/*
+/* tlsp_server_init() processes a request for the TLS proxy server
+/* role. If the request has not been seen before it checks the
+/* request for relevant differences that would conflict with
+/* tlsproxy(8) server configuration. The result is null when TLS
+/* is not available.
+/*End TODO
+/* tlsp_server_start_pre_handshake() requests the tls_server_start()
+/* handshake. It returns TLSP_STAT_OK when the request succeeds.
+/* Otherwise, it returns TLSP_STAT_ERR and state becomes a dangling
+/* pointer.
+/* DIAGNOSTICS
+/* Problems are logged to \fBsyslogd\fR(8) or \fBpostlogd\fR(8).
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* HISTORY
+/* .ad
+/* .fi
+/* This service was introduced with Postfix version 2.8.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*
+/* Wietse Venema
+/* porcupine.org
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <errno.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <mymalloc.h>
+
+ /*
+ * Global library.
+ */
+#include <mail_params.h>
+
+ /*
+ * TLS library.
+ */
+#ifdef USE_TLS
+#define TLS_INTERNAL /* XXX */
+#include <tls.h>
+#include <tls_proxy.h>
+
+ /*
+ * Application-specific.
+ */
+#include <tlsproxy.h>
+#include <tlsproxy_server.h>
+
+ /*
+ * TLS per-process status.
+ *
+ * TODO(wietse) delete externally visible state after tlsp_server_init() is
+ * implemented.
+ */
+TLS_APPL_STATE *tlsp_server_ctx;
+static int ask_client_cert;
+const char *server_role_disabled;
+
+/* tlsp_server_start_pre_handshake - turn on TLS or force disconnect */
+
+int tlsp_server_start_pre_handshake(TLSP_STATE *state)
+{
+ TLS_SERVER_START_PROPS props;
+ static char *cipher_grade;
+ static VSTRING *cipher_exclusions;
+
+ /*
+ * The code in this routine is pasted literally from smtpd(8). I am not
+ * going to sanitize this because doing so surely will break things in
+ * unexpected ways.
+ */
+
+ /*
+ * Perform the before-handshake portion of per-session initialization.
+ * Pass a null VSTREAM to indicate that this program will do the
+ * ciphertext I/O, not libtls.
+ *
+ * The cipher grade and exclusions don't change between sessions. Compute
+ * just once and cache.
+ */
+#define ADD_EXCLUDE(vstr, str) \
+ do { \
+ if (*(str)) \
+ vstring_sprintf_append((vstr), "%s%s", \
+ VSTRING_LEN(vstr) ? " " : "", (str)); \
+ } while (0)
+
+ if (cipher_grade == 0) {
+ cipher_grade =
+ var_tlsp_enforce_tls ? var_tlsp_tls_mand_ciph : var_tlsp_tls_ciph;
+ cipher_exclusions = vstring_alloc(10);
+ ADD_EXCLUDE(cipher_exclusions, var_tlsp_tls_excl_ciph);
+ if (var_tlsp_enforce_tls)
+ ADD_EXCLUDE(cipher_exclusions, var_tlsp_tls_mand_excl);
+ if (ask_client_cert)
+ ADD_EXCLUDE(cipher_exclusions, "aNULL");
+ }
+ state->tls_context =
+ TLS_SERVER_START(&props,
+ ctx = tlsp_server_ctx,
+ stream = (VSTREAM *) 0,/* unused */
+ fd = state->ciphertext_fd,
+ timeout = 0, /* unused */
+ requirecert = (var_tlsp_tls_req_ccert
+ && var_tlsp_enforce_tls),
+ enable_rpk = var_tlsp_tls_enable_rpk,
+ serverid = state->server_id,
+ namaddr = state->remote_endpt,
+ cipher_grade = cipher_grade,
+ cipher_exclusions = STR(cipher_exclusions),
+ mdalg = var_tlsp_tls_fpt_dgst);
+
+ if (state->tls_context == 0) {
+ tlsp_state_free(state);
+ return (TLSP_STAT_ERR);
+ }
+
+ /*
+ * XXX Do we care about TLS session rate limits? Good postscreen(8)
+ * clients will occasionally require the tlsproxy to renew their
+ * allowlist status, but bad clients hammering the server can suck up
+ * lots of CPU cycles. Per-client concurrency limits in postscreen(8)
+ * will divert only naive security "researchers".
+ */
+ return (TLSP_STAT_OK);
+}
+
+/* pre_jail_init_server - pre-jail initialization */
+
+void pre_jail_init_server(void)
+{
+ TLS_SERVER_INIT_PROPS props;
+ const char *cert_file;
+ int have_server_cert;
+ int no_server_cert_ok;
+ int require_server_cert;
+
+ /*
+ * The code in this routine is pasted literally from smtpd(8). I am not
+ * going to sanitize this because doing so surely will break things in
+ * unexpected ways.
+ */
+ if (*var_tlsp_tls_level) {
+ switch (tls_level_lookup(var_tlsp_tls_level)) {
+ default:
+ msg_fatal("Invalid TLS level \"%s\"", var_tlsp_tls_level);
+ /* NOTREACHED */
+ break;
+ case TLS_LEV_SECURE:
+ case TLS_LEV_VERIFY:
+ case TLS_LEV_FPRINT:
+ msg_warn("%s: unsupported TLS level \"%s\", using \"encrypt\"",
+ VAR_TLSP_TLS_LEVEL, var_tlsp_tls_level);
+ /* FALLTHROUGH */
+ case TLS_LEV_ENCRYPT:
+ var_tlsp_enforce_tls = var_tlsp_use_tls = 1;
+ break;
+ case TLS_LEV_MAY:
+ var_tlsp_enforce_tls = 0;
+ var_tlsp_use_tls = 1;
+ break;
+ case TLS_LEV_NONE:
+ var_tlsp_enforce_tls = var_tlsp_use_tls = 0;
+ break;
+ }
+ }
+ var_tlsp_use_tls = var_tlsp_use_tls || var_tlsp_enforce_tls;
+ if (!var_tlsp_use_tls) {
+ server_role_disabled = "TLS server role is disabled by configuration";
+ return;
+ }
+
+ /*
+ * Load TLS keys before dropping privileges.
+ *
+ * Can't use anonymous ciphers if we want client certificates. Must use
+ * anonymous ciphers if we have no certificates.
+ */
+ ask_client_cert = require_server_cert =
+ (var_tlsp_tls_ask_ccert
+ || (var_tlsp_enforce_tls && var_tlsp_tls_req_ccert));
+ if (strcasecmp(var_tlsp_tls_cert_file, "none") == 0) {
+ no_server_cert_ok = 1;
+ cert_file = "";
+ } else {
+ no_server_cert_ok = 0;
+ cert_file = var_tlsp_tls_cert_file;
+ }
+ have_server_cert =
+ (*cert_file || *var_tlsp_tls_dcert_file || *var_tlsp_tls_eccert_file);
+
+ if (*var_tlsp_tls_chain_files != 0) {
+ if (!have_server_cert)
+ have_server_cert = 1;
+ else
+ msg_warn("Both %s and one or more of the legacy "
+ " %s, %s or %s are non-empty; the legacy "
+ " parameters will be ignored",
+ VAR_TLSP_TLS_CHAIN_FILES,
+ VAR_TLSP_TLS_CERT_FILE,
+ VAR_TLSP_TLS_ECCERT_FILE,
+ VAR_TLSP_TLS_DCERT_FILE);
+ }
+ /* Some TLS configuration errors are not show stoppers. */
+ if (!have_server_cert && require_server_cert)
+ msg_warn("Need a server cert to request client certs");
+ if (!var_tlsp_enforce_tls && var_tlsp_tls_req_ccert)
+ msg_warn("Can't require client certs unless TLS is required");
+ /* After a show-stopper error, log a warning. */
+ if (have_server_cert || (no_server_cert_ok && !require_server_cert)) {
+
+ tls_pre_jail_init(TLS_ROLE_SERVER);
+
+ /*
+ * Large parameter lists are error-prone, so we emulate a language
+ * feature that C does not have natively: named parameter lists.
+ */
+ tlsp_server_ctx =
+ TLS_SERVER_INIT(&props,
+ log_param = VAR_TLSP_TLS_LOGLEVEL,
+ log_level = var_tlsp_tls_loglevel,
+ verifydepth = var_tlsp_tls_ccert_vd,
+ cache_type = TLS_MGR_SCACHE_SMTPD,
+ set_sessid = var_tlsp_tls_set_sessid,
+ chain_files = var_tlsp_tls_chain_files,
+ cert_file = cert_file,
+ key_file = var_tlsp_tls_key_file,
+ dcert_file = var_tlsp_tls_dcert_file,
+ dkey_file = var_tlsp_tls_dkey_file,
+ eccert_file = var_tlsp_tls_eccert_file,
+ eckey_file = var_tlsp_tls_eckey_file,
+ CAfile = var_tlsp_tls_CAfile,
+ CApath = var_tlsp_tls_CApath,
+ dh1024_param_file
+ = var_tlsp_tls_dh1024_param_file,
+ dh512_param_file
+ = var_tlsp_tls_dh512_param_file,
+ eecdh_grade = var_tlsp_tls_eecdh,
+ protocols = var_tlsp_enforce_tls ?
+ var_tlsp_tls_mand_proto :
+ var_tlsp_tls_proto,
+ ask_ccert = ask_client_cert,
+ mdalg = var_tlsp_tls_fpt_dgst);
+ } else {
+ msg_warn("No server certs available. TLS can't be enabled");
+ }
+
+ /*
+ * To maintain sanity, allow partial SSL_write() operations, and allow
+ * SSL_write() buffer pointers to change after a WANT_READ or WANT_WRITE
+ * result. This is based on OpenSSL developers talking on a mailing list,
+ * but is not supported by documentation. If this code stops working then
+ * no-one can be held responsible.
+ */
+ if (tlsp_server_ctx)
+ SSL_CTX_set_mode(tlsp_server_ctx->ssl_ctx,
+ SSL_MODE_ENABLE_PARTIAL_WRITE
+ | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+}
+
+#endif
--- /dev/null
+#ifndef _TLSPROXY_SERVER_H_
+#define _TLSPROXY_SERVER_H_
+
+/*++
+/* NAME
+/* tlsproxy_server 3h
+/* SUMMARY
+/* tlsproxy server role support
+/* SYNOPSIS
+/* #include <tlsproxy_server.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * TLS library.
+ */
+#include <tls.h>
+#include <tls_proxy.h>
+
+ /*
+ * Internal API.
+ */
+#include <tlsproxy.h>
+
+extern void pre_jail_init_server(void);
+extern TLS_APPL_STATE *tlsp_server_init(TLS_SERVER_PARAMS *, TLS_SERVER_INIT_PROPS *);
+extern int tlsp_server_start_pre_handshake(TLSP_STATE *);
+
+ /*
+ * TODO(wietse): delete these after tlsp_server_init() is implemented.
+ */
+extern TLS_APPL_STATE *tlsp_server_ctx;
+extern const char *server_role_disabled;
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*
+/* Wietse Venema
+/* porcupine.org
+/*--*/
+
+#endif
argvp = (ARGV *) mymalloc(sizeof(*argvp));
argvp->len = 0;
sane_len = (len < 2 ? 2 : len);
+ /* Peace, scanner. */
+ if (sane_len > SSIZE_MAX - 1)
+ msg_panic("argv_alloc: array length overflow");
argvp->argv = (char **) mymalloc((sane_len + 1) * sizeof(char *));
argvp->len = sane_len;
argvp->argc = 0;
ssize_t new_len;
/* 202604 Claude: avoid overflowing (new_len + 1) * sizeof(char *). */
- if (argvp->len + 1 > SSIZE_MAX / (2 * sizeof(char *)))
+ if (argvp->len > SSIZE_MAX / (2 * sizeof(char *)) - 1)
msg_panic("argv_extend: array length overflow");
new_len = argvp->len * 2;
argvp->argv = (char **)