[Commits] [SCM] claws branch, master, updated. 4.3.1-34-gcda3dae3e

wwp at claws-mail.org wwp at claws-mail.org
Fri Mar 7 13:12:34 UTC 2025


The branch, master has been updated
       via  cda3dae3ec9771b9f9581d14481e5c3cf67110b3 (commit)
      from  e483717e6c13c883c410c6382c98ecd912f68956 (commit)

Summary of changes:
 src/plugins/spamassassin/libspamc.c | 196 +++++++++++++++++++++++++++++++-----
 src/plugins/spamassassin/libspamc.h |  10 ++
 2 files changed, 180 insertions(+), 26 deletions(-)


- Log -----------------------------------------------------------------
commit cda3dae3ec9771b9f9581d14481e5c3cf67110b3
Author: wwp <subscript at free.fr>
Date:   Fri Mar 7 14:12:04 2025 +0100

    Update SpamAssassin (client) third-party code to 4.0.1.

diff --git a/src/plugins/spamassassin/libspamc.c b/src/plugins/spamassassin/libspamc.c
index 47b8c0c2c..8f2cd79fd 100644
--- a/src/plugins/spamassassin/libspamc.c
+++ b/src/plugins/spamassassin/libspamc.c
@@ -39,6 +39,7 @@
 #define sleep Sleep
 #include <io.h>
 #else
