uschar *xfer_buffer;
int xfer_buffer_lwm;
int xfer_buffer_hwm;
- int xfer_eof;
- int xfer_error;
+ BOOL xfer_eof; /*XXX never gets set! */
+ BOOL xfer_error;
} exim_gnutls_state_st;
static const exim_gnutls_state_st exim_gnutls_state_init = {
.xfer_buffer = NULL,
.xfer_buffer_lwm = 0,
.xfer_buffer_hwm = 0,
- .xfer_eof = 0,
- .xfer_error = 0,
+ .xfer_eof = FALSE,
+ .xfer_error = FALSE,
};
/* Not only do we have our own APIs which don't pass around state, assuming
goto err;
where = US"configuring cert";
-now = 0;
+now = 1;
if ( (rc = gnutls_x509_crt_set_version(cert, 3))
|| (rc = gnutls_x509_crt_set_serial(cert, &now, sizeof(now)))
|| (rc = gnutls_x509_crt_set_activation_time(cert, now = time(NULL)))
(needed for TA but not EE). */
if (usage == ((1<<DANESSL_USAGE_DANE_TA) | (1<<DANESSL_USAGE_DANE_EE)))
- { /* a mixed-usage bundle */
+ { /* a mixed-usage bundle */
int i, j, nrec;
const char ** dd;
int * ddl;
1, 0))
|| (rc = dane_verify_crt_raw(s, certlist, lsize,
gnutls_certificate_type_get(state->session),
- r, 0,
+ r, 0,
# ifdef GNUTLS_BROKEN_DANE_VALIDATION
usage == (1 << DANESSL_USAGE_DANE_EE)
? DANE_VFLAG_ONLY_CHECK_EE_USAGE : 0,
uschar * yield;
exim_gnutls_state_st * state = gnutls_session_get_ptr(session);
-cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
-if (cert_list)
+if ((cert_list = gnutls_certificate_get_peers(session, &cert_list_size)))
while (cert_list_size--)
{
- rc = import_cert(&cert_list[cert_list_size], &crt);
- if (rc != GNUTLS_E_SUCCESS)
+ if ((rc = import_cert(&cert_list[cert_list_size], &crt)) != GNUTLS_E_SUCCESS)
{
DEBUG(D_tls) debug_printf("TLS: peer cert problem: depth %d: %s\n",
cert_list_size, gnutls_strerror(rc));
(smtp_transport_options_block *)tb->options_block;
int rc;
exim_gnutls_state_st * state = NULL;
+uschar *cipher_list = NULL;
#ifndef DISABLE_OCSP
BOOL require_ocsp =
verify_check_given_host(&ob->hosts_require_ocsp, host) == OK;
DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", fd);
+#ifdef SUPPORT_DANE
+if (tlsa_dnsa && ob->dane_require_tls_ciphers)
+ {
+ /* not using expand_check_tlsvar because not yet in state */
+ if (!expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers",
+ &cipher_list, errstr))
+ return DEFER;
+ cipher_list = cipher_list && *cipher_list
+ ? ob->dane_require_tls_ciphers : ob->tls_require_ciphers;
+ }
+#endif
+
+if (!cipher_list)
+ cipher_list = ob->tls_require_ciphers;
+
if ((rc = tls_init(host, ob->tls_certificate, ob->tls_privatekey,
ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl,
- ob->tls_require_ciphers, &state, errstr)) != OK)
+ cipher_list, &state, errstr)) != OK)
return rc;
{
daemon, to shut down the TLS library, without actually doing a shutdown (which
would tamper with the TLS session in the parent process).
-Arguments: TRUE if gnutls_bye is to be called
+Arguments:
+ shutdown 1 if TLS close-alert is to be sent,
+ 2 if also response to be waited for
+
Returns: nothing
*/
void
-tls_close(BOOL is_server, BOOL shutdown)
+tls_close(BOOL is_server, int shutdown)
{
exim_gnutls_state_st *state = is_server ? &state_server : &state_client;
if (shutdown)
{
- DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS\n");
- gnutls_bye(state->session, GNUTLS_SHUT_WR);
+ DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
+ shutdown > 1 ? " (with response-wait)" : "");
+
+ alarm(2);
+ gnutls_bye(state->session, shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+ alarm(0);
}
gnutls_deinit(state->session);
state->tlsp->active = -1;
+if (state->xfer_buffer) store_free(state->xfer_buffer);
memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
-if ((state_server.session == NULL) && (state_client.session == NULL))
+if (!state_server.session && !state_client.session)
{
gnutls_global_deinit();
exim_gnutls_base_init_done = FALSE;
if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
MIN(ssl_xfer_buffer_size, lim));
-alarm(0);
+if (smtp_receive_timeout > 0) alarm(0);
+
+if (had_command_timeout) /* set by signal handler */
+ smtp_command_timeout_exit(); /* does not return */
+if (had_command_sigterm)
+ smtp_command_sigterm_exit();
+if (had_data_timeout)
+ smtp_data_timeout_exit();
+if (had_data_sigint)
+ smtp_data_sigint_exit();
-/* Timeouts do not get this far; see command_timeout_handler().
- A zero-byte return appears to mean that the TLS session has been
- closed down, not that the socket itself has been closed down. Revert to
- non-TLS handling. */
+/* Timeouts do not get this far. A zero-byte return appears to mean that the
+TLS session has been closed down, not that the socket itself has been closed
+down. Revert to non-TLS handling. */
if (sigalrm_seen)
{
DEBUG(D_tls) debug_printf("Got tls read timeout\n");
- state->xfer_error = 1;
+ state->xfer_error = TRUE;
return FALSE;
}
else if (inbytes < 0)
{
record_io_error(state, (int) inbytes, US"recv", NULL);
- state->xfer_error = 1;
+ state->xfer_error = TRUE;
return FALSE;
}
#ifndef DISABLE_DKIM