Add event for inbound cert visibility
[exim.git] / src / src / tls-gnu.c
index 3043e3abc925ff07f2ee9b6ed8a069d118c853a9..1966c557dc0f440cc1b3d9c93caebd0344aed628 100644 (file)
@@ -47,9 +47,14 @@ require current GnuTLS, then we'll drop support for the ancient libraries).
 # warning "GnuTLS library version too old; define DISABLE_OCSP in Makefile"
 # define DISABLE_OCSP
 #endif
-#if GNUTLS_VERSION_NUMBER < 0x020a00 && defined(EXPERIMENTAL_TPDA)
-# warning "GnuTLS library version too old; TPDA tls:cert event unsupported"
-# undef EXPERIMENTAL_TPDA
+#if GNUTLS_VERSION_NUMBER < 0x020a00 && defined(EXPERIMENTAL_EVENT)
+# warning "GnuTLS library version too old; tls:cert event unsupported"
+# undef EXPERIMENTAL_EVENT
+#endif
+#if GNUTLS_VERSION_NUMBER >= 0x030306
+# define SUPPORT_CA_DIR
+#else
+# undef  SUPPORT_CA_DIR
 #endif
 
 #ifndef DISABLE_OCSP
@@ -119,7 +124,7 @@ typedef struct exim_gnutls_state {
 #ifdef EXPERIMENTAL_CERTNAMES
   uschar *exp_tls_verify_cert_hostnames;
 #endif
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
   uschar *event_action;
 #endif
 
@@ -140,7 +145,7 @@ static const exim_gnutls_state_st exim_gnutls_state_init = {
 #ifdef EXPERIMENTAL_CERTNAMES
                                             NULL,
 #endif
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
                                             NULL,
 #endif
   NULL,
@@ -268,7 +273,7 @@ tls_error(const uschar *prefix, const char *msg, const host_item *host)
 {
 if (host)
   {
-  log_write(0, LOG_MAIN, "TLS error on connection to %s [%s] (%s)%s%s",
+  log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection (%s)%s%s",
       host->name, host->address, prefix, msg ? ": " : "", msg ? msg : "");
   return FAIL;
   }
@@ -277,6 +282,7 @@ else
   uschar *conn_info = smtp_get_connection_info();
   if (Ustrncmp(conn_info, US"SMTP ", 5) == 0)
     conn_info += 5;
+  /* I'd like to get separated H= here, but too hard for now */
   log_write(0, LOG_MAIN, "TLS error on %s (%s)%s%s",
       conn_info, prefix, msg ? ": " : "", msg ? msg : "");
   return DEFER;
@@ -884,6 +890,7 @@ if (Ustat(state->exp_tls_verify_certificates, &statbuf) < 0)
   return DEFER;
   }
 
+#ifndef SUPPORT_CA_DIR
 /* The test suite passes in /dev/null; we could check for that path explicitly,
 but who knows if someone has some weird FIFO which always dumps some certs, or
 other weirdness.  The thing we really want to check is that it's not a
@@ -899,6 +906,7 @@ if (S_ISDIR(statbuf.st_mode))
       state->exp_tls_verify_certificates);
   return DEFER;
   }
+#endif
 
 DEBUG(D_tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n",
         state->exp_tls_verify_certificates, statbuf.st_size);
@@ -910,8 +918,18 @@ if (statbuf.st_size == 0)
   return OK;
   }
 
-cert_count = gnutls_certificate_set_x509_trust_file(state->x509_cred,
+cert_count =
+
+#ifdef SUPPORT_CA_DIR
+  (statbuf.st_mode & S_IFMT) == S_IFDIR
+  ?
+  gnutls_certificate_set_x509_trust_dir(state->x509_cred,
+    CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM)
+  :
+#endif
+  gnutls_certificate_set_x509_trust_file(state->x509_cred,
     CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM);
+
 if (cert_count < 0)
   {
   rc = cert_count;
@@ -1524,18 +1542,18 @@ return 0;
 #endif
 
 
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
 /*
 We use this callback to get observability and detail-level control
-for an exim client TLS connection, raising a TPDA tls:cert event
-for each cert in the chain presented by the server.  Any event
+for an exim TLS connection (either direction), raising a tls:cert event
+for each cert in the chain presented by the peer.  Any event
 can deny verification.
 
 Return 0 for the handshake to continue or non-zero to terminate.
 */
 
 static int
-client_verify_cb(gnutls_session_t session)
+verify_cb(gnutls_session_t session)
 {
 const gnutls_datum * cert_list;
 unsigned int cert_list_size = 0;
@@ -1556,7 +1574,7 @@ if (cert_list)
     }
 
   state->tlsp->peercert = crt;
-  if (tpda_raise_event(state->event_action,
+  if (event_raise(state->event_action,
              US"tls:cert", string_sprintf("%d", cert_list_size)) == DEFER)
     {
     log_write(0, LOG_MAIN,
@@ -1646,6 +1664,15 @@ else
   gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE);
   }
 
+#ifdef EXPERIMENTAL_EVENT
+if (event_action)
+  {
+  state->event_action = event_action;
+  gnutls_session_set_ptr(state->session, state);
+  gnutls_certificate_set_verify_function(state->x509_cred, verify_cb);
+  }
+#endif
+
 /* Register SNI handling; always, even if not in tls_certificate, so that the
 expansion variable $tls_sni is always available. */
 
@@ -1867,12 +1894,12 @@ if (request_ocsp)
   }
 #endif
 
-#ifdef EXPERIMENTAL_TPDA
-if (tb->tpda_event_action)
+#ifdef EXPERIMENTAL_EVENT
+if (tb->event_action)
   {
-  state->event_action = tb->tpda_event_action;
+  state->event_action = tb->event_action;
   gnutls_session_set_ptr(state->session, state);
-  gnutls_certificate_set_verify_function(state->x509_cred, client_verify_cb);
+  gnutls_certificate_set_verify_function(state->x509_cred, verify_cb);
   }
 #endif