X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/e498ab40197936833f696439e78c5cb08e5180cb..cd1a5fe0ed22087c6afbe585ab0206c2a4a267aa:/src/src/tls-gnu.c diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index c7c6b2674..10bfaca32 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -493,8 +493,7 @@ else if (Ustrcmp(exp_tls_dhparam, "none") == 0) } 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); } @@ -548,8 +547,7 @@ if (use_file_in_spool) /* 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; @@ -566,8 +564,7 @@ if (fd >= 0) (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); @@ -576,14 +573,12 @@ if (fd >= 0) } 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); @@ -627,8 +622,7 @@ if (rc < 0) 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 */ @@ -665,9 +659,9 @@ if (rc < 0) 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); @@ -678,23 +672,19 @@ if (rc < 0) } 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\"", @@ -1832,16 +1822,27 @@ 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; @@ -1866,8 +1867,7 @@ if ( state->verify_requirement != VERIFY_NONE /* 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 */ @@ -1879,6 +1879,7 @@ and initialize appropriately. */ 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; @@ -2042,8 +2043,13 @@ do 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"); @@ -2125,6 +2131,8 @@ if (shutdown) } 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)); @@ -2170,21 +2178,32 @@ if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm) 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; @@ -2217,6 +2236,17 @@ if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm) 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 +} +