]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.12-20260415
authorWietse Z Venema <wietse@porcupine.org>
Wed, 15 Apr 2026 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Thu, 16 Apr 2026 03:48:18 +0000 (13:48 +1000)
17 files changed:
postfix/HISTORY
postfix/proto/stop.double-history
postfix/src/global/dict_memcache.c
postfix/src/global/dict_mysql.c
postfix/src/global/dict_pgsql.c
postfix/src/global/mail_version.h
postfix/src/tls/tls_prng_file.c
postfix/src/tlsproxy/Makefile.in
postfix/src/tlsproxy/tlsproxy.c
postfix/src/tlsproxy/tlsproxy.h
postfix/src/tlsproxy/tlsproxy_client.c [new file with mode: 0644]
postfix/src/tlsproxy/tlsproxy_client.h [new file with mode: 0644]
postfix/src/tlsproxy/tlsproxy_diff.c [new file with mode: 0644]
postfix/src/tlsproxy/tlsproxy_diff.h [new file with mode: 0644]
postfix/src/util/argv.c
postfix/src/util/dict.c
postfix/src/util/dict_pcre.c

index a972260f334a3846adc8054a935dbbe98b100774..9bf3151a1135549ebd6d87462b6286cc24b91a1b 100644 (file)
@@ -30907,6 +30907,48 @@ Apologies for any names omitted.
        Testing: updated postscreen tests for changes in make_attr()
        API. File: src/postscreen/postscreen_dnsbl_test.c.
 
+20260415
+
+       Code health: verified zero functionality change. Factored
+       out tlsproxy code for client role management, in preparation
+       for overhaul of the code for server role management (which
+       will become very similar). Next up will be renaming identifiers
+       for consistency. Files: tlsproxy/tlsproxy.[hc],
+       tlsproxy/tlsproxy_client.[hc], tlsproxy/tlsproxy_diff.[hc].
+
+       Code health: renamed some identifiers for consistency.
+       Files: tlsproxy/tlsproxy_client.[hc].
+
+       Claude scan: the memcached server rejects control characters
+       in a text-protocol key, but it is better if Postfix rejects
+       such keys, because that produces a better-quality error
+       message. File: global/dict_memcache.c.
+
+       Claude scan: the MySQL client used an unsigned int for the
+       server port variable, but the find_inet_service() function
+       returns -1 after an error which is converted to unsigned,
+       resulting in no error message from Postfix, and a low-quality
+       error message from the MySQL client library. Changed the
+       port variable type to a signed int, so that Postfix will
+       log its better error message. File: global/dict_mysql.c.
+
+       Claude scan: the PostgreSQL client strategy to recover from
+       an error in PQescapeStringConn() needed clarification. File:
+       global/dict_pgsql.c.
+
+       Claude scan: remove %m (errno to string) from non-error logging.
+       File: tls/tls_prng_file.c.
+
+       Claude scan: the recent argv.c fix should count the number
+       of bytes per (char *) pointer. File: util/argv.c.
+
+       Claude scan: dict_walk() was broken (but never called). File:
+       util/dict.c.
+
+       Claude scan: handle a pcre2_match_data_create_from_pattern()
+       out-of-memory error, instead of letting the PCRE2 library
+       silently skip a rule. File: util/dict_pcre.c.
+
 TODO
 
        Reorganize PTEST_LIB, PMOCK_LIB, TESTLIB, TESTLIBS, etc.
index 60aa8aff8a9992ae48925a8f1ffa31747e4d114b..13a35af1dbc8307e7fb3f98ad3309ec7995bdbbb 100644 (file)
@@ -237,3 +237,4 @@ proto  proto stop proto stop double cc
  proxymap proxymap c smtp smtp_proto c smtpd smtpd_expand c 
  Files tlsproxy tlsproxy c tlsproxy tlsproxy h 
  Files tlsproxy tlsproxy c tlsproxy tlsproxy h 
+ for consistency Files tlsproxy tlsproxy hc 
index 0b6dcc027a590424bb497f53d56564a6d9835a30..0351c0bf10c4910043a4e799fbea9c9e868b04ee 100644 (file)
@@ -343,8 +343,9 @@ static int dict_memcache_valid_key(DICT_MC *dict_mc,
     if (rc < 0)
        DICT_ERR_VAL_RETURN(dict_mc, rc, 0);
     for (cp = (unsigned char *) STR(dict_mc->key_buf); *cp; cp++)
-       if (isascii(*cp) && isspace(*cp))
-           DICT_MC_SKIP("name contains space");
+       /* 202604 Claude: memcached rejects control characters in key. */
+       if (ISSPACE(*cp) || ISCNTRL(*cp))
+           DICT_MC_SKIP("name contains space or controls");
 
     DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, 1);
 }
