]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.12-20260416 master
authorWietse Z Venema <wietse@porcupine.org>
Thu, 16 Apr 2026 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Fri, 17 Apr 2026 02:03:42 +0000 (12:03 +1000)
17 files changed:
postfix/HISTORY
postfix/proto/stop.double-history
postfix/proto/stop.spell-cc
postfix/src/global/mail_version.h
postfix/src/tls/tls_proxy_client_init_proto.c
postfix/src/tls/tls_proxy_client_param_proto.c
postfix/src/tls/tls_proxy_client_start_proto.c
postfix/src/tls/tls_proxy_server_init_proto.c
postfix/src/tls/tls_proxy_server_param_proto.c
postfix/src/tls/tls_proxy_server_start_proto.c
postfix/src/tlsproxy/Makefile.in
postfix/src/tlsproxy/tlsproxy.c
postfix/src/tlsproxy/tlsproxy.h
postfix/src/tlsproxy/tlsproxy_diff.c
postfix/src/tlsproxy/tlsproxy_server.c [new file with mode: 0644]
postfix/src/tlsproxy/tlsproxy_server.h [new file with mode: 0644]
postfix/src/util/argv.c

index 9bf3151a1135549ebd6d87462b6286cc24b91a1b..8fa7e5c054ff95014db5d4769fc770e6479d01ea 100644 (file)
@@ -30949,6 +30949,21 @@ Apologies for any names omitted.
        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.
index 13a35af1dbc8307e7fb3f98ad3309ec7995bdbbb..ddccc17fb5aef5d55baa4644f2950499c94eb2ad 100644 (file)
@@ -238,3 +238,4 @@ proto  proto stop proto stop double cc
  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 
index 627642a4960485dca44f090fc5047ae8deffff54..77f4e741718384d8779bcef8f8911c36919fa2ff 100644 (file)
@@ -1980,3 +1980,5 @@ PQerrorMessage
 deref
 openUTS
 xff
+nameN
+valueN
index 499f20c267f7cbcacb361086f5345ea78297c37c..3bff4b416052484e227ac773fc9c90884452ca10 100644 (file)
@@ -20,7 +20,7 @@
   * 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
index 18b293ae41384235bf34cb06f73fd4525e485883..eecdbdda3ba00cdfe23b9037c3120aaf888b3d42 100644 (file)
@@ -6,6 +6,8 @@
 /* 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
index b9bdb863e064982739a6ae897e55927942710c55..d0720519cf2e1439db6e82a5edd2fcc416e23445 100644 (file)
@@ -6,6 +6,8 @@
 /* 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
index 5e1bc913bb36f926e15cde33102795aa37cf7073..aef615acabcd206408d08bb21e03453b3efe4eb8 100644 (file)
@@ -6,6 +6,8 @@
 /* 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.
index 65860dfc2532f24937cdb8119fa0e451ca406f0f..f4cb7caa2c95937c81a5483037542b0e86b1fa15 100644 (file)
@@ -6,6 +6,8 @@
 /* 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
index 7675f264252b56a4f437620634135cae1e7dfbac..f7d059166735c9b11aad5063790c54f35d85383c 100644 (file)
@@ -9,6 +9,8 @@
 /*     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
index d480ec235c5524f14942a2c463e59d4afdc27a2e..b64dab3ee898ff1fad6eb0b242d97513a989e034 100644 (file)
@@ -6,6 +6,8 @@
 /* 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
index 69805eb9ff56f12a66d11cf5f6a1dcf1a16cd421..b2a401947e89fc08ea64caf0e1857782cc5ae2cc 100644 (file)
@@ -1,7 +1,9 @@
 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)
@@ -89,6 +91,7 @@ tlsproxy.o: ../../include/vstring.h
 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
@@ -155,6 +158,37 @@ tlsproxy_diff.o: ../../include/vstring.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
index e17b897b9c304a44bb7c9e260ceed06e3f0305b2..32951e4719ecbf91469a36d3af0e1cf3e3e1aa8f 100644 (file)
   */
 #include <tlsproxy.h>
 #include <tlsproxy_client.h>
+#include <tlsproxy_server.h>
 
  /*
   * Tunable parameters. We define our clones of the smtpd(8) parameters to
@@ -542,13 +543,6 @@ bool    var_tlsp_clnt_enforce_tls;
 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.
@@ -1021,75 +1015,6 @@ static void tlsp_ciphertext_event(int event, void *context)
     }
 }
 
-/* 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.
@@ -1348,139 +1273,6 @@ static void tlsp_service(VSTREAM *plaintext_stream,
                            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)
index 6fbc294f45be21046f7d069de4f3a004488735d8..a8a718cf3c860eb3edaa188c3a5fc157dd578256 100644 (file)
@@ -20,6 +20,8 @@
  /*
   * TLS library.
   */
+#ifdef USE_TLS
+
 #include <tls.h>
 #include <tls_proxy.h>
 
@@ -99,3 +101,5 @@ extern void tlsp_state_free(TLSP_STATE *);
 /*--*/
 
 #endif
+
+#endif
index a5fe6408350d117b3a2d91b93434c180bd4250a1..a9d057713938d2da3eeb45270271b4abf4d7bc6f 100644 (file)
  /*
   * 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.
@@ -90,3 +95,5 @@ void    tlsp_log_config_diff(const char *server_cfg, const char *client_cfg)
     myfree(saved_client);
     myfree(saved_server);
 }
+
+#endif
diff --git a/postfix/src/tlsproxy/tlsproxy_server.c b/postfix/src/tlsproxy/tlsproxy_server.c
new file mode 100644 (file)
index 0000000..c733bcb
--- /dev/null
@@ -0,0 +1,311 @@
+/*++
+/* 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
diff --git a/postfix/src/tlsproxy/tlsproxy_server.h b/postfix/src/tlsproxy/tlsproxy_server.h
new file mode 100644 (file)
index 0000000..f4938d2
--- /dev/null
@@ -0,0 +1,54 @@
+#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
index 56fc4501353a2a2c78a7b76ea2b3c5c268551f3d..8bc412f1847feaedec31b3bc73112eb678459387 100644 (file)
@@ -204,6 +204,9 @@ ARGV   *argv_alloc(ssize_t len)
     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;
@@ -263,7 +266,7 @@ static void argv_extend(ARGV *argvp)
     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 **)