[exim-dev] patch for review: TLS logging

Top Page
Delete this message
Reply to this message
Author: Tony Finch
Date:  
To: exim-dev
Subject: [exim-dev] patch for review: TLS logging
I've been putting together a patch that fixes the TLS error reporting so
that it respects the incoming_interface log selector. This is so that the
postmaster can find out if a client is connecting to port 25 or 465 or
587, which is useful for M$ MUAs that have stupid TLS implementations.

I think the OpenSSL version works OK. I'd be grateful if someone can check
out the GnuTLS version.

Tony.
--
<fanf@???> <dot@???> http://dotat.at/ ${sg{\N${sg{\
N\}{([^N]*)(.)(.)(.*)}{\$1\$3\$2\$1\$3\n\$2\$3\$4\$3\n\$3\$2\$4}}\
\N}{([^N]*)(.)(.)(.*)}{\$1\$3\$2\$1\$3\n\$2\$3\$4\$3\n\$3\$2\$4}}Index: tls-openssl.c
===================================================================
RCS file: /home/cvs/exim/exim-src/src/tls-openssl.c,v
retrieving revision 1.12
diff -u -r1.12 tls-openssl.c
--- tls-openssl.c    13 Apr 2007 15:13:47 -0000    1.12
+++ tls-openssl.c    24 Jan 2008 17:55:47 -0000
@@ -62,25 +62,33 @@
   prefix    text to include in the logged error
   host      NULL if setting up a server;
             the connected host if setting up a client
+  msg       error message or NULL if we should ask OpenSSL
 
 Returns:    OK/DEFER/FAIL
 */
 
 static int
-tls_error(uschar *prefix, host_item *host)
+tls_error(uschar *prefix, host_item *host, uschar *msg)
 {
-ERR_error_string(ERR_get_error(), ssl_errstring);
+if (msg == NULL)
+  {
+  ERR_error_string(ERR_get_error(), ssl_errstring);
+  msg = ssl_errstring;
+  }
+
 if (host == NULL)
   {
-  log_write(0, LOG_MAIN, "TLS error on connection from %s (%s): %s",
-    (sender_fullhost != NULL)? sender_fullhost : US"local process",
-    prefix, ssl_errstring);
+  uschar *conn_info = smtp_get_connection_info();
+  if (strncmp(conn_info, "SMTP ", 5) == 0)
+    conn_info += 5;
+  log_write(0, LOG_MAIN, "TLS error on %s (%s): %s",
+    conn_info, prefix, msg);
   return DEFER;
   }
 else
   {
   log_write(0, LOG_MAIN, "TLS error on connection to %s [%s] (%s): %s",
-    host->name, host->address, prefix, ssl_errstring);
+    host->name, host->address, prefix, msg);
   return FAIL;
   }
 }
@@ -224,12 +232,13 @@
 
 Arguments:
   dhparam   DH parameter file
+  host      connected host, if client; NULL if server
 
 Returns:    TRUE if OK (nothing to set up, or setup worked)
 */
 
 static BOOL