index c0affafec6d47a741e63563ec0bfeffcaa3df687..482e6180d178e0ae9624fa03c1cae0cc88899289 100644 (file)
@@ -135,7 +135,8 @@ typedef struct {
     MYSQL  *db;
     char   *hostname;
     char   *name;
-    unsigned port;
+    /* 202604 Claude: find_inet_service() returns -1 on error. */
+    int     port;
     unsigned type;                     /* TYPEUNIX | TYPEINET */
     unsigned stat;                     /* STATUNTRIED | STATFAIL | STATCUR */
     time_t  ts;                                /* used for attempting reconnection
index 6bf2622bcb566d0a86fd32bc7f152dcf0f6ba81d..65cd138af318e070f2aa5912c10fe0cb57149ce0 100644 (file)
@@ -191,11 +191,17 @@ static void dict_pgsql_quote(DICT *dict, const char *name, VSTRING *result)
     buflen = 2 * len + 1;
 
     /*
-     * XXX Workaround: stop further processing when PQescapeStringConn()
-     * (below) fails. A more proper fix requires invasive changes, not
-     * suitable for a stable release.
+     * 202604 Claude: error recovery strategy needs clarification.
+     * 
+     * When the PQescapeStringConn() call below fails, we flag the host via
+     * active_host->stat = STATFAIL and return without writing to `result`.
+     * plpgsql_query() examines host->stat immediately after
+     * db_common_expand() returns, calls plpgsql_down_host(), and tries the
+     * next available server (i.e. not already flagged as STATFAIL).
+     * dict_pgsql_lookup() sets dict->error = DICT_ERR_RETRY if all servers
+     * fail.
      */
-    if (active_host->stat == STATFAIL)
+    if (active_host->stat == STATFAIL)         /* Can't happen */
        return;
 
     /*
index 4653dea22ad5db3deaa7b0442acd90490e933a89..499f20c267f7cbcacb361086f5345ea78297c37c 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      "20260413"
+#define MAIL_RELEASE_DATE      "20260415"
 #define MAIL_VERSION_NUMBER    "3.12"
 
 #ifdef SNAPSHOT
index 23865be39db8df64bffa419542038e45210165bf..c2a05b006355ea1091883c2c8a803bc87f022e71 100644 (file)
@@ -118,7 +118,7 @@ ssize_t tls_prng_file_read(TLS_PRNG_SRC *fh, size_t len)
            msg_info("cannot seek entropy file %s: %m", fh->name);
        return (-1);
     }
-    errno = 0;
+    /* 202604 Claude: no need to reset errno. */
     for (to_read = len; to_read > 0; to_read -= count) {
        if ((count = timed_read(fh->fd, buffer, to_read > sizeof(buffer) ?
                                sizeof(buffer) : to_read,
@@ -132,7 +132,8 @@ ssize_t tls_prng_file_read(TLS_PRNG_SRC *fh, size_t len)
        RAND_seed(buffer, count);
     }
     if (msg_verbose)
-       msg_info("read %ld bytes from entropy file %s: %m",
+       /* 202604 Claude: remove '%m' from non-error logging. */
+       msg_info("read %ld bytes from entropy file %s",
                 (long) (len - to_read), fh->name);
     return (len - to_read);
 }
index 2b6d34589595da9138039b806dada683b0eeea85..69805eb9ff56f12a66d11cf5f6a1dcf1a16cd421 100644 (file)
@@ -1,7 +1,7 @@
 SHELL  = /bin/sh
-SRCS   = tlsproxy.c tlsproxy_state.c
-OBJS   = tlsproxy.o tlsproxy_state.o
-HDRS   = 
+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
 TESTSRC        =
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@@ -75,12 +75,86 @@ tlsproxy.o: ../../include/split_at.h
 tlsproxy.o: ../../include/sys_defs.h
 tlsproxy.o: ../../include/tls.h
 tlsproxy.o: ../../include/tls_proxy.h
+tlsproxy.o: ../../include/tls_proxy_attr.h
+tlsproxy.o: ../../include/tls_proxy_client_init_proto.h
+tlsproxy.o: ../../include/tls_proxy_client_param_proto.h
+tlsproxy.o: ../../include/tls_proxy_client_start_proto.h
+tlsproxy.o: ../../include/tls_proxy_server_init_proto.h
+tlsproxy.o: ../../include/tls_proxy_server_param_proto.h
+tlsproxy.o: ../../include/tls_proxy_server_start_proto.h
 tlsproxy.o: ../../include/tlsrpt_wrapper.h
 tlsproxy.o: ../../include/vbuf.h
 tlsproxy.o: ../../include/vstream.h
 tlsproxy.o: ../../include/vstring.h
 tlsproxy.o: tlsproxy.c
 tlsproxy.o: tlsproxy.h
+tlsproxy.o: tlsproxy_client.h
+tlsproxy_client.o: ../../include/argv.h
+tlsproxy_client.o: ../../include/attr.h
+tlsproxy_client.o: ../../include/been_here.h
+tlsproxy_client.o: ../../include/check_arg.h
+tlsproxy_client.o: ../../include/dns.h
+tlsproxy_client.o: ../../include/events.h
+tlsproxy_client.o: ../../include/htable.h
+tlsproxy_client.o: ../../include/iostuff.h
+tlsproxy_client.o: ../../include/mail_params.h
+tlsproxy_client.o: ../../include/mail_proto.h
+tlsproxy_client.o: ../../include/msg.h
+tlsproxy_client.o: ../../include/myaddrinfo.h
+tlsproxy_client.o: ../../include/mymalloc.h
+tlsproxy_client.o: ../../include/name_code.h
+tlsproxy_client.o: ../../include/name_mask.h
+tlsproxy_client.o: ../../include/nbbio.h
+tlsproxy_client.o: ../../include/nvtable.h
+tlsproxy_client.o: ../../include/sock_addr.h
+tlsproxy_client.o: ../../include/sys_defs.h
+tlsproxy_client.o: ../../include/tls.h
+tlsproxy_client.o: ../../include/tls_proxy.h
+tlsproxy_client.o: ../../include/tls_proxy_attr.h
+tlsproxy_client.o: ../../include/tls_proxy_client_init_proto.h
+tlsproxy_client.o: ../../include/tls_proxy_client_param_proto.h
+tlsproxy_client.o: ../../include/tls_proxy_client_start_proto.h
+tlsproxy_client.o: ../../include/tls_proxy_server_init_proto.h
+tlsproxy_client.o: ../../include/tls_proxy_server_param_proto.h
+tlsproxy_client.o: ../../include/tls_proxy_server_start_proto.h
+tlsproxy_client.o: ../../include/vbuf.h
+tlsproxy_client.o: ../../include/vstream.h
+tlsproxy_client.o: ../../include/vstring.h
+tlsproxy_client.o: tlsproxy.h
+tlsproxy_client.o: tlsproxy_client.c
+tlsproxy_client.o: tlsproxy_client.h
+tlsproxy_client.o: tlsproxy_diff.h
+tlsproxy_diff.o: ../../include/argv.h
+tlsproxy_diff.o: ../../include/attr.h
+tlsproxy_diff.o: ../../include/check_arg.h
+tlsproxy_diff.o: ../../include/dns.h
+tlsproxy_diff.o: ../../include/events.h
+tlsproxy_diff.o: ../../include/htable.h
+tlsproxy_diff.o: ../../include/msg.h
+tlsproxy_diff.o: ../../include/myaddrinfo.h
+tlsproxy_diff.o: ../../include/mymalloc.h
+tlsproxy_diff.o: ../../include/name_code.h
+tlsproxy_diff.o: ../../include/name_mask.h
+tlsproxy_diff.o: ../../include/nbbio.h
+tlsproxy_diff.o: ../../include/nvtable.h
+tlsproxy_diff.o: ../../include/sock_addr.h
+tlsproxy_diff.o: ../../include/split_at.h
+tlsproxy_diff.o: ../../include/sys_defs.h
+tlsproxy_diff.o: ../../include/tls.h
+tlsproxy_diff.o: ../../include/tls_proxy.h
+tlsproxy_diff.o: ../../include/tls_proxy_attr.h
+tlsproxy_diff.o: ../../include/tls_proxy_client_init_proto.h
+tlsproxy_diff.o: ../../include/tls_proxy_client_param_proto.h
+tlsproxy_diff.o: ../../include/tls_proxy_client_start_proto.h
+tlsproxy_diff.o: ../../include/tls_proxy_server_init_proto.h
+tlsproxy_diff.o: ../../include/tls_proxy_server_param_proto.h
+tlsproxy_diff.o: ../../include/tls_proxy_server_start_proto.h
+tlsproxy_diff.o: ../../include/vbuf.h
+tlsproxy_diff.o: ../../include/vstream.h
+tlsproxy_diff.o: ../../include/vstring.h
+tlsproxy_diff.o: tlsproxy.h
+tlsproxy_diff.o: tlsproxy_diff.c
+tlsproxy_diff.o: tlsproxy_diff.h
 tlsproxy_state.o: ../../include/argv.h
 tlsproxy_state.o: ../../include/attr.h
 tlsproxy_state.o: ../../include/check_arg.h
@@ -100,6 +174,13 @@ tlsproxy_state.o: ../../include/sock_addr.h
 tlsproxy_state.o: ../../include/sys_defs.h
 tlsproxy_state.o: ../../include/tls.h
 tlsproxy_state.o: ../../include/tls_proxy.h
+tlsproxy_state.o: ../../include/tls_proxy_attr.h
+tlsproxy_state.o: ../../include/tls_proxy_client_init_proto.h
+tlsproxy_state.o: ../../include/tls_proxy_client_param_proto.h
+tlsproxy_state.o: ../../include/tls_proxy_client_start_proto.h
+tlsproxy_state.o: ../../include/tls_proxy_server_init_proto.h
+tlsproxy_state.o: ../../include/tls_proxy_server_param_proto.h
+tlsproxy_state.o: ../../include/tls_proxy_server_start_proto.h
 tlsproxy_state.o: ../../include/vbuf.h
 tlsproxy_state.o: ../../include/vstream.h
 tlsproxy_state.o: ../../include/vstring.h
index d9c48001af3b54e560403c8020f6dedbe7ec0617..e17b897b9c304a44bb7c9e260ceed06e3f0305b2 100644 (file)
   * Application-specific.
   */
 #include <tlsproxy.h>
+#include <tlsproxy_client.h>
 
  /*
   * Tunable parameters. We define our clones of the smtpd(8) parameters to
@@ -545,36 +546,9 @@ char   *var_tlsp_clnt_policy;
   * TLS per-process status.
   */
 static TLS_APPL_STATE *tlsp_server_ctx;
-static bool tlsp_pre_jail_done;
 static int ask_client_cert;
-static char *tlsp_pre_jail_client_param_key;   /* pre-jail global params */
-static char *tlsp_pre_jail_client_init_key;    /* pre-jail init props */
 static const char *server_role_disabled;
 
- /*
-  * TLS per-client status.
-  */
-static HTABLE *tlsp_client_app_cache;  /* per-client init props */
-static BH_TABLE *tlsp_params_mismatch_filter;  /* per-client nag filter */
-
- /*
-  * Error handling: if a function detects an error, then that function is
-  * responsible for destroying TLSP_STATE. Exceptions to this principle are
-  * indicated in the code.
-  */
-
- /*
-  * Internal status API.
-  */
-#define TLSP_STAT_OK   0
-#define TLSP_STAT_ERR  (-1)
-
- /*
-  * SLMs.
-  */
-#define STR(x) vstring_str(x)
-#define LEN(x) VSTRING_LEN(x)
-
  /*
   * 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.
@@ -1047,20 +1021,6 @@ static void tlsp_ciphertext_event(int event, void *context)
     }
 }
 
-/* tlsp_client_start_pre_handshake - turn on TLS or force disconnect */
-
-static int tlsp_client_start_pre_handshake(TLSP_STATE *state)
-{
-    state->client_start_props->ctx = state->appl_state;
-    state->client_start_props->fd = state->ciphertext_fd;
-    state->tls_context = tls_client_start(state->client_start_props);
-    if (state->tls_context != 0)
-       return (TLSP_STAT_OK);
-
-    tlsp_state_free(state);
-    return (TLSP_STAT_ERR);
-}
-
 /* tlsp_server_start_pre_handshake - turn on TLS or force disconnect */
 
 static int tlsp_server_start_pre_handshake(TLSP_STATE *state)
@@ -1207,176 +1167,6 @@ static void tlsp_get_fd_event(int event, void *context)
     /* At this point, state could be a dangling pointer. */
 }
 
-/* tlsp_config_diff - report server-client config differences */
-
-static void tlsp_log_config_diff(const char *server_cfg, const char *client_cfg)
-{
-    VSTRING *diff_summary = vstring_alloc(100);
-    char   *saved_server = mystrdup(server_cfg);
-    char   *saved_client = mystrdup(client_cfg);
-    char   *server_field;
-    char   *client_field;
-    char   *server_next;
-    char   *client_next;
-
-    /*
-     * Not using argv_split(), because it would treat multiple consecutive
-     * newline characters as one.
-     */
-    for (server_field = saved_server, client_field = saved_client;
-        server_field && client_field;
-        server_field = server_next, client_field = client_next) {
-       server_next = split_at(server_field, '\n');
-       client_next = split_at(client_field, '\n');
-       if (strcmp(server_field, client_field) != 0) {
-           if (LEN(diff_summary) > 0)
-               vstring_sprintf_append(diff_summary, "; ");
-           vstring_sprintf_append(diff_summary,
-                                  "(server) '%s' != (client) '%s'",
-                                  server_field, client_field);
-       }
-    }
-    msg_warn("%s", STR(diff_summary));
-
-    vstring_free(diff_summary);
-    myfree(saved_client);
-    myfree(saved_server);
-}
-
-/* tlsp_client_init - initialize a TLS client engine */
-
-static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params,
-                                         TLS_CLIENT_INIT_PROPS *init_props)
-{
-    TLS_APPL_STATE *appl_state;
-    VSTRING *param_buf;
-    char   *param_key;
-    VSTRING *init_buf;
-    char   *init_key;
-    int     log_hints = 0;
-
-    /*
-     * Use one TLS_APPL_STATE object for all requests that specify the same
-     * TLS_CLIENT_INIT_PROPS. Each TLS_APPL_STATE owns an SSL_CTX, which is
-     * expensive to create. Bug: TLS_CLIENT_PARAMS are not used when creating
-     * a TLS_APPL_STATE instance.
-     * 
-     * First, compute the TLS_APPL_STATE cache lookup key. Save a copy of the
-     * pre-jail request TLS_CLIENT_PARAMS and TLSPROXY_CLIENT_INIT_PROPS
-     * settings, so that we can detect post-jail requests that do not match.
-     */
-    param_buf = vstring_alloc(100);
-    param_key = tls_proxy_client_param_serialize(attr_print_plain, param_buf,
-                                                tls_params);
-    init_buf = vstring_alloc(100);
-    init_key = tls_proxy_client_init_serialize(attr_print_plain, init_buf,
-                                              init_props);
-#define TLSP_CLIENT_INIT_RETURN(retval) do { \
-       vstring_free(init_buf); \
-       vstring_free(param_buf); \
-       return (retval); \
-    } while (0)
-
-    if (tlsp_pre_jail_done == 0) {
-       if (tlsp_pre_jail_client_param_key == 0
-           || tlsp_pre_jail_client_init_key == 0) {
-           tlsp_pre_jail_client_param_key = mystrdup(param_key);
-           tlsp_pre_jail_client_init_key = mystrdup(init_key);
-       } else if (strcmp(tlsp_pre_jail_client_param_key, param_key) != 0
-                  || strcmp(tlsp_pre_jail_client_init_key, init_key) != 0) {
-           msg_panic("tlsp_client_init: too many pre-jail calls");
-       }
-    }
-
-    /*
-     * Log a warning if a post-jail request uses unexpected TLS_CLIENT_PARAMS
-     * settings. Bug: TLS_CLIENT_PARAMS settings are not used when creating a
-     * TLS_APPL_STATE instance; this makes a mismatch of TLS_CLIENT_PARAMS
-     * settings problematic.
-     */
-    else if (tlsp_pre_jail_client_param_key == 0
-            || tlsp_pre_jail_client_init_key == 0) {
-       msg_warn("TLS client role is disabled by configuration");
-       TLSP_CLIENT_INIT_RETURN(0);
-    } else if (!been_here_fixed(tlsp_params_mismatch_filter, param_key)
-              && strcmp(tlsp_pre_jail_client_param_key, param_key) != 0) {
-       msg_warn("request from tlsproxy client with unexpected settings");
-       tlsp_log_config_diff(tlsp_pre_jail_client_param_key, param_key);
-       log_hints = 1;
-    }
-
-    /*
-     * Look up the cached TLS_APPL_STATE for this tls_client_init request.
-     */
-    if ((appl_state = (TLS_APPL_STATE *)
-        htable_find(tlsp_client_app_cache, init_key)) == 0) {
-
-       /*
-        * Before creating a TLS_APPL_STATE instance, log a warning if a
-        * post-jail request differs from the saved pre-jail request AND the
-        * post-jail request specifies file/directory pathname arguments.
-        * Unexpected requests containing pathnames are problematic after
-        * chroot (pathname resolution) and after dropping privileges (key
-        * files must be root read-only). Unexpected requests are not a
-        * problem as long as they contain no pathnames (for example a
-        * tls_loglevel change).
-        * 
-        * We could eliminate some of this complication by adding code that
-        * opens a cert/key lookup table at pre-jail time, and by reading
-        * cert/key info on-the-fly from that table. But then all requests
-        * would still have to specify the same table.
-        */
-#define NOT_EMPTY(x) ((x) && *(x))
-
-       if (tlsp_pre_jail_done
-           && strcmp(tlsp_pre_jail_client_init_key, init_key) != 0
-           && (NOT_EMPTY(init_props->chain_files)
-               || NOT_EMPTY(init_props->cert_file)
-               || NOT_EMPTY(init_props->key_file)
-               || NOT_EMPTY(init_props->dcert_file)
-               || NOT_EMPTY(init_props->dkey_file)
-               || NOT_EMPTY(init_props->eccert_file)
-               || NOT_EMPTY(init_props->eckey_file)
-               || NOT_EMPTY(init_props->CAfile)
-               || NOT_EMPTY(init_props->CApath))) {
-           msg_warn("request from tlsproxy client with unexpected settings");
-           tlsp_log_config_diff(tlsp_pre_jail_client_init_key, init_key);
-           log_hints = 1;
-       }
-    }
-    if (log_hints)
-       msg_warn("to avoid this warning, 1) identify the tlsproxy "
-                "client that is making this request, 2) configure "
-                "a custom tlsproxy service with settings that "
-                "match that tlsproxy client, and 3) configure "
-                "that tlsproxy client with a tlsproxy_service_name "
-                "setting that resolves to that custom tlsproxy "
-                "service");
-
-    /*
-     * TLS_APPL_STATE creation may fail when a post-jail request specifies
-     * unexpected cert/key information, but that is OK because we already
-     * logged a warning with configuration suggestions.
-     */
-    if (appl_state == 0
-       && (appl_state = tls_client_init(init_props)) != 0) {
-       (void) htable_enter(tlsp_client_app_cache, init_key,
-                           (void *) appl_state);
-
-       /*
-        * 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.
-        */
-       SSL_CTX_set_mode(appl_state->ssl_ctx,
-                        SSL_MODE_ENABLE_PARTIAL_WRITE
-                        | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-    }
-    TLSP_CLIENT_INIT_RETURN(appl_state);
-}
-
 /* tlsp_close_event - pre-handshake plaintext-client close event */
 
 static void tlsp_close_event(int event, void *context)
@@ -1691,126 +1481,6 @@ static void pre_jail_init_server(void)
                         | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
 }
 
-/* pre_jail_init_client - pre-jail initialization */
-
-static void pre_jail_init_client(void)
-{
-    int     clnt_use_tls;
-
-    /*
-     * The cache with TLS_APPL_STATE instances for different TLS_CLIENT_INIT
-     * configurations.
-     */
-    tlsp_client_app_cache = htable_create(10);
-
-    /* Postfix <= 3.10 backwards compatibility. */
-    if (warn_compat_break_tlsp_clnt_level
-       && warn_compat_break_smtp_tls_level)
-       msg_info("using backwards-compatible default setting "
-                VAR_TLSP_CLNT_LEVEL "=(empty)");
-
-    /*
-     * Most sites don't use TLS client certs/keys. In that case, enabling
-     * tlsproxy-based connection caching is trivial.
-     * 
-     * But some sites do use TLS client certs/keys, and that is challenging when
-     * tlsproxy runs in a post-jail environment: chroot breaks pathname
-     * resolution, and an unprivileged process should not be able to open
-     * files with secrets. The workaround: assume that most of those sites
-     * will use a fixed TLS client identity. In that case, tlsproxy can load
-     * the corresponding certs/keys at pre-jail time, so that secrets can
-     * remain read-only for root. As long as the tlsproxy pre-jail TLS client
-     * configuration with cert or key pathnames is the same as the one used
-     * in the Postfix SMTP client, sites can selectively or globally enable
-     * tlsproxy-based connection caching without additional TLS
-     * configuration.
-     * 
-     * Loading one TLS client configuration at pre-jail time is not sufficient
-     * for the minority of sites that want to use TLS connection caching with
-     * multiple TLS client identities. To alert the operator, tlsproxy will
-     * log a warning when a TLS_CLIENT_INIT message specifies a different
-     * configuration than the tlsproxy pre-jail client configuration, and
-     * that different configuration specifies file/directory pathname
-     * arguments. The workaround is to have one tlsproxy process per TLS
-     * client identity.
-     * 
-     * The general solution for single-identity or multi-identity clients is to
-     * stop loading certs and keys from individual files. Instead, have a
-     * cert/key map, indexed by client identity, read-only by root. After
-     * opening the map as root at pre-jail time, tlsproxy can read certs/keys
-     * on-the-fly as an unprivileged process at post-jail time. This is the
-     * approach that was already proposed for server-side SNI support, and it
-     * could be reused here. It would also end the proliferation of RSA
-     * cert/key parameters, DSA cert/key parameters, EC cert/key parameters,
-     * and so on.
-     * 
-     * Horror: In order to create the same pre-jail TLS client context as the
-     * one used in the Postfix SMTP client, we have to duplicate intricate
-     * SMTP client code, including a handful configuration parameters that
-     * tlsproxy does not need. We must duplicate the logic, so that we only
-     * load certs and keys when the SMTP client would load them.
-     */
-    if (*var_tlsp_clnt_level != 0)
-       switch (tls_level_lookup(var_tlsp_clnt_level)) {
-       case TLS_LEV_SECURE:
-       case TLS_LEV_VERIFY:
-       case TLS_LEV_DANE_ONLY:
-       case TLS_LEV_FPRINT:
-       case TLS_LEV_ENCRYPT:
-           var_tlsp_clnt_use_tls = var_tlsp_clnt_enforce_tls = 1;
-           break;
-       case TLS_LEV_DANE:
-       case TLS_LEV_MAY:
-           var_tlsp_clnt_use_tls = 1;
-           var_tlsp_clnt_enforce_tls = 0;
-           break;
-       case TLS_LEV_NONE:
-           var_tlsp_clnt_use_tls = var_tlsp_clnt_enforce_tls = 0;
-           break;
-       default:
-           /* tls_level_lookup() logs no warning. */
-           /* session_tls_init() assumes that var_tlsp_clnt_level is sane. */
-           msg_fatal("Invalid TLS level \"%s\"", var_tlsp_clnt_level);
-       }
-    clnt_use_tls = (var_tlsp_clnt_use_tls || var_tlsp_clnt_enforce_tls);
-
-    /*
-     * Initialize the TLS data before entering the chroot jail.
-     */
-    if (clnt_use_tls || var_tlsp_clnt_per_site[0] || var_tlsp_clnt_policy[0]) {
-       TLS_CLIENT_PARAMS tls_params;
-       TLS_CLIENT_INIT_PROPS init_props;
-
-       tls_pre_jail_init(TLS_ROLE_CLIENT);
-
-       /*
-        * We get stronger type safety and a cleaner interface by combining
-        * the various parameters into a single tls_client_props structure.
-        * 
-        * Large parameter lists are error-prone, so we emulate a language
-        * feature that C does not have natively: named parameter lists.
-        */
-       (void) tls_proxy_client_param_from_config(&tls_params);
-       (void) TLS_CLIENT_INIT_ARGS(&init_props,
-                                   log_param = var_tlsp_clnt_logparam,
-                                   log_level = var_tlsp_clnt_loglevel,
-                                   verifydepth = var_tlsp_clnt_scert_vd,
-                                   cache_type = TLS_MGR_SCACHE_SMTP,
-                                   chain_files = var_tlsp_clnt_chain_files,
-                                   cert_file = var_tlsp_clnt_cert_file,
-                                   key_file = var_tlsp_clnt_key_file,
-                                   dcert_file = var_tlsp_clnt_dcert_file,
-                                   dkey_file = var_tlsp_clnt_dkey_file,
-                                   eccert_file = var_tlsp_clnt_eccert_file,
-                                   eckey_file = var_tlsp_clnt_eckey_file,
-                                   CAfile = var_tlsp_clnt_CAfile,
-                                   CApath = var_tlsp_clnt_CApath,
-                                   mdalg = var_tlsp_clnt_fpt_dgst);
-       if (tlsp_client_init(&tls_params, &init_props) == 0)
-           msg_warn("TLS client initialization failed");
-    }
-}
-
 /* pre_jail_init - pre-jail initialization */
 
 static void pre_jail_init(char *unused_name, char **unused_argv)
@@ -1820,19 +1490,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
      * Initialize roles separately.
      */
     pre_jail_init_server();
-    pre_jail_init_client();
-
-    /*
-     * tlsp_client_init() needs to know if it is called pre-jail or
-     * post-jail.
-     */
-    tlsp_pre_jail_done = 1;
-
-    /*
-     * Bug: TLS_CLIENT_PARAMS attributes are not used when creating a
-     * TLS_APPL_STATE instance; we can only warn about attribute mismatches.
-     */
-    tlsp_params_mismatch_filter = been_here_init(BH_BOUND_NONE, BH_FLAG_NONE);
+    tlsp_pre_jail_client_init();
 }
 
 MAIL_VERSION_STAMP_DECLARE;