+#include <strings.h>
 #include <syslog.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -489,7 +490,6 @@ static int _try_to_connect_tcp(const struct transport *tp, int *sockptr)
 #ifdef SPAMC_HAS_ADDRINFO
         res = tp->hosts[hostix];
         while(res) {
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
             char *family = NULL;
             switch(res->ai_family) {
             case AF_INET:
@@ -502,7 +502,6 @@ static int _try_to_connect_tcp(const struct transport *tp, int *sockptr)
                 family = "Unknown";
                 break;
             }
-#endif
 
             if ((ret = _opensocket(tp->flags, res, &mysock)) != EX_OK) {
                 res = res->ai_next;
@@ -610,6 +609,120 @@ static int _try_to_connect_tcp(const struct transport *tp, int *sockptr)
     return _translate_connect_errno(origerr);
 }
 
+#ifdef SPAMC_SSL
+static char * _ssl_err_as_string (void) {
+    BIO *bio = BIO_new(BIO_s_mem());
+    ERR_print_errors(bio);
+    char *buf = NULL;
+    size_t len = BIO_get_mem_data(bio, &buf);
+    char *ret = (char *)calloc(1, 1 + len);
+    if (!ret) {
+        BIO_free(bio);
+        char *err = "(could not get SSL error)";
+        return err;
+    }
+    memcpy(ret, buf, len);
+    BIO_free(bio);
+    /* Only return up to first newline */
+    char *lf = strchr(ret, '\n');
+    if (lf)
+        *lf = '\0';
+    return ret;
+}
+
+static SSL_CTX * _try_ssl_ctx_init(int flags)
+{
+    const SSL_METHOD *meth;
+    SSL_CTX *ctx;
+
+    SSLeay_add_ssl_algorithms();
+    SSL_load_error_strings();
+    /* this method allows negotiation of version */
+    meth = SSLv23_client_method();
+    ctx = SSL_CTX_new(meth);
+    if (ctx == NULL) {
+        libspamc_log(flags, LOG_ERR, "cannot create SSL CTX context: %s",
+                     _ssl_err_as_string());
+        return NULL;
+    }
+    if (flags & SPAMC_TLSV1) {
+	/* allow TLSv1.0 or better */
+	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
+    } else {
+	/* allow SSLv3 or better */
+	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+    }
+    SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+    return ctx;
+}
+
+static int _try_ssl_connect(SSL_CTX *ctx, struct transport *tp,
+			    SSL **pssl, int flags, int sock)
+{
+    SSL *ssl;
+    int ssl_rtn;
+    if (tp->ssl_ca_file || tp->ssl_ca_path) {
+	if (!SSL_CTX_load_verify_locations(ctx, tp->ssl_ca_file,
+					   tp->ssl_ca_path)) {
+	    libspamc_log(flags, LOG_ERR,
+			 "error loading CA file %s or path %s: %s",
+			 tp->ssl_ca_file ? tp->ssl_ca_file : "(void)",
+			 tp->ssl_ca_path ? tp->ssl_ca_path : "(void)",
+			 _ssl_err_as_string());
+	    return EX_OSERR;
+	}
+	SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+    } else {
+        SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+    }
+    if (flags & SPAMC_CLIENT_SSL_CERT) {
+	/* libspamc_log(flags, LOG_ERR, "loading client cert %s key %s",
+		     tp->ssl_cert_file, tp->ssl_key_file); */
+	if (!SSL_CTX_use_certificate_file(ctx, tp->ssl_cert_file,
+					  SSL_FILETYPE_PEM)) {
+	    libspamc_log(flags, LOG_ERR,
+			 "unable to load certificate file %s: %s",
+			 tp->ssl_cert_file, _ssl_err_as_string());
+	    return EX_OSERR;
+	}
+	if (!SSL_CTX_use_PrivateKey_file(ctx, tp->ssl_key_file,
+					 SSL_FILETYPE_PEM)) {
+	    libspamc_log(flags, LOG_ERR,
+			 "unable to load key file %s: %s",
+			 tp->ssl_key_file, _ssl_err_as_string());
+	    return EX_OSERR;
+	}
+	if (!SSL_CTX_check_private_key(ctx)) {
+	    libspamc_log(flags, LOG_ERR,
+			 "key file %s and cert file %s do not match: %s",
+			 tp->ssl_key_file, tp->ssl_cert_file,
+			 _ssl_err_as_string());
+	    return EX_OSERR;
+	}
+    }
+    ssl = SSL_new(ctx);
+    if (ssl == NULL) {
+        libspamc_log(flags, LOG_ERR,
+	             "SSL_new failed: %s", _ssl_err_as_string());
+        return EX_OSERR;
+    }
+    *pssl = ssl;
+    if (!SSL_set_fd(ssl, sock)) {
+	libspamc_log(flags, LOG_ERR,
+		     "SSL_set_fd failed: %s", _ssl_err_as_string());
+	return EX_OSERR;
+    }
+    ssl_rtn = SSL_connect(ssl);
+    if (ssl_rtn != 1) {
+	int ssl_err = SSL_get_error(ssl, ssl_rtn);
+	libspamc_log(flags, LOG_ERR,
+		     "SSL_connect error: %s", _ssl_err_as_string());
+	return EX_UNAVAILABLE;
+    }
+    return EX_OK;
+}
+#endif
+
 /* Aug 14, 2002 bj: Reworked things. Now we have message_read, message_write,
  * message_dump, lookup_host, message_filter, and message_process, and a bunch
  * of helper functions.
@@ -919,7 +1032,7 @@ _spamc_read_full_line(struct message *m, int flags, SSL * ssl, int sock,
 	}
     }
 
-    libspamc_log(flags, LOG_ERR, "spamd responded with line of %lu bytes, dying", len);
+    libspamc_log(flags, LOG_ERR, "spamd responded with line of %d bytes, dying", len);
     failureval = EX_TOOBIG;
 
   failure:
@@ -1216,13 +1329,13 @@ int message_filter(struct transport *tp, const char *username,
 
     if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-	SSLeay_add_ssl_algorithms();
-	meth = SSLv23_client_method();
-	SSL_load_error_strings();
-	ctx = SSL_CTX_new(meth);
+        ctx = _try_ssl_ctx_init(flags);
+        if (ctx == NULL) {
+	    failureval = EX_OSERR;
+	    goto failure;
+        }
 #else
 	UNUSED_VARIABLE(ssl);
-	UNUSED_VARIABLE(meth);
 	UNUSED_VARIABLE(ctx);
 	libspamc_log(flags, LOG_ERR, "spamc not built with SSL support");
 	return EX_SOFTWARE;
@@ -1375,17 +1488,33 @@ int message_filter(struct transport *tp, const char *username,
     
         if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-            ssl = SSL_new(ctx);
-            SSL_set_fd(ssl, sock);
-            SSL_connect(ssl);
+            rc = _try_ssl_connect(ctx, tp, &ssl, flags, sock);
+            if (rc != EX_OK) {
+                failureval = rc;
+                goto failure;
+            }
 #endif
         }
     
         /* Send to spamd */
         if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-            SSL_write(ssl, buf, len);
-            SSL_write(ssl, towrite_buf, towrite_len);
+            rc = SSL_write(ssl, buf, len);
+            if (rc <= 0) {
+                libspamc_log(flags, LOG_ERR, "SSL write failed (%d)",
+                             SSL_get_error(ssl, rc));
+                failureval = EX_IOERR;
+                goto failure;
+            }
+            rc = SSL_write(ssl, towrite_buf, towrite_len);
+            if (rc <= 0) {
+                libspamc_log(flags, LOG_ERR, "SSL write failed (%d)",
+                             SSL_get_error(ssl, rc));
+                failureval = EX_IOERR;
+                goto failure;
+            }
+            SSL_shutdown(ssl);
+            shutdown(sock, SHUT_WR);
 #endif
         }
         else {
@@ -1596,20 +1725,19 @@ int message_tell(struct transport *tp, const char *username, int flags,
     int failureval;
     SSL_CTX *ctx = NULL;
     SSL *ssl = NULL;
-    const SSL_METHOD *meth;
 
     assert(tp != NULL);
     assert(m != NULL);
 
     if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-	SSLeay_add_ssl_algorithms();
-	meth = SSLv23_client_method();
-	SSL_load_error_strings();
-	ctx = SSL_CTX_new(meth);
+        ctx = _try_ssl_ctx_init(flags);
+        if (ctx == NULL) {
+            failureval = EX_OSERR;
+            goto failure;
+        }
 #else
 	UNUSED_VARIABLE(ssl);
-	UNUSED_VARIABLE(meth);
 	UNUSED_VARIABLE(ctx);
 	libspamc_log(flags, LOG_ERR, "spamc not built with SSL support");
 	return EX_SOFTWARE;
@@ -1723,17 +1851,33 @@ int message_tell(struct transport *tp, const char *username, int flags,
 
     if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-	ssl = SSL_new(ctx);
-	SSL_set_fd(ssl, sock);
-	SSL_connect(ssl);
+        rc = _try_ssl_connect(ctx, tp, &ssl, flags, sock);
+        if (rc != EX_OK) {
+            failureval = rc;
+            goto failure;
+        }
 #endif
     }
 
     /* Send to spamd */
     if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-	SSL_write(ssl, buf, len);
-	SSL_write(ssl, m->msg, m->msg_len);
+	rc = SSL_write(ssl, buf, len);
+        if (rc <= 0) {
+            libspamc_log(flags, LOG_ERR, "SSL write failed (%d)",
+                         SSL_get_error(ssl, rc));
+            failureval = EX_IOERR;
+            goto failure;
+        }
+	rc = SSL_write(ssl, m->msg, m->msg_len);
+        if (rc <= 0) {
+            libspamc_log(flags, LOG_ERR, "SSL write failed (%d)",
+                         SSL_get_error(ssl, rc));
+            failureval = EX_IOERR;
+            goto failure;
+        }
+	SSL_shutdown(ssl);
+	shutdown(sock, SHUT_WR);
 #endif
     }
     else {
@@ -1911,7 +2055,7 @@ static void _randomize_hosts(struct transport *tp)
 int transport_setup(struct transport *tp, int flags)
 {
 #ifdef SPAMC_HAS_ADDRINFO
-    struct addrinfo hints, *res; /* , *addrp; */
+    struct addrinfo hints, *res, *addrp;
     char port[6];
     int origerr;
 #else
@@ -2248,7 +2392,7 @@ libspamc_log (int flags, int level, char *msg, ...)
         syslog (level, "%s", buf);
 #else
         (void) level;  /* not used. suppress compiler warning */
-        f_printerr ("%s\n", buf);
+        fprintf (stderr, "%s\n", buf);
 #endif
     }
 
diff --git a/src/plugins/spamassassin/libspamc.h b/src/plugins/spamassassin/libspamc.h
index 7a6fc1209..269e57464 100644
--- a/src/plugins/spamassassin/libspamc.h
+++ b/src/plugins/spamassassin/libspamc.h
@@ -139,6 +139,9 @@
  * */
 #define SPAMC_UNAVAIL_TEMPFAIL (1<<13)
 
+/* April 2022, add SSL client certificate support, bug 7267 */
+#define SPAMC_CLIENT_SSL_CERT (1<<12)
+
 #define SPAMC_MESSAGE_CLASS_SPAM 1
 #define SPAMC_MESSAGE_CLASS_HAM  2
 
@@ -249,6 +252,13 @@ struct transport
     /* Added for filterloop */
     int filter_retries;
     int filter_retry_sleep;
+
+#ifdef SPAMC_SSL
+    const char *ssl_cert_file;
+    const char *ssl_key_file;
+    const char *ssl_ca_file;
+    const char *ssl_ca_path;
+#endif
 };
 
 /* Initialise and setup transport-specific context for the connection

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list