/* needed to disable PKCS11 autoload unless requested */
#if GNUTLS_VERSION_NUMBER >= 0x020c00
# include <gnutls/pkcs11.h>
+# define SUPPORT_PARAM_TO_PK_BITS
#endif
#if GNUTLS_VERSION_NUMBER < 0x030103 && !defined(DISABLE_OCSP)
# warning "GnuTLS library version too old; define DISABLE_OCSP in Makefile"
}
else if (exp_tls_dhparam[0] != '/')
{
- m.data = US std_dh_prime_named(exp_tls_dhparam);
- if (m.data == NULL)
+ if (!(m.data = US std_dh_prime_named(exp_tls_dhparam)))
return tls_error(US"No standard prime named", CS exp_tls_dhparam, NULL);
m.size = Ustrlen(m.data);
}
/* Open the cache file for reading and if successful, read it and set up the
parameters. */
-fd = Uopen(filename, O_RDONLY, 0);
-if (fd >= 0)
+if ((fd = Uopen(filename, O_RDONLY, 0)) >= 0)
{
struct stat statbuf;
FILE *fp;
(void)close(fd);
return tls_error(US"TLS cache not a file", NULL, NULL);
}
- fp = fdopen(fd, "rb");
- if (!fp)
+ if (!(fp = fdopen(fd, "rb")))
{
saved_errno = errno;
(void)close(fd);
}
m.size = statbuf.st_size;
- m.data = malloc(m.size);
- if (m.data == NULL)
+ if (!(m.data = malloc(m.size)))
{
fclose(fp);
return tls_error(US"malloc failed", strerror(errno), NULL);
}
- sz = fread(m.data, m.size, 1, fp);
- if (!sz)
+ if (!(sz = fread(m.data, m.size, 1, fp)))
{
saved_errno = errno;
fclose(fp);
CS filename, NULL);
temp_fn = string_copy(US "%s.XXXXXXX");
- fd = mkstemp(CS temp_fn); /* modifies temp_fn */
- if (fd < 0)
+ if ((fd = mkstemp(CS temp_fn)) < 0) /* modifies temp_fn */
return tls_error(US"Unable to open temp file", strerror(errno), NULL);
(void)fchown(fd, exim_uid, exim_gid); /* Probably not necessary */
if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
exim_gnutls_err_check(US"gnutls_dh_params_export_pkcs3(NULL) sizing");
m.size = sz;
- m.data = malloc(m.size);
- if (m.data == NULL)
+ if (!(m.data = malloc(m.size)))
return tls_error(US"memory allocation failed", strerror(errno), NULL);
+
/* this will return a size 1 less than the allocation size above */
rc = gnutls_dh_params_export_pkcs3(dh_server_params, GNUTLS_X509_FMT_PEM,
m.data, &sz);
}
m.size = sz; /* shrink by 1, probably */
- sz = write_to_fd_buf(fd, m.data, (size_t) m.size);
- if (sz != m.size)
+ if ((sz = write_to_fd_buf(fd, m.data, (size_t) m.size)) != m.size)
{
free(m.data);
return tls_error(US"TLS cache write D-H params failed",
strerror(errno), NULL);
}
free(m.data);
- sz = write_to_fd_buf(fd, US"\n", 1);
- if (sz != 1)
+ if ((sz = write_to_fd_buf(fd, US"\n", 1)) != 1)
return tls_error(US"TLS cache write D-H params final newline failed",
strerror(errno), NULL);
- rc = close(fd);
- if (rc)
- return tls_error(US"TLS cache write close() failed",
- strerror(errno), NULL);
+ if ((rc = close(fd)))
+ return tls_error(US"TLS cache write close() failed", strerror(errno), NULL);
if (Urename(temp_fn, filename) < 0)
return tls_error(string_sprintf("failed to rename \"%s\" as \"%s\"",
where = US"generating pkey";
if ((rc = gnutls_x509_privkey_generate(pkey, GNUTLS_PK_RSA,
+#ifdef SUPPORT_PARAM_TO_PK_BITS
gnutls_sec_param_to_pk_bits(GNUTLS_PK_RSA, GNUTLS_SEC_PARAM_LOW),
- 0))) /* _to_pk_bits() Since: 2.12.0 */
+#else
+ 1024,
+#endif
+ 0)))
goto err;
where = US"configuring cert";
int sep = 0;
const uschar * list = state->exp_tls_verify_cert_hostnames;
uschar * name;
- while (name = string_nextinlist(&list, &sep, NULL, 0))
+ while ((name = string_nextinlist(&list, &sep, NULL, 0)))
if (gnutls_x509_crt_check_hostname(state->tlsp->peercert, CS name))
break;
if (!name)
sigalrm_seen = FALSE;
if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
do
- {
rc = gnutls_handshake(state->session);
- } while ((rc == GNUTLS_E_AGAIN) ||
- (rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen));
+while (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen);
alarm(0);
if (rc != GNUTLS_E_SUCCESS)
{
- tls_error(US"gnutls_handshake",
- sigalrm_seen ? "timed out" : gnutls_strerror(rc), NULL);
/* 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
until the server times out. */
- if (!sigalrm_seen)
+ if (sigalrm_seen)
{
+ tls_error(US"gnutls_handshake", "timed out", NULL);
+ gnutls_db_remove_session(state->session);
+ }
+ else
+ {
+ tls_error(US"gnutls_handshake", gnutls_strerror(rc), NULL);
+ (void) gnutls_alert_send_appropriate(state->session, rc);
+ gnutls_deinit(state->session);
+ gnutls_certificate_free_credentials(state->x509_cred);
+ millisleep(500);
+ shutdown(state->fd_out, SHUT_WR);
+ for (rc = 1024; fgetc(smtp_in) != EOF && rc > 0; ) rc--; /* drain skt */
(void)fclose(smtp_out);
(void)fclose(smtp_in);
+ smtp_out = smtp_in = NULL;
}
return FAIL;
/* Figure out peer DN, and if authenticated, etc. */
-rc = peer_status(state);
-if (rc != OK) return rc;
+if ((rc = peer_status(state)) != OK) return rc;
/* Sets various Exim expansion variables; always safe within server */
state->xfer_buffer = store_malloc(ssl_xfer_buffer_size);
receive_getc = tls_getc;
+receive_get_cache = tls_get_cache;
receive_ungetc = tls_ungetc;
receive_feof = tls_feof;
receive_ferror = tls_ferror;
alarm(0);
if (rc != GNUTLS_E_SUCCESS)
- return tls_error(US"gnutls_handshake",
- sigalrm_seen ? "timed out" : gnutls_strerror(rc), state->host);
+ if (sigalrm_seen)
+ {
+ gnutls_alert_send(state->session, GNUTLS_AL_FATAL, GNUTLS_A_USER_CANCELED);
+ return tls_error(US"gnutls_handshake", "timed out", state->host);
+ }
+ else
+ return tls_error(US"gnutls_handshake", gnutls_strerror(rc), state->host);
DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");
}
gnutls_deinit(state->session);
+gnutls_certificate_free_credentials(state->x509_cred);
+
state->tlsp->active = -1;
memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
ssl_xfer_buffer_size);
alarm(0);
- /* A zero-byte return appears to mean that the TLS session has been
+ /* 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. */
- if (inbytes == 0)
+ if (sigalrm_seen)
+ {
+ DEBUG(D_tls) debug_printf("Got tls read timeout\n");
+ state->xfer_error = 1;
+ return EOF;
+ }
+
+ else if (inbytes == 0)
{
DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
receive_getc = smtp_getc;
+ receive_get_cache = smtp_get_cache;
receive_ungetc = smtp_ungetc;
receive_feof = smtp_feof;
receive_ferror = smtp_ferror;
receive_smtp_buffered = smtp_buffered;
gnutls_deinit(state->session);
+ gnutls_certificate_free_credentials(state->x509_cred);
+
state->session = NULL;
state->tlsp->active = -1;
state->tlsp->bits = 0;
return state->xfer_buffer[state->xfer_buffer_lwm++];
}
+void
+tls_get_cache()
+{
+#ifndef DISABLE_DKIM
+exim_gnutls_state_st * state = &state_server;
+int n = state->xfer_buffer_hwm - state->xfer_buffer_lwm;
+if (n > 0)
+ dkim_exim_verify_feed(state->xfer_buffer+state->xfer_buffer_lwm, n);
+#endif
+}
+