index b3223ab7425201d45b0d49f984ba2da536ef9513..6fbc294f45be21046f7d069de4f3a004488735d8 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _TLSPROXY_H_INCLUDED_
+#define _TLSPROXY_H_INCLUDED_
+
 /*++
 /* NAME
 /*     tlsproxy 3h
@@ -18,6 +21,7 @@
   * TLS library.
   */
 #include <tls.h>
+#include <tls_proxy.h>
 
  /*
   * Internal interface.
@@ -53,6 +57,28 @@ typedef struct {
 extern TLSP_STATE *tlsp_state_create(const char *, VSTREAM *);
 extern void tlsp_state_free(TLSP_STATE *);
 
+ /*
+  * Error handling: if a function detects an error, then that function is
+  * responsible for destroying TLSP_STATE. Exceptions to this principle are
+  * indicated in the code.
+  * 
+  * TODO(wietse) Revisit this contract. Destroying state violates layering.
+  * Maybe encapsulate the error returning action in a wrapper that destroys
+  * state.
+  */
+
+ /*
+  * Internal status API.
+  */
+#define TLSP_STAT_OK    0
+#define TLSP_STAT_ERR   (-1)
+
+ /*
+  * SLMs.
+  */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
 /* LICENSE
 /* .ad
 /* .fi
@@ -71,3 +97,5 @@ extern void tlsp_state_free(TLSP_STATE *);
 /*     Wietse Venema
 /*     porcupine.org
 /*--*/