-init_dh(uschar *dhparam)
+init_dh(uschar *dhparam, host_item *host)
 {
 BOOL yield = TRUE;
 BIO *bio;
@@ -243,16 +252,16 @@
 
 if ((bio = BIO_new_file(CS dhexpanded, "r")) == NULL)
   {
-  log_write(0, LOG_MAIN, "DH: could not read %s: %s", dhexpanded,
-    strerror(errno));
+  tls_error(string_sprintf("could not read dhparams file %s", dhexpanded),
+    host, strerror(errno));
   yield = FALSE;
   }
 else
   {
   if ((dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)) == NULL)
     {
-    log_write(0, LOG_MAIN, "DH: could not load params from %s",
-      dhexpanded);
+    tls_error(string_sprintf("could not read dhparams file %s", dhexpanded),
+      host, NULL);
     yield = FALSE;
     }
   else
@@ -301,7 +310,7 @@
 ctx = SSL_CTX_new((host == NULL)?
   SSLv23_server_method() : SSLv23_client_method());
 
-if (ctx == NULL) return tls_error(US"SSL_CTX_new", host);
+if (ctx == NULL) return tls_error(US"SSL_CTX_new", host, NULL);
 
 /* It turns out that we need to seed the random number generator this early in
 order to get the full complement of ciphers to work. It took me roughly a day
@@ -322,22 +331,8 @@
   if (addr != NULL) RAND_seed((uschar *)addr, sizeof(addr));
 
   if (!RAND_status())
-    {
-    if (host == NULL)
-      {
-      log_write(0, LOG_MAIN, "TLS error on connection from %s: "
-        "unable to seed random number generator",
-        (sender_fullhost != NULL)? sender_fullhost : US"local process");
-      return DEFER;
-      }
-    else
-      {
-      log_write(0, LOG_MAIN, "TLS error on connection to %s [%s]: "
-        "unable to seed random number generator",
-        host->name, host->address);
-      return FAIL;
-      }
-    }
+    return tls_error(US"RAND_status", host,
+      "unable to seed random number generator");
   }
 
 /* Set up the information callback, which outputs if debugging is at a suitable
@@ -358,12 +353,12 @@
 /* XXX (Silently?) ignore failure here? XXX*/
 
 if (!(SSL_CTX_set_options(ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)))
-  return tls_error(US"SSL_CTX_set_option", host);
+  return tls_error(US"SSL_CTX_set_option", host, NULL);
 #endif
 
 /* Initialize with DH parameters if supplied */
 
-if (!init_dh(dhparam)) return DEFER;
+if (!init_dh(dhparam, host)) return DEFER;
 
 /* Set up certificate and key */
 
@@ -378,7 +373,7 @@
     DEBUG(D_tls) debug_printf("tls_certificate file %s\n", expanded);
     if (!SSL_CTX_use_certificate_chain_file(ctx, CS expanded))
       return tls_error(string_sprintf(
-        "SSL_CTX_use_certificate_chain_file file=%s", expanded), host);
+        "SSL_CTX_use_certificate_chain_file file=%s", expanded), host, NULL);
     }
 
   if (privatekey != NULL &&
@@ -394,7 +389,7 @@
     DEBUG(D_tls) debug_printf("tls_privatekey file %s\n", expanded);
     if (!SSL_CTX_use_PrivateKey_file(ctx, CS expanded, SSL_FILETYPE_PEM))
       return tls_error(string_sprintf(
-        "SSL_CTX_use_PrivateKey_file file=%s", expanded), host);
+        "SSL_CTX_use_PrivateKey_file file=%s", expanded), host, NULL);
     }
   }
 
@@ -491,7 +486,7 @@
   {
   struct stat statbuf;
   if (!SSL_CTX_set_default_verify_paths(ctx))
-    return tls_error(US"SSL_CTX_set_default_verify_paths", host);
+    return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL);
 
   if (Ustat(expcerts, &statbuf) < 0)
     {
@@ -514,7 +509,7 @@
 
     if ((file == NULL || statbuf.st_size > 0) &&
           !SSL_CTX_load_verify_locations(ctx, CS file, CS dir))
-      return tls_error(US"SSL_CTX_load_verify_locations", host);
+      return tls_error(US"SSL_CTX_load_verify_locations", host, NULL);
 
     if (file != NULL)
       {
@@ -564,7 +559,7 @@
         DEBUG(D_tls) debug_printf("SSL CRL value is a file %s\n", file);
         }
       if (X509_STORE_load_locations(cvstore, CS file, CS dir) == 0)
-        return tls_error(US"X509_STORE_load_locations", host);
+        return tls_error(US"X509_STORE_load_locations", host, NULL);
 
       /* setting the flags to check against the complete crl chain */
 
@@ -620,9 +615,7 @@
 
 if (tls_active >= 0)
   {
-  log_write(0, LOG_MAIN, "STARTTLS received in already encrypted "
-    "connection from %s",
-    (sender_fullhost != NULL)? sender_fullhost : US"local process");
+  tls_error("STARTTLS received after TLS started", NULL, "");
   smtp_printf("554 Already in TLS\r\n");
   return FAIL;
   }
@@ -646,7 +639,7 @@
   while (*s != 0) { if (*s == '_') *s = '-'; s++; }
   DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
   if (!SSL_CTX_set_cipher_list(ctx, CS expciphers))
-    return tls_error(US"SSL_CTX_set_cipher_list", NULL);
+    return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL);
   }
 
 /* If this is a host for which certificate verification is mandatory or
@@ -670,7 +663,7 @@
 
 /* Prepare for new connection */
 