+
+#endif
diff --git a/postfix/src/tlsproxy/tlsproxy_client.c b/postfix/src/tlsproxy/tlsproxy_client.c
new file mode 100644 (file)
index 0000000..cb638b3
--- /dev/null
@@ -0,0 +1,389 @@
+/*++
+/* NAME
+/*     tlsproxy_client 3
+/* SUMMARY
+/*     Postfix TLS proxy client role support
+/* SYNOPSIS
+/*     #include <tlsproxy_client.h>
+/*
+/*     void tlsp_pre_jail_client_init(void)
+/*
+/*     TLS_APPL_STATE *tlsp_client_init(
+/*     TLS_CLIENT_PARAMS *tls_params,
+/*     TLS_CLIENT_INIT_PROPS *init_props)
+/*
+/*     int     tlsp_client_start_pre_handshake(TLSP_STATE *state)
+/* DESCRIPTION
+/*     This module implements TLS proxy client role support.
+/*
+/*     tlsp_pre_jail_client_init() saves a copy of serialized
+/*     TLS_CLIENT_PARAMS and TLS_CLIENT_INIT_PROPS based on configuration
+/*     parameter settings. These will be used as a reference when
+/*     receiving a request for the client role.
+/*
+/*     tlsp_client_init() processes a request for the TLS proxy client
+/*     role. If the request has not been seen before it checks the
+/*     request for relevant differences that would conflict with
+/*     tlsproxy(8) client configuration. The result is null when
+/*     TLS is not available.
+/*
+/*     tlsp_client_start_pre_handshake() requests the tls_client_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 and transactions 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>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <mymalloc.h>
+
+ /*
+  * Global library.
+  */
+#include <been_here.h>
+#include <mail_proto.h>
+#include <mail_params.h>
+
+ /*
+  * TLS library.
+  */
+#ifdef USE_TLS
+#define TLS_INTERNAL                   /* XXX */
+#include <tls.h>
+#include <tls_proxy.h>
+
+ /*
+  * Application-specific.
+  */
+#include <tlsproxy_client.h>
+#include <tlsproxy_diff.h>
+
+ /*
+  * TLS per-process status.
+  */
+static bool tlsp_pre_jail_client_done;
+static char *tlsp_pre_jail_client_param_key;   /* pre-jail global params */
+static char *tlsp_pre_jail_client_init_key;    /* pre-jail init props */
+
+ /*
+  * TLS per-client status.
+  */
+static HTABLE *tlsp_client_app_cache;  /* per-client init props */
+static BH_TABLE *tlsp_client_params_nag_filter;        /* per-client nag filter */
+
+/* tlsp_client_start_pre_handshake - turn on TLS or force disconnect */
+
+int     tlsp_client_start_pre_handshake(TLSP_STATE *state)
+{
+    state->client_start_props->ctx = state->appl_state;
+    state->client_start_props->fd = state->ciphertext_fd;
+    state->tls_context = tls_client_start(state->client_start_props);
+    if (state->tls_context != 0)
+       return (TLSP_STAT_OK);
+
+    tlsp_state_free(state);
+    return (TLSP_STAT_ERR);
+}
+
+/* tlsp_client_init - initialize a TLS client engine */
+
+TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params,
+                                        TLS_CLIENT_INIT_PROPS *init_props)
+{
+    TLS_APPL_STATE *appl_state;
+    VSTRING *param_buf;
+    char   *param_key;
+    VSTRING *init_buf;
+    char   *init_key;
+    int     log_hints = 0;
+
+    /*
+     * Use one TLS_APPL_STATE object for all requests that specify the same
+     * TLS_CLIENT_INIT_PROPS. Each TLS_APPL_STATE owns an SSL_CTX, which is
+     * expensive to create. Bug: TLS_CLIENT_PARAMS are not used when creating
+     * a TLS_APPL_STATE instance.
+     * 
+     * First, compute the TLS_APPL_STATE cache lookup key. Save a copy of the
+     * pre-jail request TLS_CLIENT_PARAMS and TLSPROXY_CLIENT_INIT_PROPS
+     * settings, so that we can detect post-jail requests that do not match.
+     */
+    param_buf = vstring_alloc(100);
+    param_key = tls_proxy_client_param_serialize(attr_print_plain, param_buf,
+                                                tls_params);
+    init_buf = vstring_alloc(100);
+    init_key = tls_proxy_client_init_serialize(attr_print_plain, init_buf,
+                                              init_props);
+#define TLSP_CLIENT_INIT_RETURN(retval) do { \
+       vstring_free(init_buf); \
+       vstring_free(param_buf); \
+       return (retval); \
+    } while (0)
+
+    if (tlsp_pre_jail_client_done == 0) {
+       if (tlsp_pre_jail_client_param_key == 0
+           || tlsp_pre_jail_client_init_key == 0) {
+           tlsp_pre_jail_client_param_key = mystrdup(param_key);
+           tlsp_pre_jail_client_init_key = mystrdup(init_key);
+       } else if (strcmp(tlsp_pre_jail_client_param_key, param_key) != 0
+                  || strcmp(tlsp_pre_jail_client_init_key, init_key) != 0) {
+           msg_panic("tlsp_client_init: too many pre-jail calls");
+       }
+    }
+
+    /*
+     * Log a warning if a post-jail request uses unexpected TLS_CLIENT_PARAMS
+     * settings. Bug: TLS_CLIENT_PARAMS settings are not used when creating a
+     * TLS_APPL_STATE instance; this makes a mismatch of TLS_CLIENT_PARAMS
+     * settings problematic.
+     */
+    else if (tlsp_pre_jail_client_param_key == 0
+            || tlsp_pre_jail_client_init_key == 0) {
+       msg_warn("TLS client role is disabled by configuration");
+       TLSP_CLIENT_INIT_RETURN(0);
+    } else if (!been_here_fixed(tlsp_client_params_nag_filter, param_key)
+              && strcmp(tlsp_pre_jail_client_param_key, param_key) != 0) {
+       msg_warn("request from tlsproxy client with unexpected settings");
+       tlsp_log_config_diff(tlsp_pre_jail_client_param_key, param_key);
+       log_hints = 1;
+    }
+
+    /*
+     * Look up the cached TLS_APPL_STATE for this tls_client_init request.
+     */
+    if ((appl_state = (TLS_APPL_STATE *)
+        htable_find(tlsp_client_app_cache, init_key)) == 0) {
+
+       /*
+        * Before creating a TLS_APPL_STATE instance, log a warning if a
+        * post-jail request differs from the saved pre-jail request AND the
+        * post-jail request specifies file/directory pathname arguments.
+        * Unexpected requests containing pathnames are problematic after
+        * chroot (pathname resolution) and after dropping privileges (key
+        * files must be root read-only). Unexpected requests are not a
+        * problem as long as they contain no pathnames (for example a
+        * tls_loglevel change).
+        * 
+        * We could eliminate some of this complication by adding code that
+        * opens a cert/key lookup table at pre-jail time, and by reading
+        * cert/key info on-the-fly from that table. But then all requests
+        * would still have to specify the same table.
+        */
+#define NOT_EMPTY(x) ((x) && *(x))
+
+       if (tlsp_pre_jail_client_done
+           && strcmp(tlsp_pre_jail_client_init_key, init_key) != 0
+           && (NOT_EMPTY(init_props->chain_files)
+               || NOT_EMPTY(init_props->cert_file)
+               || NOT_EMPTY(init_props->key_file)
+               || NOT_EMPTY(init_props->dcert_file)
+               || NOT_EMPTY(init_props->dkey_file)
+               || NOT_EMPTY(init_props->eccert_file)
+               || NOT_EMPTY(init_props->eckey_file)
+               || NOT_EMPTY(init_props->CAfile)
+               || NOT_EMPTY(init_props->CApath))) {
+           msg_warn("request from tlsproxy client with unexpected settings");
+           tlsp_log_config_diff(tlsp_pre_jail_client_init_key, init_key);
+           log_hints = 1;
+       }
+    }
+    if (log_hints)
+       msg_warn("to avoid this warning, 1) identify the tlsproxy "
+                "client that is making this request, 2) configure "
+                "a custom tlsproxy service with settings that "
+                "match that tlsproxy client, and 3) configure "
+                "that tlsproxy client with a tlsproxy_service_name "
+                "setting that resolves to that custom tlsproxy "
+                "service");
+
+    /*
+     * TLS_APPL_STATE creation may fail when a post-jail request specifies
+     * unexpected cert/key information, but that is OK because we already
+     * logged a warning with configuration suggestions.
+     */
+    if (appl_state == 0
+       && (appl_state = tls_client_init(init_props)) != 0) {
+       (void) htable_enter(tlsp_client_app_cache, init_key,
+                           (void *) appl_state);
+
+       /*
+        * 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.
+        */
+       SSL_CTX_set_mode(appl_state->ssl_ctx,
+                        SSL_MODE_ENABLE_PARTIAL_WRITE
+                        | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+    }
+    TLSP_CLIENT_INIT_RETURN(appl_state);
+}
+
+/* tlsp_pre_jail_client_init - pre-jail initialization */
+
+void    tlsp_pre_jail_client_init(void)
+{
+    int     clnt_use_tls;
+
+    /*
+     * The cache with TLS_APPL_STATE instances for different TLS_CLIENT_INIT
+     * configurations.
+     */
+    tlsp_client_app_cache = htable_create(10);
+
+    /* Postfix <= 3.10 backwards compatibility. */
+    if (warn_compat_break_tlsp_clnt_level
+       && warn_compat_break_smtp_tls_level)
+       msg_info("using backwards-compatible default setting "
+                VAR_TLSP_CLNT_LEVEL "=(empty)");
+
+    /*
+     * Most sites don't use TLS client certs/keys. In that case, enabling
+     * tlsproxy-based connection caching is trivial.
+     * 
+     * But some sites do use TLS client certs/keys, and that is challenging when
+     * tlsproxy runs in a post-jail environment: chroot breaks pathname
+     * resolution, and an unprivileged process should not be able to open
+     * files with secrets. The workaround: assume that most of those sites
+     * will use a fixed TLS client identity. In that case, tlsproxy can load
+     * the corresponding certs/keys at pre-jail time, so that secrets can
+     * remain read-only for root. As long as the tlsproxy pre-jail TLS client
+     * configuration with cert or key pathnames is the same as the one used
+     * in the Postfix SMTP client, sites can selectively or globally enable
+     * tlsproxy-based connection caching without additional TLS
+     * configuration.
+     * 
+     * Loading one TLS client configuration at pre-jail time is not sufficient
+     * for the minority of sites that want to use TLS connection caching with
+     * multiple TLS client identities. To alert the operator, tlsproxy will
+     * log a warning when a TLS_CLIENT_INIT message specifies a different
+     * configuration than the tlsproxy pre-jail client configuration, and
+     * that different configuration specifies file/directory pathname
+     * arguments. The workaround is to have one tlsproxy process per TLS
+     * client identity.
+     * 
+     * The general solution for single-identity or multi-identity clients is to
+     * stop loading certs and keys from individual files. Instead, have a
+     * cert/key map, indexed by client identity, read-only by root. After
+     * opening the map as root at pre-jail time, tlsproxy can read certs/keys
+     * on-the-fly as an unprivileged process at post-jail time. This is the
+     * approach that was already proposed for server-side SNI support, and it
+     * could be reused here. It would also end the proliferation of RSA
+     * cert/key parameters, DSA cert/key parameters, EC cert/key parameters,
+     * and so on.
+     * 
+     * Horror: In order to create the same pre-jail TLS client context as the
+     * one used in the Postfix SMTP client, we have to duplicate intricate
+     * SMTP client code, including a handful configuration parameters that
+     * tlsproxy does not need. We must duplicate the logic, so that we only
+     * load certs and keys when the SMTP client would load them.
+     */
+    if (*var_tlsp_clnt_level != 0)
+       switch (tls_level_lookup(var_tlsp_clnt_level)) {
+       case TLS_LEV_SECURE:
+       case TLS_LEV_VERIFY:
+       case TLS_LEV_DANE_ONLY:
+       case TLS_LEV_FPRINT:
+       case TLS_LEV_ENCRYPT:
+           var_tlsp_clnt_use_tls = var_tlsp_clnt_enforce_tls = 1;
+           break;
+       case TLS_LEV_DANE:
+       case TLS_LEV_MAY:
+           var_tlsp_clnt_use_tls = 1;
+           var_tlsp_clnt_enforce_tls = 0;
+           break;
+       case TLS_LEV_NONE:
+           var_tlsp_clnt_use_tls = var_tlsp_clnt_enforce_tls = 0;
+           break;
+       default:
+           /* tls_level_lookup() logs no warning. */
+           /* session_tls_init() assumes that var_tlsp_clnt_level is sane. */
+           msg_fatal("Invalid TLS level \"%s\"", var_tlsp_clnt_level);
+       }
+    clnt_use_tls = (var_tlsp_clnt_use_tls || var_tlsp_clnt_enforce_tls);
+
+    /*
+     * Initialize the TLS data before entering the chroot jail.
+     */
+    if (clnt_use_tls || var_tlsp_clnt_per_site[0] || var_tlsp_clnt_policy[0]) {
+       TLS_CLIENT_PARAMS tls_params;
+       TLS_CLIENT_INIT_PROPS init_props;
+
+       tls_pre_jail_init(TLS_ROLE_CLIENT);
+
+       /*
+        * We get stronger type safety and a cleaner interface by combining
+        * the various parameters into a single tls_client_props structure.
+        * 
+        * Large parameter lists are error-prone, so we emulate a language
+        * feature that C does not have natively: named parameter lists.
+        */
+       (void) tls_proxy_client_param_from_config(&tls_params);
+       (void) TLS_CLIENT_INIT_ARGS(&init_props,
+                                   log_param = var_tlsp_clnt_logparam,
+                                   log_level = var_tlsp_clnt_loglevel,
+                                   verifydepth = var_tlsp_clnt_scert_vd,
+                                   cache_type = TLS_MGR_SCACHE_SMTP,
+                                   chain_files = var_tlsp_clnt_chain_files,
+                                   cert_file = var_tlsp_clnt_cert_file,
+                                   key_file = var_tlsp_clnt_key_file,
+                                   dcert_file = var_tlsp_clnt_dcert_file,
+                                   dkey_file = var_tlsp_clnt_dkey_file,
+                                   eccert_file = var_tlsp_clnt_eccert_file,
+                                   eckey_file = var_tlsp_clnt_eckey_file,
+                                   CAfile = var_tlsp_clnt_CAfile,
+                                   CApath = var_tlsp_clnt_CApath,
+                                   mdalg = var_tlsp_clnt_fpt_dgst);
+       if (tlsp_client_init(&tls_params, &init_props) == 0)
+           msg_warn("TLS client initialization failed");
+    }
+
+    /*
+     * Bug: TLS_CLIENT_PARAMS attributes are not used when creating a
+     * TLS_APPL_STATE instance; we can only warn about attribute mismatches.
+     */
+    tlsp_client_params_nag_filter = been_here_init(BH_BOUND_NONE, BH_FLAG_NONE);
+
+    /*
+     * Any of the static global variables would suffice, but this is more
+     * explicit.
+     */
+    tlsp_pre_jail_client_done = 1;
+}
+
+#endif
diff --git a/postfix/src/tlsproxy/tlsproxy_client.h b/postfix/src/tlsproxy/tlsproxy_client.h
new file mode 100644 (file)
index 0000000..ed15197
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _TLSPROXY_CLIENT_H_
+#define _TLSPROXY_CLIENT_H_
+
+/*++
+/* NAME
+/*     tlsproxy_client 3h
+/* SUMMARY
+/*     tlsproxy client role support
+/* SYNOPSIS
+/*     #include <tlsproxy_client.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * TLS library.
+  */
+#include <tls.h>
+#include <tls_proxy.h>
+
+ /*
+  * Internal API.
+  */
+#include <tlsproxy.h>
+
+extern void tlsp_pre_jail_client_init(void);
+extern TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *, TLS_CLIENT_INIT_PROPS *);
+extern int tlsp_client_start_pre_handshake(TLSP_STATE *);
+
+/* 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
diff --git a/postfix/src/tlsproxy/tlsproxy_diff.c b/postfix/src/tlsproxy/tlsproxy_diff.c
new file mode 100644 (file)
index 0000000..a5fe640
--- /dev/null
@@ -0,0 +1,92 @@
+/*++
+/* NAME
+/*     tlsproxy_diff 3
+/* SUMMARY
+/*     Diff TLS proxy client attribute lists
+/* SYNOPSIS
+/*     #include <tlsproxy_diff.h>
+/*
+/*     void     tlsp_log_config_diff(
+/*     const char *server_cfg,
+/*     const char *client_cfg)
+/* DESCRIPTION
+/*     tlsp_log_config_diff() logs the difference between TLS
+/*     configuration attribute lists. The format is zer or more "name
+/*     = value\n". The server_cfg argument specifies attributes from
+/*     the tlsproxy server, and client_cfg lists attributes from a
+/*     tlsproxy client.
+/* 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>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <split_at.h>
+
+ /*
+  * Internal API.
+  */
+#include <tlsproxy.h>
+#include <tlsproxy_diff.h>
+
+/* tlsp_config_diff - report server-client config differences */
+
+void    tlsp_log_config_diff(const char *server_cfg, const char *client_cfg)
+{
+    VSTRING *diff_summary = vstring_alloc(100);
+    char   *saved_server = mystrdup(server_cfg);
+    char   *saved_client = mystrdup(client_cfg);
+    char   *server_field;
+    char   *client_field;
+    char   *server_next;
+    char   *client_next;
+
+    /*
+     * Not using argv_split(), because it would treat multiple consecutive
+     * newline characters as one.
+     */
+    for (server_field = saved_server, client_field = saved_client;
+        server_field && client_field;
+        server_field = server_next, client_field = client_next) {
+       server_next = split_at(server_field, '\n');
+       client_next = split_at(client_field, '\n');
+       if (strcmp(server_field, client_field) != 0) {
+           if (LEN(diff_summary) > 0)
+               vstring_sprintf_append(diff_summary, "; ");
+           vstring_sprintf_append(diff_summary,
+                                  "(server) '%s' != (client) '%s'",
+                                  server_field, client_field);
+       }
+    }
+    msg_warn("%s", STR(diff_summary));
+
+    vstring_free(diff_summary);
+    myfree(saved_client);
+    myfree(saved_server);
+}
diff --git a/postfix/src/tlsproxy/tlsproxy_diff.h b/postfix/src/tlsproxy/tlsproxy_diff.h
new file mode 100644 (file)
index 0000000..bee2112
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _TLSPROXY_DIFF_H_
+#define _TLSPROXY_DIFF_H_
+
+/*++
+/* NAME
+/*     tlsproxy_diff 3h
+/* SUMMARY
+/*     log serialized attribute differences
+/* SYNOPSIS
+/*     #include <tlsproxy_diff.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Internal API.
+  */
+extern void tlsp_log_config_diff(const char *, const char *);
+
+/* 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 a0dc395f3a0caf8452849f77a75c0f05f70a5f1f..56fc4501353a2a2c78a7b76ea2b3c5c268551f3d 100644 (file)
@@ -262,8 +262,8 @@ static void argv_extend(ARGV *argvp)
 {
     ssize_t new_len;
 
-    /* 202604 Claude: avoid small non-negative expression 'new_len + 1'.  */
-    if (argvp->len > SSIZE_MAX / 2)
+    /* 202604 Claude: avoid overflowing (new_len + 1) * sizeof(char *).  */
+    if (argvp->len + 1 > SSIZE_MAX / (2 * sizeof(char *)))
        msg_panic("argv_extend: array length overflow");
     new_len = argvp->len * 2;
     argvp->argv = (char **)
index 8189b5e898f038098362d62e0517ff44a922c11a..afe6594e068499a6b327d007290d5aa9f6a78ec6 100644 (file)
@@ -620,7 +620,8 @@ void    dict_walk(DICT_WALK_ACTION action, void *ptr)
 
     ht_info_list = htable_list(dict_table);
     for (ht = ht_info_list; (h = *ht) != 0; ht++)
-       action(h->key, (DICT *) h->value, ptr);
+       /* 202604 Claude: h->value is (DICT_NODE *) not (DICT *). */
+       action(h->key, ((DICT_NODE *) h->value)->dict, ptr);
     myfree((void *) ht_info_list);
 }
 
index f65f440a65f9a734148b6e4c1cbaecef2a3c14fa..29e4f0ca7cc2bb375efbd1304eb06ea96bd9ba38 100644 (file)
@@ -728,6 +728,9 @@ static int dict_pcre_compile(const char *mapname, int lineno,
     }
     engine->match_data = pcre2_match_data_create_from_pattern(
                                               engine->pattern, (void *) 0);
+    /* 202604 Claude: handle error result. */
+    if (engine->match_data == 0)
+       msg_fatal("out of memory in pcre2_match_data_create_from_pattern()");
 #endif
     return (1);
 }