-if ((ssl = SSL_new(ctx)) == NULL) return tls_error(US"SSL_new", NULL);
+if ((ssl = SSL_new(ctx)) == NULL) return tls_error(US"SSL_new", NULL, NULL);
 SSL_clear(ssl);
 
 /* Set context and tell client to go ahead, except in the case of TLS startup
@@ -702,11 +695,7 @@
 
 if (rc <= 0)
   {
-  if (sigalrm_seen) Ustrcpy(ssl_errstring, "timed out");
-    else ERR_error_string(ERR_get_error(), ssl_errstring);
-  log_write(0, LOG_MAIN, "TLS error on connection from %s (SSL_accept): %s",
-    (sender_fullhost != NULL)? sender_fullhost : US"local process",
-    ssl_errstring);
+  tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL);
   return FAIL;
   }
 
@@ -801,13 +790,13 @@
   while (*s != 0) { if (*s == '_') *s = '-'; s++; }
   DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
   if (!SSL_CTX_set_cipher_list(ctx, CS expciphers))
-    return tls_error(US"SSL_CTX_set_cipher_list", host);
+    return tls_error(US"SSL_CTX_set_cipher_list", host, NULL);
   }
 
 rc = setup_certs(verify_certs, crl, host, FALSE);
 if (rc != OK) return rc;
 
-if ((ssl = SSL_new(ctx)) == NULL) return tls_error(US"SSL_new", host);
+if ((ssl = SSL_new(ctx)) == NULL) return tls_error(US"SSL_new", host, NULL);
 SSL_set_session_id_context(ssl, sid_ctx, Ustrlen(sid_ctx));
 SSL_set_fd(ssl, fd);
 SSL_set_connect_state(ssl);
@@ -821,15 +810,7 @@
 alarm(0);
 
 if (rc <= 0)
-  {
-  if (sigalrm_seen)
-    {
-    log_write(0, LOG_MAIN, "TLS error on connection to %s [%s]: "
-      "SSL_connect timed out", host->name, host->address);
-    return FAIL;
-    }
-  else return tls_error(US"SSL_connect", host);
-  }
+  return tls_error(US"SSL_connect", host, sigalrm_seen ? US"timed out" : NULL);
 
 DEBUG(D_tls) debug_printf("SSL_connect succeeded\n");
 
Index: tls-gnu.c
===================================================================
RCS file: /home/cvs/exim/exim-src/src/tls-gnu.c,v
retrieving revision 1.19
diff -u -r1.19 tls-gnu.c
--- tls-gnu.c    13 Apr 2007 15:13:47 -0000    1.19
+++ tls-gnu.c    24 Jan 2008 17:55:47 -0000
@@ -26,14 +26,12 @@
 #define PARAM_SIZE 2*1024
 
 
-/* Values for verify_requirment and initialized */
+/* Values for verify_requirment */
 
 enum { VERIFY_NONE, VERIFY_OPTIONAL, VERIFY_REQUIRED };
-enum { INITIALIZED_NOT, INITIALIZED_SERVER, INITIALIZED_CLIENT };
 
 /* Local static variables for GNUTLS */
 
-static BOOL initialized = INITIALIZED_NOT;
 static host_item *client_host;
 
 static gnutls_dh_params dh_params = NULL;
@@ -164,27 +162,28 @@
   prefix    text to include in the logged error
   host      NULL if setting up a server;
             the connected host if setting up a client
-  err       a GnuTLS error number, or 0 if local error
+  msg       additional error string (may be NULL)
+            usually obtained from gnutls_strerror()
 
 Returns:    OK/DEFER/FAIL
 */
 
 static int
-tls_error(uschar *prefix, host_item *host, int err)
+tls_error(uschar *prefix, host_item *host, uschar *msg)
 {
-uschar *errtext = US"";
-if (err != 0) errtext = string_sprintf(": %s", gnutls_strerror(err));
 if (host == NULL)
   {
-  log_write(0, LOG_MAIN, "TLS error on connection from %s (%s)%s",
-    (sender_fullhost != NULL)? sender_fullhost : US "local process",
-    prefix, errtext);
+  uschar *conn_info = smtp_get_connection_info();
+  if (strncmp(conn_info, "SMTP ", 5) == 0)
+    conn_info += 5;
+  log_write(0, LOG_MAIN, "TLS error on %s (%s)%s%s",
+    conn_info, prefix, msg ? ": " : "", msg ? msg : "");
   return DEFER;
   }
 else
   {
-  log_write(0, LOG_MAIN, "TLS error on connection to %s [%s] (%s)%s",
-    host->name, host->address, prefix, errtext);
+  log_write(0, LOG_MAIN, "TLS error on connection to %s [%s] (%s)%s%s",
+    host->name, host->address, prefix, msg ? ": " : "", msg ? msg : "");
   return FAIL;
   }
 }
@@ -306,13 +305,13 @@
 /* Initialize the data structures for holding the parameters */
 
 ret = gnutls_dh_params_init(&dh_params);
-if (ret < 0) return tls_error(US"init dh_params", host, ret);
+if (ret < 0) return tls_error(US"init dh_params", host, gnutls_strerror(ret));
 
 /* Set up the name of the cache file */
 
 if (!string_format(filename, sizeof(filename), "%s/gnutls-params",
       spool_directory))
-  return tls_error(US"overlong filename", host, 0);
+  return tls_error(US"overlong filename", host, NULL);
 
 /* Open the cache file for reading and if successful, read it and set up the
 parameters. */
@@ -324,19 +323,21 @@
   if (fstat(fd, &statbuf) < 0)
     {
     (void)close(fd);
-    return tls_error(US"TLS cache stat failed", host, 0);
+    return tls_error(US"TLS cache stat failed", host, strerror(errno));
     }
 
   m.size = statbuf.st_size;
   m.data = malloc(m.size);
   if (m.data == NULL)
-    return tls_error(US"memory allocation failed", host, 0);
+    return tls_error(US"memory allocation failed", host, strerror(errno));
+  errno = 0;
   if (read(fd, m.data, m.size) != m.size)
-    return tls_error(US"TLS cache read failed", host, 0);
+    return tls_error(US"TLS cache read failed", host, strerror(errno));
   (void)close(fd);
 
   ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
-  if (ret < 0) return tls_error(US"DH params import", host, ret);
+  if (ret < 0)
+    return tls_error(US"DH params import", host, gnutls_strerror(ret));
   DEBUG(D_tls) debug_printf("read D-H parameters from file\n");
 
   free(m.data);
@@ -353,7 +354,7 @@
   }
 else
   return tls_error(string_open_failed(errno, "%s for reading", filename),
-    host, 0);
+    host, NULL);
 
 /* If ret < 0, either the cache file does not exist, or the data it contains
 is not useful. One particular case of this is when upgrading from an older
@@ -368,7 +369,7 @@
   DEBUG(D_tls) debug_printf("generating %d bit Diffie-Hellman key...\n",
     DH_BITS);
   ret = gnutls_dh_params_generate2(dh_params, DH_BITS);
-  if (ret < 0) return tls_error(US"D-H key generation", host, ret);
+  if (ret < 0) return tls_error(US"D-H key generation", host, gnutls_strerror(ret));
 
   /* Write the parameters to a file in the spool directory so that we
   can use them from other Exim processes. */
@@ -377,7 +378,7 @@
   fd = Uopen(tempfilename, O_WRONLY|O_CREAT, 0400);
   if (fd < 0)
     return tls_error(string_open_failed(errno, "%s for writing", filename),
-      host, 0);
+      host, NULL);
   (void)fchown(fd, exim_uid, exim_gid);   /* Probably not necessary */
 
   /* export the parameters in a format that can be generated using GNUTLS'
@@ -390,23 +391,25 @@
   m.size = PARAM_SIZE;
   m.data = malloc(m.size);
   if (m.data == NULL)
-    return tls_error(US"memory allocation failed", host, 0);
+    return tls_error(US"memory allocation failed", host, strerror(errno));
 
   m.size = PARAM_SIZE;
   ret = gnutls_dh_params_export_pkcs3(dh_params, GNUTLS_X509_FMT_PEM, m.data,
     &m.size);
-  if (ret < 0) return tls_error(US"DH params export", host, ret);
+  if (ret < 0)
+    return tls_error(US"DH params export", host, gnutls_strerror(ret));
 
   m.size = Ustrlen(m.data);
+  errno = 0;
   if (write(fd, m.data, m.size) != m.size || write(fd, "\n", 1) != 1)
-    return tls_error(US"TLS cache write failed", host, 0);
+    return tls_error(US"TLS cache write failed", host, strerror(errno));
 
   free(m.data);
   (void)close(fd);
 
   if (rename(CS tempfilename, CS filename) < 0)
-    return tls_error(string_sprintf("failed to rename %s as %s: %s",
-      tempfilename, filename, strerror(errno)), host, 0);
+    return tls_error(string_sprintf("failed to rename %s as %s",
+      tempfilename, filename), host, strerror(errno));
 
   DEBUG(D_tls) debug_printf("wrote D-H parameters to file %s\n", filename);
   }
@@ -442,10 +445,10 @@
 int rc;
 uschar *cert_expanded, *key_expanded, *cas_expanded, *crl_expanded;
 
-initialized = (host == NULL)? INITIALIZED_SERVER : INITIALIZED_CLIENT;
+client_host = host;
 
 rc = gnutls_global_init();
-if (rc < 0) return tls_error(US"tls-init", host, rc);
+if (rc < 0) return tls_error(US"tls-init", host, gnutls_strerror(rc));
 
 /* Create D-H parameters, or read them from the cache file. This function does
 its own SMTP error messaging. */
@@ -456,7 +459,9 @@
 /* Create the credentials structure */
 
 rc = gnutls_certificate_allocate_credentials(&x509_cred);
-if (rc < 0) return tls_error(US"certificate_allocate_credentials", host, rc);
+if (rc < 0)
+  return tls_error(US"certificate_allocate_credentials",
+    host, gnutls_strerror(rc));
 
 /* This stuff must be done for each session, because different certificates
 may be required for different sessions. */
@@ -490,7 +495,7 @@
     {
     uschar *msg = string_sprintf("cert/key setup: cert=%s key=%s",
       cert_expanded, key_expanded);
-    return tls_error(msg, host, rc);
+    return tls_error(msg, host, gnutls_strerror(rc));
     }
   }
 
@@ -499,7 +504,7 @@
 else
   {
   if (host == NULL)
-    return tls_error(US"no TLS server certificate is specified", host, 0);
+    return tls_error(US"no TLS server certificate is specified", NULL, NULL);
   DEBUG(D_tls) debug_printf("no TLS client certificate is specified\n");
   }
 
@@ -532,7 +537,7 @@
     {
     rc = gnutls_certificate_set_x509_trust_file(x509_cred, CS cas_expanded,
       GNUTLS_X509_FMT_PEM);
-    if (rc < 0) return tls_error(US"setup_certs", host, rc);
+    if (rc < 0) return tls_error(US"setup_certs", host, gnutls_strerror(rc));
 
     if (crl != NULL && *crl != 0)
       {
@@ -541,7 +546,7 @@
       DEBUG(D_tls) debug_printf("loading CRL file = %s\n", crl_expanded);
       rc = gnutls_certificate_set_x509_crl_file(x509_cred, CS crl_expanded,
         GNUTLS_X509_FMT_PEM);
-      if (rc < 0) return tls_error(US"CRL setup", host, rc);
+      if (rc < 0) return tls_error(US"CRL setup", host, gnutls_strerror(rc));
       }
     }
   }
@@ -865,9 +870,7 @@
 
 if (tls_active >= 0)
   {
-  log_write(0, LOG_MAIN, "STARTTLS received in already encrypted "
-    "connection from %s",
-    (sender_fullhost != NULL)? sender_fullhost : US"local process");
+  tls_error("STARTTLS received after TLS started", NULL, "");
   smtp_printf("554 Already in TLS\r\n");
   return FAIL;
   }
@@ -903,7 +906,8 @@
 tls_session = tls_session_init(GNUTLS_SERVER, expciphers, expmac, expkx,
   expproto);
 if (tls_session == NULL)
-  return tls_error(US"tls_session_init", NULL, GNUTLS_E_MEMORY_ERROR);
+  return tls_error(US"tls_session_init", NULL,
+    gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
 
 /* Set context and tell client to go ahead, except in the case of TLS startup
 on connection, where outputting anything now upsets the clients and tends to
@@ -930,14 +934,8 @@
 
 if (rc < 0)
   {
-  if (sigalrm_seen)
-    Ustrcpy(ssl_errstring, "timed out");
-  else
-    Ustrcpy(ssl_errstring, gnutls_strerror(rc));
-  log_write(0, LOG_MAIN,
-    "TLS error on connection from %s (gnutls_handshake): %s",
-    (sender_fullhost != NULL)? sender_fullhost : US"local process",
-    ssl_errstring);
+  tls_error(US"gnutls_handshake", NULL,
+    sigalrm_seen ? "timed out" : gnutls_strerror(rc));
 
   /* It seems that, except in the case of a timeout, we have to close the
   connection right here; otherwise if the other end is running OpenSSL it hangs
@@ -957,9 +955,7 @@
 if (verify_requirement != VERIFY_NONE &&
      !verify_certificate(tls_session, &error))
   {
-  log_write(0, LOG_MAIN,
-    "TLS error on connection from %s: certificate verification failed (%s)",
-    (sender_fullhost != NULL)? sender_fullhost : US"local process", error);
+  tls_error(US"certificate verification failed", NULL, error);
   return FAIL;
   }
 
@@ -1028,7 +1024,6 @@
 
 DEBUG(D_tls) debug_printf("initializing GnuTLS as a client\n");
 
-client_host = host;
 verify_requirement = (verify_certs == NULL)? VERIFY_NONE : VERIFY_REQUIRED;
 rc = tls_init(host, certificate, privatekey, verify_certs, verify_crl);
 if (rc != OK) return rc;
@@ -1043,7 +1038,8 @@
   expproto);
 
 if (tls_session == NULL)
-  return tls_error(US "tls_session_init", host, GNUTLS_E_MEMORY_ERROR);
+  return tls_error(US "tls_session_init", host,
+    gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
 
 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)fd);
 
@@ -1055,15 +1051,8 @@
 alarm(0);
 
 if (rc < 0)
-  {
-  if (sigalrm_seen)
-    {
-    log_write(0, LOG_MAIN, "TLS error on connection to %s [%s]: "
-      "gnutls_handshake timed out", host->name, host->address);
-    return FAIL;
-    }
-  else return tls_error(US "gnutls_handshake", host, rc);
-  }
+  return tls_error(US "gnutls_handshake", host,
+    sigalrm_seen ? "timed out" : gnutls_strerror(rc));
 
 server_certs = gnutls_certificate_get_peers(tls_session, &server_certs_size);
 
@@ -1087,12 +1076,7 @@
 
 if (verify_requirement != VERIFY_NONE &&
       !verify_certificate(tls_session, &error))
-  {
-  log_write(0, LOG_MAIN,
-    "TLS error on connection to %s [%s]: certificate verification failed (%s)",
-    host->name, host->address, error);
-  return FAIL;
-  }
+  return tls_error(US"certificate verification failed", host, error);
 
 construct_cipher_name(tls_session);    /* Sets tls_cipher */
 tls_active = fd;
@@ -1118,21 +1102,15 @@
 static void
 record_io_error(int ec, uschar *when, uschar *text)
 {
-uschar *additional = US"";
+uschar *msg;
 
 if (ec == GNUTLS_E_FATAL_ALERT_RECEIVED)
-  additional = string_sprintf(": %s",
+  msg = string_sprintf("%s: %s", gnutls_strerror(ec),
     gnutls_alert_get_name(gnutls_alert_get(tls_session)));
-
-if (initialized == INITIALIZED_SERVER)
-  log_write(0, LOG_MAIN, "TLS %s error on connection from %s: %s%s", when,
-    (sender_fullhost != NULL)? sender_fullhost : US "local process",
-    (ec == 0)? text : US gnutls_strerror(ec), additional);
-
 else
-  log_write(0, LOG_MAIN, "TLS %s error on connection to %s [%s]: %s%s", when,
-    client_host->name, client_host->address,
-    (ec == 0)? text : US gnutls_strerror(ec), additional);
+  msg = gnutls_strerror(ec);
+
+tls_error(when, client_host, msg);
 }