commit f07c22772581c167112540af35b997e6829eef64 Author: Jeremy Harris Date: Sat Feb 9 16:56:59 2019 +0000 Fix json extract operator for unfound case (cherry picked from commit e73798976812e652320f096870359ef35ed069ff) (cherry picked from commit b2734f7b45111f9b7de790c7b334a2ece47675b5) (cherry picked from commit b88b6f6f3a29b70cd0b314da8ceab18b0b34eed6) diff --git a/src/src/expand.c b/src/src/expand.c index 1bcfbe8d..c2eba072 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -5861,10 +5861,11 @@ while (*s != 0) } while (field_number > 0 && (item = json_nextinlist(&list))) field_number--; - s = item; - lookup_value = s; - while (*s) s++; - while (--s >= lookup_value && isspace(*s)) *s = '\0'; + if ((lookup_value = s = item)) + { + while (*s) s++; + while (--s >= lookup_value && isspace(*s)) *s = '\0'; + } } else { commit 926fce6aaacb525c10c864d4064b1cd086e0dd5a Author: Jeremy Harris Date: Tue Feb 12 16:52:51 2019 +0000 Fix transport buffer size handling Broken-by: 59932f7dcd (cherry picked from commit 05bf16f6217e93594929c8bbbbbc852caf3ed374) (cherry picked from commit 1cfa7822ca8928f95160df8742af11fff888ae7e) (cherry picked from commit 0654d3440d8735221a58f96f5343fbe243171711) diff --git a/src/src/transport.c b/src/src/transport.c index 8ccdd038..a069b883 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -1115,13 +1115,13 @@ DEBUG(D_transport) if (!(tctx->options & topt_no_body)) { - int size = size_limit; + unsigned long size = size_limit > 0 ? size_limit : ULONG_MAX; nl_check_length = abs(nl_check_length); nl_partial_match = 0; if (lseek(deliver_datafile, SPOOL_DATA_START_OFFSET, SEEK_SET) < 0) return FALSE; - while ( (len = MAX(DELIVER_IN_BUFFER_SIZE, size)) > 0 + while ( (len = MIN(DELIVER_IN_BUFFER_SIZE, size)) > 0 && (len = read(deliver_datafile, deliver_in_buffer, len)) > 0) { if (!write_chunk(tctx, deliver_in_buffer, len)) commit 0799ba118b9c83731c1db34affcf9fecc10fd627 Author: Jeremy Harris Date: Thu Feb 14 17:14:34 2019 +0000 Fix info on using local_scan() in the default Makefile Broken-by: 9723f96673 (cherry picked from commit 882bc1704d33aa34873e3a0f72e657b0cc2985e5) (cherry picked from commit cb25b75af850d664fc005d24fbad0e58bf79d4c7) (cherry picked from commit 2c7c4a9c23950044507a78956ca2c23f9c6a9491) diff --git a/src/OS/Makefile-Default b/src/OS/Makefile-Default index b3990fe8..41a4dbbd 100644 --- a/src/OS/Makefile-Default +++ b/src/OS/Makefile-Default @@ -232,6 +232,11 @@ RANLIB=ranlib EXIM_CHMOD=@true +# If you want to use local_scan() at all, the support code must be included +# by uncommenting this line. + +# HAVE_LOCAL_SCAN=yes + # LOCAL_SCAN_SOURCE defines the file in which the function local_scan() is # defined. This provides the administrator with a hook for including C code # for scanning incoming mails. The path that is defined must be relative to @@ -239,8 +244,9 @@ EXIM_CHMOD=@true # LOCAL_SCAN_SOURCE=Local/local_scan.c -# The default setting points to a template function that doesn't actually do -# any scanning, but just accepts the message. +# A very simple example points to a template function that doesn't actually do +# any scanning, but just accepts the message. A compilable file must be +# included in the build even if HAVE_LOCAL_SCAN is not defined. LOCAL_SCAN_SOURCE=src/local_scan.c commit c07419f2eda0c1a3f2fe7282de9da2e661b8b068 Author: Jeremy Harris Date: Sat Feb 16 12:59:23 2019 +0000 GnuTLS: Fix client detection of server reject of client cert under TLS1.3 (cherry picked from commit fc243e944ec00b59b75f41d07494116f925d58b4) (cherry picked from commit c15523829ba17cce5829e2976aa1ff928965d948) (cherry picked from commit c18e2c3b059f6bfd1c6e9a65ffc8243a4d8034fe) diff --git a/src/src/deliver.c b/src/src/deliver.c index 664d0045..e1799411 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -7433,7 +7433,7 @@ if (addr_senddsn) tctx.u.fd = fd; tctx.options = topt_add_return_path | topt_no_body; - /*XXX hmm, retval ignored. + /*XXX hmm, FALSE(fail) retval ignored. Could error for any number of reasons, and they are not handled. */ transport_write_message(&tctx, 0); fflush(f); diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 9bd90c77..b194e804 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -688,20 +688,22 @@ Returns: TRUE if a valid, non-error response was received; else FALSE /*XXX could move to smtp transport; no other users */ BOOL -smtp_read_response(void * sx0, uschar *buffer, int size, int okdigit, +smtp_read_response(void * sx0, uschar * buffer, int size, int okdigit, int timeout) { smtp_context * sx = sx0; -uschar *ptr = buffer; -int count = 0; +uschar * ptr = buffer; +int count = 0, rc; errno = 0; /* Ensure errno starts out zero */ #ifdef EXPERIMENTAL_PIPE_CONNECT if (sx->pending_BANNER || sx->pending_EHLO) - if (smtp_reap_early_pipe(sx, &count) != OK) + if ((rc = smtp_reap_early_pipe(sx, &count)) != OK) { DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n"); + buffer[0] = '\0'; + if (rc == DEFER) errno = ERRNO_TLSFAILURE; return FALSE; } #endif diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index c404dc29..de2d70c0 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -229,7 +229,7 @@ static gnutls_dh_params_t dh_server_params = NULL; static const int ssl_session_timeout = 200; -static const char * const exim_default_gnutls_priority = "NORMAL"; +static const uschar * const exim_default_gnutls_priority = US"NORMAL"; /* Guard library core initialisation */ @@ -1278,7 +1278,6 @@ int rc; size_t sz; const char *errpos; uschar *p; -BOOL want_default_priorities; if (!exim_gnutls_base_init_done) { @@ -1387,32 +1386,24 @@ and replaces gnutls_require_kx, gnutls_require_mac & gnutls_require_protocols. This was backwards incompatible, but means Exim no longer needs to track all algorithms and provide string forms for them. */ -want_default_priorities = TRUE; - +p = NULL; if (state->tls_require_ciphers && *state->tls_require_ciphers) { if (!expand_check_tlsvar(tls_require_ciphers, errstr)) return DEFER; if (state->exp_tls_require_ciphers && *state->exp_tls_require_ciphers) { - DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority \"%s\"\n", - state->exp_tls_require_ciphers); - - rc = gnutls_priority_init(&state->priority_cache, - CS state->exp_tls_require_ciphers, &errpos); - want_default_priorities = FALSE; p = state->exp_tls_require_ciphers; + DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority \"%s\"\n", p); } } -if (want_default_priorities) +if (!p) { + p = exim_default_gnutls_priority; DEBUG(D_tls) - debug_printf("GnuTLS using default session cipher/priority \"%s\"\n", - exim_default_gnutls_priority); - rc = gnutls_priority_init(&state->priority_cache, - exim_default_gnutls_priority, &errpos); - p = US exim_default_gnutls_priority; + debug_printf("GnuTLS using default session cipher/priority \"%s\"\n", p); } +rc = gnutls_priority_init(&state->priority_cache, CCS p, &errpos); exim_gnutls_err_check(rc, string_sprintf( "gnutls_priority_init(%s) failed at offset %ld, \"%.6s..\"", diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c index 240d78b2..57b346d4 100644 --- a/src/src/transports/lmtp.c +++ b/src/src/transports/lmtp.c @@ -122,7 +122,8 @@ Arguments: Returns: TRUE if a "QUIT" command should be sent, else FALSE */ -static BOOL check_response(int *errno_value, int more_errno, uschar *buffer, +static BOOL +check_response(int *errno_value, int more_errno, uschar *buffer, int *yield, uschar **message) { *yield = '4'; /* Default setting is to give a temporary error */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index a351da84..bfd6018d 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -594,6 +594,11 @@ switch(*errno_value) pl, smtp_command, s); return FALSE; + case ERRNO_TLSFAILURE: /* Handle bad first read; can happen with + GnuTLS and TLS1.3 */ + *message = US"bad first read from TLS conn"; + return TRUE; + case ERRNO_FILTER_FAIL: /* Handle a failed filter process error; can't send QUIT as we mustn't end the DATA. */ *message = string_sprintf("transport filter process failed (%d)%s", @@ -942,6 +947,7 @@ Arguments: Return: OK all well + DEFER error on first read of TLS'd conn FAIL SMTP error in response */ int @@ -949,6 +955,7 @@ smtp_reap_early_pipe(smtp_context * sx, int * countp) { BOOL pending_BANNER = sx->pending_BANNER; BOOL pending_EHLO = sx->pending_EHLO; +int rc = FAIL; sx->pending_BANNER = FALSE; /* clear early to avoid recursion */ sx->pending_EHLO = FALSE; @@ -960,6 +967,7 @@ if (pending_BANNER) if (!smtp_reap_banner(sx)) { DEBUG(D_transport) debug_printf("bad banner\n"); + if (tls_out.active.sock >= 0) rc = DEFER; goto fail; } } @@ -974,6 +982,7 @@ if (pending_EHLO) if (!smtp_reap_ehlo(sx)) { DEBUG(D_transport) debug_printf("bad response for EHLO\n"); + if (tls_out.active.sock >= 0) rc = DEFER; goto fail; } @@ -1011,7 +1020,7 @@ return OK; fail: invalidate_ehlo_cache_entry(sx); (void) smtp_discard_responses(sx, sx->conn_args.ob, *countp); - return FAIL; + return rc; } #endif @@ -1056,6 +1065,7 @@ Returns: 3 if at least one address had 2xx and one had 5xx -2 I/O or other non-response error for RCPT -3 DATA or MAIL failed - errno and buffer set -4 banner or EHLO failed (early-pipelining) + -5 banner or EHLO failed (early-pipelining, TLS) */ static int @@ -1064,10 +1074,11 @@ sync_responses(smtp_context * sx, int count, int pending_DATA) address_item * addr = sx->sync_addr; smtp_transport_options_block * ob = sx->conn_args.ob; int yield = 0; +int rc; #ifdef EXPERIMENTAL_PIPE_CONNECT -if (smtp_reap_early_pipe(sx, &count) != OK) - return -4; +if ((rc = smtp_reap_early_pipe(sx, &count)) != OK) + return rc == FAIL ? -4 : -5; #endif /* Handle the response for a MAIL command. On error, reinstate the original @@ -1083,6 +1094,8 @@ if (sx->pending_MAIL) { DEBUG(D_transport) debug_printf("bad response for MAIL\n"); Ustrcpy(big_buffer, mail_command); /* Fits, because it came from there! */ + if (errno == ERRNO_TLSFAILURE) + return -5; if (errno == 0 && sx->buffer[0] != 0) { int save_errno = 0; @@ -1141,6 +1154,11 @@ while (count-- > 0) } } + /* Error on first TLS read */ + + else if (errno == ERRNO_TLSFAILURE) + return -5; + /* Timeout while reading the response */ else if (errno == ETIMEDOUT) @@ -1253,6 +1271,10 @@ if (pending_DATA != 0) int code; uschar *msg; BOOL pass_message; + + if (errno == ERRNO_TLSFAILURE) /* Error on first TLS read */ + return -5; + if (pending_DATA > 0 || (yield & 1) != 0) { if (errno == 0 && sx->buffer[0] == '4') @@ -1802,7 +1824,9 @@ Args: tc_chunk_last add LAST option to SMTP BDAT command tc_reap_prev reap response to previous SMTP commands -Returns: OK or ERROR +Returns: + OK or ERROR + DEFER TLS error on first read (EHLO-resp); errno set */ static int @@ -1859,10 +1883,12 @@ if (flags & tc_reap_prev && prev_cmd_count > 0) case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */ case 0: break; /* No 2xx or 5xx, but no probs */ - case -1: /* Timeout on RCPT */ + case -5: errno = ERRNO_TLSFAILURE; + return DEFER; #ifdef EXPERIMENTAL_PIPE_CONNECT case -4: /* non-2xx for pipelined banner or EHLO */ #endif + case -1: /* Timeout on RCPT */ default: return ERROR; /* I/O error, or any MAIL/DATA error */ } cmd_count = 1; @@ -1933,6 +1959,9 @@ BOOL pass_message = FALSE; uschar * message = NULL; int yield = OK; int rc; +#ifdef SUPPORT_TLS +uschar * tls_errstr; +#endif sx->conn_args.ob = ob; @@ -2474,27 +2503,27 @@ if ( smtp_peer_options & OPTION_TLS TLS_NEGOTIATE: { address_item * addr; - uschar * errstr; sx->cctx.tls_ctx = tls_client_start(sx->cctx.sock, sx->conn_args.host, sx->addrlist, sx->conn_args.tblock, # ifdef SUPPORT_DANE sx->dane ? &tlsa_dnsa : NULL, # endif - &tls_out, &errstr); + &tls_out, &tls_errstr); if (!sx->cctx.tls_ctx) { /* TLS negotiation failed; give an error. From outside, this function may be called again to try in clear on a new connection, if the options permit it for this host. */ - DEBUG(D_tls) debug_printf("TLS session fail: %s\n", errstr); +GNUTLS_CONN_FAILED: + DEBUG(D_tls) debug_printf("TLS session fail: %s\n", tls_errstr); # ifdef SUPPORT_DANE if (sx->dane) { log_write(0, LOG_MAIN, "DANE attempt failed; TLS connection to %s [%s]: %s", - sx->conn_args.host->name, sx->conn_args.host->address, errstr); + sx->conn_args.host->name, sx->conn_args.host->address, tls_errstr); # ifndef DISABLE_EVENT (void) event_raise(sx->conn_args.tblock->event_action, US"dane:fail", US"validation-failure"); /* could do with better detail */ @@ -2503,7 +2532,7 @@ if ( smtp_peer_options & OPTION_TLS # endif errno = ERRNO_TLSFAILURE; - message = string_sprintf("TLS session: %s", errstr); + message = string_sprintf("TLS session: %s", tls_errstr); sx->send_quit = FALSE; goto TLS_FAILED; } @@ -2601,7 +2630,22 @@ if (tls_out.active.sock >= 0) #endif { if (!smtp_reap_ehlo(sx)) +#ifdef USE_GNUTLS + { + /* The GnuTLS layer in Exim only spots a server-rejection of a client + cert late, under TLS1.3 - which means here; the first time we try to + receive crypted data. Treat it as if it was a connect-time failure. + See also the early-pipe equivalent... which will be hard; every call + to sync_responses will need to check the result. + It would be nicer to have GnuTLS check the cert during the handshake. + Can it do that, with all the flexibility we need? */ + + tls_errstr = US"error on first read"; + goto GNUTLS_CONN_FAILED; + } +#else goto RESPONSE_FAILED; +#endif smtp_peer_options = 0; } } @@ -3261,6 +3305,7 @@ for (addr = sx->first_addr, address_count = 0; #ifdef EXPERIMENTAL_PIPE_CONNECT case -4: return -1; /* non-2xx for pipelined banner or EHLO */ + case -5: return -1; /* TLS first-read error */ #endif } sx->pending_MAIL = FALSE; /* Dealt with MAIL */ @@ -3589,11 +3634,12 @@ if ( !(sx.peer_offered & OPTION_CHUNKING) case 1: sx.ok = TRUE; /* 2xx (only) => OK, but if LMTP, */ if (!sx.lmtp) sx.completed_addr = TRUE; /* can't tell about progress yet */ - case 0: break; /* No 2xx or 5xx, but no probs */ + case 0: break; /* No 2xx or 5xx, but no probs */ - case -1: goto END_OFF; /* Timeout on RCPT */ + case -1: goto END_OFF; /* Timeout on RCPT */ #ifdef EXPERIMENTAL_PIPE_CONNECT + case -5: /* TLS first-read error */ case -4: HDEBUG(D_transport) debug_printf("failed reaping pipelined cmd responses\n"); #endif @@ -3730,19 +3776,20 @@ else { case 3: sx.ok = TRUE; /* 2xx & 5xx => OK & progress made */ case 2: sx.completed_addr = TRUE; /* 5xx (only) => progress made */ - break; + break; - case 1: sx.ok = TRUE; /* 2xx (only) => OK, but if LMTP, */ + case 1: sx.ok = TRUE; /* 2xx (only) => OK, but if LMTP, */ if (!sx.lmtp) sx.completed_addr = TRUE; /* can't tell about progress yet */ - case 0: break; /* No 2xx or 5xx, but no probs */ + case 0: break; /* No 2xx or 5xx, but no probs */ - case -1: goto END_OFF; /* Timeout on RCPT */ + case -1: goto END_OFF; /* Timeout on RCPT */ #ifdef EXPERIMENTAL_PIPE_CONNECT + case -5: /* TLS first-read error */ case -4: HDEBUG(D_transport) debug_printf("failed reaping pipelined cmd responses\n"); #endif - default: goto RESPONSE_FAILED; /* I/O error, or any MAIL/DATA error */ + default: goto RESPONSE_FAILED; /* I/O error, or any MAIL/DATA error */ } } commit 27662d806b99c9369e564f6f33769836c27085df Author: Jasen Betts Date: Mon Feb 18 13:52:16 2019 +0000 Fix expansions for RFC 822 addresses having comments in local-part and/or domain. Bug 2375 (cherry picked from commit e2ff8e24f41caca3623228b1ec66a3f3961ecad6) (cherry picked from commit f634b80846cc7ffcab65c9855bcb35312f0232e8) (cherry picked from commit cebd5bd2ab84c7815a9b99c0f0f16e829af7b4bc) diff --git a/src/src/expand.c b/src/src/expand.c index c2eba072..fbb2dfb1 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -7151,16 +7151,11 @@ while (*s != 0) uschar * t = parse_extract_address(sub, &error, &start, &end, &domain, FALSE); if (t) - if (c != EOP_DOMAIN) - { - if (c == EOP_LOCAL_PART && domain != 0) end = start + domain - 1; - yield = string_catn(yield, sub+start, end-start); - } - else if (domain != 0) - { - domain += start; - yield = string_catn(yield, sub+domain, end-domain); - } + yield = c == EOP_DOMAIN + ? string_cat(yield, t + domain) + : c == EOP_LOCAL_PART && domain > 0 + ? string_catn(yield, t, domain - 1 ) + : string_cat(yield, t); continue; } @@ -7184,7 +7179,7 @@ while (*s != 0) for (;;) { - uschar *p = parse_find_address_end(sub, FALSE); + uschar * p = parse_find_address_end(sub, FALSE); uschar saveend = *p; *p = '\0'; address = parse_extract_address(sub, &error, &start, &end, &domain, @@ -7197,7 +7192,7 @@ while (*s != 0) list, add in a space if the new address begins with the separator character, or is an empty string. */ - if (address != NULL) + if (address) { if (yield->ptr != save_ptr && address[0] == *outsep) yield = string_catn(yield, US" ", 1); commit 97229a2119f27f735ba4f02c131aac116ee0d5d5 Author: Jeremy Harris Date: Thu Mar 14 12:26:34 2019 +0000 Fix crash from SRV lookup hitting a CNAME (cherry picked from commit 14bc9cf085aff7bd5147881e5b7068769a29b026) (cherry picked from commit 09720dd9506176294154dad7152f5f40554046a4) (cherry picked from commit a189eb636256833f3053d8f2fbb95e51dc0f936c) diff --git a/src/src/dns.c b/src/src/dns.c index 0f0b435d..b7978c52 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -716,7 +716,11 @@ lookup, which constructs the names itself, so they should be OK. Besides, bitstring labels don't conform to normal name syntax. (But the aren't used any more.) -For SRV records, we omit the initial _smtp._tcp. components at the start. */ +For SRV records, we omit the initial _smtp._tcp. components at the start. +The check has been seen to bite on the destination of a SRV lookup that +initiall hit a CNAME, for which the next name had only two components. +RFC2782 makes no mention of the possibiility of CNAMES, but the Wikipedia +article on SRV says they are not a valid configuration. */ #ifndef STAND_ALONE /* Omit this for stand-alone tests */ @@ -732,8 +736,8 @@ if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT) if (type == T_SRV || type == T_TLSA) { - while (*checkname++ != '.'); - while (*checkname++ != '.'); + while (*checkname && *checkname++ != '.') ; + while (*checkname && *checkname++ != '.') ; } if (pcre_exec(regex_check_dns_names, NULL, CCS checkname, Ustrlen(checkname), commit c0c781e2cabb7746a49edc88043db91f9e869c0b Author: Jeremy Harris Date: Mon Mar 18 00:31:43 2019 +0000 Logging: fix initial listening-on log line (cherry picked from commit 254f38d1c5ada5e4df0bccb385dc466549620c71) (cherry picked from commit e5be948a65fe601024e5d4256f64efbfed3dd72e) (cherry picked from commit 8b81ffe198b36c7d3dcaa1697ab71eefa78946ed) diff --git a/src/src/daemon.c b/src/src/daemon.c index a852192e..01da3936 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -1627,8 +1627,8 @@ else if (f.daemon_listen) int i, j; int smtp_ports = 0; int smtps_ports = 0; - ip_address_item * ipa, * i2; - uschar * p = big_buffer; + ip_address_item * ipa; + uschar * p; uschar * qinfo = queue_interval > 0 ? string_sprintf("-q%s", readconf_printtime(queue_interval)) : US"no queue runs"; @@ -1640,27 +1640,19 @@ else if (f.daemon_listen) deprecated protocol that starts TLS without using STARTTLS), and others listening for standard SMTP. Keep their listings separate. */ - for (j = 0; j < 2; j++) + for (int j = 0, i; j < 2; j++) { for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next) { /* First time round, look for SMTP ports; second time round, look for - SMTPS ports. For the first one of each, insert leading text. */ + SMTPS ports. Build IP+port strings. */ if (host_is_tls_on_connect_port(ipa->port) == (j > 0)) { if (j == 0) - { - if (smtp_ports++ == 0) - { - memcpy(p, "SMTP on", 8); - p += 7; - } - } + smtp_ports++; else - if (smtps_ports++ == 0) - p += sprintf(CS p, "%sSMTPS on", - smtp_ports == 0 ? "" : " and for "); + smtps_ports++; /* Now the information about the port (and sometimes interface) */ @@ -1669,40 +1661,67 @@ else if (f.daemon_listen) if (ipa->next && ipa->next->address[0] == 0 && ipa->next->port == ipa->port) { - p += sprintf(CS p, " port %d (IPv6 and IPv4)", ipa->port); - ipa = ipa->next; + ipa->log = string_sprintf(" port %d (IPv6 and IPv4)", ipa->port); + (ipa = ipa->next)->log = NULL; } else if (ipa->v6_include_v4) - p += sprintf(CS p, " port %d (IPv6 with IPv4)", ipa->port); + ipa->log = string_sprintf(" port %d (IPv6 with IPv4)", ipa->port); else - p += sprintf(CS p, " port %d (IPv6)", ipa->port); + ipa->log = string_sprintf(" port %d (IPv6)", ipa->port); } else if (ipa->address[0] == 0) /* v4 wildcard */ - p += sprintf(CS p, " port %d (IPv4)", ipa->port); + ipa->log = string_sprintf(" port %d (IPv4)", ipa->port); else /* check for previously-seen IP */ { + ip_address_item * i2; for (i2 = addresses; i2 != ipa; i2 = i2->next) if ( host_is_tls_on_connect_port(i2->port) == (j > 0) && Ustrcmp(ipa->address, i2->address) == 0 ) { /* found; append port to list */ - if (p[-1] == '}') p--; - while (isdigit(*--p)) ; - p += 1 + sprintf(CS p+1, "%s%d,%d}", *p == ',' ? "" : "{", - i2->port, ipa->port); + for (p = i2->log; *p; ) p++; /* end of existing string */ + if (*--p == '}') *p = '\0'; /* drop EOL */ + while (isdigit(*--p)) ; /* char before port */ + + i2->log = *p == ':' /* no list yet? */ + ? string_sprintf("%.*s{%s,%d}", + (int)(p - i2->log + 1), i2->log, p+1, ipa->port) + : string_sprintf("%s,%d}", i2->log, ipa->port); + ipa->log = NULL; break; } if (i2 == ipa) /* first-time IP */ - p += sprintf(CS p, " [%s]:%d", ipa->address, ipa->port); + ipa->log = string_sprintf(" [%s]:%d", ipa->address, ipa->port); } } } + } - if (ipa) + p = big_buffer; + for (int j = 0, i; j < 2; j++) + { + /* First time round, look for SMTP ports; second time round, look for + SMTPS ports. For the first one of each, insert leading text. */ + + if (j == 0) { - memcpy(p, " ...", 5); - p += 4; + if (smtp_ports > 0) + p += sprintf(CS p, "SMTP on"); } + else + if (smtps_ports > 0) + p += sprintf(CS p, "%sSMTPS on", + smtp_ports == 0 ? "" : " and for "); + + /* Now the information about the port (and sometimes interface) */ + + for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next) + if (host_is_tls_on_connect_port(ipa->port) == (j > 0)) + if (ipa->log) + p += sprintf(CS p, "%s", ipa->log); + + if (ipa) + p += sprintf(CS p, " ..."); } log_write(0, LOG_MAIN, diff --git a/src/src/host.c b/src/src/host.c index 29c977fe..a3b0977b 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -759,6 +759,7 @@ while ((s = string_nextinlist(&list, &sep, NULL, 0))) Ustrcpy(next->address, s); next->port = port; next->v6_include_v4 = FALSE; + next->log = NULL; if (!yield) yield = last = next; diff --git a/src/src/structs.h b/src/src/structs.h index 20db0e5f..1e63d752 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -444,6 +444,7 @@ typedef struct ip_address_item { int port; BOOL v6_include_v4; /* Used in the daemon */ uschar address[46]; + uschar * log; /* portion of "listening on" log line */ } ip_address_item; /* Structure for chaining together arbitrary strings. */ commit 412885bdba907588c5ac8ea789e673c3198d381a Author: Jeremy Harris Date: Tue Mar 19 15:33:31 2019 +0000 OpenSSL: Fix aggregation of messages. Broken-by: a5ffa9b475 (cherry picked from commit c09dbcfb71f4b9a42cbfd8a20e0be6bfa1b12488) (cherry picked from commit 332ebeaf8139b2b75f475880fc14b63c7c45c706) (cherry picked from commit 1bd4207a399775cf842607930e76c14ac54327df) diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 8f4cf4d8..cc0ead02 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -274,6 +274,7 @@ Server: typedef struct { SSL_CTX * ctx; SSL * ssl; + gstring * corked; } exim_openssl_client_tls_ctx; static SSL_CTX *server_ctx = NULL; @@ -2473,6 +2474,7 @@ BOOL require_ocsp = FALSE; rc = store_pool; store_pool = POOL_PERM; exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx)); +exim_client_ctx->corked = NULL; store_pool = rc; #ifdef SUPPORT_DANE @@ -2908,8 +2910,12 @@ int tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more) { int outbytes, error, left; -SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl; -static gstring * corked = NULL; +SSL * ssl = ct_ctx + ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl; +static gstring * server_corked = NULL; +gstring ** corkedp = ct_ctx + ? &((exim_openssl_client_tls_ctx *)ct_ctx)->corked : &server_corked; +gstring * corked = *corkedp; DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__, buff, (unsigned long)len, more ? ", more" : ""); @@ -2917,9 +2923,12 @@ DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__, /* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when "more" is notified. This hack is only ok if small amounts are involved AND only one stream does it, in one context (i.e. no store reset). Currently it is used -for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. */ -/*XXX + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's -a store reset there. */ +for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. +We support callouts done by the server process by using a separate client +context for the stashed information. */ +/* + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's +a store reset there, so use POOL_PERM. */ +/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */ if (!ct_ctx && (more || corked)) { @@ -2935,10 +2944,13 @@ if (!ct_ctx && (more || corked)) #endif if (more) + { + *corkedp = corked; return len; + } buff = CUS corked->s; len = corked->ptr; - corked = NULL; + *corkedp = NULL; } for (left = len; left > 0;) commit 3063baa25c0a8103438ee73051e61f82476861b3 Author: Jeremy Harris Date: Thu Mar 21 20:01:03 2019 +0000 Harden plaintext authenticator Cherry-picked from: f9fc942757 (cherry picked from commit e5b942ae007d0533fbd599c64d550f3a8355b940) (cherry picked from commit 7556111f007c98f11adfa27c492d73b775886d9d) diff --git a/src/src/auths/plaintext.c b/src/src/auths/plaintext.c index 7a0f7885..fa05b0ad 100644 --- a/src/src/auths/plaintext.c +++ b/src/src/auths/plaintext.c @@ -223,11 +223,7 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size))) if (ss[i+1] != '^') ss[i] = 0; else - { - i++; - len--; - memmove(ss + i, ss + i + 1, len - i); - } + if (--len > ++i) memmove(ss + i, ss + i + 1, len - i); /* The first string is attached to the AUTH command; others are sent unembellished. */ commit 0b558fbc10d6a0dd6337903d3d85dcc161724e8c Author: Jeremy Harris Date: Fri Mar 22 15:00:23 2019 +0000 Fix "-bP smtp_receive_timeout". Bug 2384 (cherry picked from commit e6024a5e9e193f559508d05ee401ae8f7f3c25ae) (cherry picked from commit 2cf1c24f203b3995cfa4434907cff05917a55c90) (cherry picked from commit 9cfb6ebeb68fcefc83e261cff036aaf444d7d4c5) diff --git a/src/src/readconf.c b/src/src/readconf.c index 5742d10a..10bde557 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -19,7 +19,7 @@ implementation of the conditional .ifdef etc. */ static uschar * syslog_facility_str; -static void fn_smtp_receive_timeout(const uschar *, const uschar *); +static void fn_smtp_receive_timeout(const uschar *, const uschar *, unsigned); /************************************************* * Main configuration options * @@ -392,7 +392,8 @@ static int optionlist_config_size = nelem(optionlist_config); #ifdef MACRO_PREDEF -static void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {/*Dummy*/} +static void +fn_smtp_receive_timeout(const uschar * name, const uschar * str, unsigned flags) {/*Dummy*/} void options_main(void) @@ -559,6 +560,8 @@ static syslog_fac_item syslog_list[] = { static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item); +#define opt_fn_print BIT(0) +#define opt_fn_print_label BIT(1) /************************************************* @@ -1532,9 +1535,16 @@ return yield; * Custom-handler options * *************************************************/ static void -fn_smtp_receive_timeout(const uschar * name, const uschar * str) +fn_smtp_receive_timeout(const uschar * name, const uschar * str, unsigned flags) { -if (*str == '$') +if (flags & opt_fn_print) + { + if (flags & opt_fn_print_label) printf("%s = ", name); + printf("%s\n", smtp_receive_timeout_s + ? string_printing2(smtp_receive_timeout_s, FALSE) + : readconf_printtime(smtp_receive_timeout)); + } +else if (*str == '$') smtp_receive_timeout_s = string_copy(str); else { @@ -2328,7 +2338,7 @@ switch (type) case opt_func: { void (*fn)() = ol->value; - fn(name, s); + fn(name, s, 0); break; } } @@ -2670,6 +2680,13 @@ switch(ol->type & opt_mask) case opt_bool_set: printf("%s%s\n", (*((BOOL *)value))? "" : "no_", name); break; + + case opt_func: + { + void (*fn)() = ol->value; + fn(name, NULL, no_labels ? opt_fn_print : opt_fn_print|opt_fn_print_label); + break; + } } return TRUE; } commit f627fcf379d9453326672016168e2e73f6c42916 Author: Jeremy Harris Date: Fri Apr 5 13:38:54 2019 +0100 Fix build with recent LibreSSL, when including DANE. Bug 2386 (cherry picked from commit c19ab167ac and 1fbf41cdf6 (cherry picked from commit 0d82437ff97668a34a67b4ba398d1294ec016d3a) (cherry picked from commit 09cc73f04332f420e07f4bc8bb2e2466c2460067) diff --git a/src/src/dane-openssl.c b/src/src/dane-openssl.c index f7ccbd76..79f136ea 100644 --- a/src/src/dane-openssl.c +++ b/src/src/dane-openssl.c @@ -2,7 +2,7 @@ * Author: Viktor Dukhovni * License: THIS CODE IS IN THE PUBLIC DOMAIN. * - * Copyright (c) The Exim Maintainers 2014 - 2018 + * Copyright (c) The Exim Maintainers 2014 - 2019 */ #include #include @@ -25,9 +25,18 @@ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) # define X509_up_ref(x) CRYPTO_add(&((x)->references), 1, CRYPTO_LOCK_X509) #endif + +/* LibreSSL 2.9.0 and later - 2.9.0 has removed a number of macros ... */ +#ifdef LIBRESSL_VERSION_NUMBER +# if LIBRESSL_VERSION_NUMBER >= 0x2090000fL +# define EXIM_HAVE_ASN1_MACROS +# endif +#endif +/* OpenSSL */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) # define EXIM_HAVE_ASN1_MACROS # define EXIM_OPAQUE_X509 +/* Older OpenSSL and all LibreSSL */ #else # define X509_STORE_CTX_get_verify(ctx) (ctx)->verify # define X509_STORE_CTX_get_verify_cb(ctx) (ctx)->verify_cb diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c index 7e0128ee..3551045c 100644 --- a/src/src/tlscert-openssl.c +++ b/src/src/tlscert-openssl.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) Jeremy Harris 2014 - 2018 */ +/* Copyright (c) Jeremy Harris 2014 - 2019 */ /* This module provides TLS (aka SSL) support for Exim using the OpenSSL library. It is #included into the tls.c file when that library is used. @@ -17,8 +17,14 @@ library. It is #included into the tls.c file when that library is used. #include #include -#if OPENSSL_VERSION_NUMBER >= 0x10100000L -# define EXIM_HAVE_ASN1_MACROS +#ifdef LIBRESSL_VERSION_NUMBER /* LibreSSL */ +# if LIBRESSL_VERSION_NUMBER >= 0x2090000fL +# define EXIM_HAVE_ASN1_MACROS +# endif +#else /* OpenSSL */ +# if OPENSSL_VERSION_NUMBER >= 0x10100000L +# define EXIM_HAVE_ASN1_MACROS +# endif #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) commit 6c2054f65ae6beb2a38c6188c0807417adbb3880 Author: Jeremy Harris Date: Thu Apr 4 14:33:28 2019 +0100 SPF: better buld compatibility with OpenBSD (cherry picked from commit bda76da8a9357f4fc525b5f8b925fae262c28010) (cherry picked from commit 804219086fe9afbc1429c309e339524aaaabcec1) (cherry picked from commit c26e27d5b81ed5640c00ee87f1d4287fb066dc12) diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c index b32a73e6..48d6ce3b 100644 --- a/src/src/lookups/spf.c +++ b/src/src/lookups/spf.c @@ -25,8 +25,8 @@ static void dummy(int x) { dummy2(x-1); } #else #include "lf_functions.h" -#ifndef HAVE_NS_TYPE -#define HAVE_NS_TYPE +#if !defined(HAVE_NS_TYPE) && defined(NS_INADDRSZ) +# define HAVE_NS_TYPE #endif #include #include diff --git a/src/src/spf.h b/src/src/spf.h index 23ad325f..a0779f87 100644 --- a/src/src/spf.h +++ b/src/src/spf.h @@ -11,7 +11,7 @@ #ifdef SUPPORT_SPF /* Yes, we do have ns_type. spf.h redefines it if we don't set this. Doh */ -#ifndef HAVE_NS_TYPE +#if !defined(HAVE_NS_TYPE) && defined(NS_INADDRSZ) # define HAVE_NS_TYPE #endif #include commit d3a0dde57754d2b434957c126e1a22e2094cbbf1 Author: Jeremy Harris Date: Thu Apr 25 18:24:33 2019 +0100 GnuTLS 3.6.7 cipher strings (cherry picked from commits d9acfc1ce6, 57eb2f6463, b9c6f63cd5) WARNING: This changes user-visible and configuration-visible behaviour. Read the ChangeLog! (cherry picked from commit 656b804e099a4704bd6071241a85bc1e0cc85887) (cherry picked from commit bf9375eaa85bfa0dbb973aa03accbe5f21808732) diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index de2d70c0..af815d22 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -67,6 +67,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries). #if GNUTLS_VERSION_NUMBER >= 0x030109 # define SUPPORT_CORK #endif +#if GNUTLS_VERSION_NUMBER >= 0x03010a +# define SUPPORT_GNUTLS_SESS_DESC +#endif #if GNUTLS_VERSION_NUMBER >= 0x030506 && !defined(DISABLE_OCSP) # define SUPPORT_SRV_OCSP_STACK #endif @@ -1487,23 +1490,61 @@ state->peerdn = NULL; cipher = gnutls_cipher_get(state->session); protocol = gnutls_protocol_get_version(state->session); mac = gnutls_mac_get(state->session); -kx = gnutls_kx_get(state->session); - -string_format(cipherbuf, sizeof(cipherbuf), - "%s:%s:%d", - gnutls_protocol_get_name(protocol), - gnutls_cipher_suite_get_name(kx, cipher, mac), - (int) gnutls_cipher_get_key_size(cipher) * 8); - -/* I don't see a way that spaces could occur, in the current GnuTLS -code base, but it was a concern in the old code and perhaps older GnuTLS -releases did return "TLS 1.0"; play it safe, just in case. */ -for (p = cipherbuf; *p != '\0'; ++p) - if (isspace(*p)) - *p = '-'; +kx = +#ifdef GNUTLS_TLS1_3 + protocol >= GNUTLS_TLS1_3 ? 0 : +#endif + gnutls_kx_get(state->session); + old_pool = store_pool; -store_pool = POOL_PERM; -state->ciphersuite = string_copy(cipherbuf); + { + store_pool = POOL_PERM; + +#ifdef SUPPORT_GNUTLS_SESS_DESC + { + gstring * g = NULL; + uschar * s = US gnutls_session_get_desc(state->session), c; + + /* Nikos M suggests we use this by preference. It returns like: + (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM) + + For partial back-compat, put a colon after the TLS version, replace the + )-( grouping with __, replace in-group - with _ and append the :keysize. */ + + /* debug_printf("peer_status: gnutls_session_get_desc %s\n", s); */ + + for (s++; (c = *s) && c != ')'; s++) g = string_catn(g, s, 1); + g = string_catn(g, US":", 1); + if (*s) s++; /* now on _ between groups */ + while ((c = *s)) + { + for (*++s && ++s; (c = *s) && c != ')'; s++) g = string_catn(g, c == '-' ? US"_" : s, 1); + /* now on ) closing group */ + if ((c = *s) && *++s == '-') g = string_catn(g, US"__", 2); + /* now on _ between groups */ + } + g = string_catn(g, US":", 1); + g = string_cat(g, string_sprintf("%d", (int) gnutls_cipher_get_key_size(cipher) * 8)); + state->ciphersuite = string_from_gstring(g); + } +#else + state->ciphersuite = string_sprintf("%s:%s:%d", + gnutls_protocol_get_name(protocol), + gnutls_cipher_suite_get_name(kx, cipher, mac), + (int) gnutls_cipher_get_key_size(cipher) * 8); + + /* I don't see a way that spaces could occur, in the current GnuTLS + code base, but it was a concern in the old code and perhaps older GnuTLS + releases did return "TLS 1.0"; play it safe, just in case. */ + + for (uschar * p = state->ciphersuite; *p; p++) if (isspace(*p)) *p = '-'; +#endif + +/* debug_printf("peer_status: ciphersuite %s\n", state->ciphersuite); */ + + state->tlsp->cipher = state->ciphersuite; + state->tlsp->bits = gnutls_cipher_get_key_size(cipher) * 8; + } store_pool = old_pool; state->tlsp->cipher = state->ciphersuite; commit 6712694eae57a7d3544c6f0d8a6c03cd246fdb48 Author: Jeremy Harris Date: Tue May 7 22:55:41 2019 +0100 GnuTLS: fix $tls_out_ocsp under hosts_request_ocsp (cherry picked from commit 7a501c874f028f689c44999ab05bb0d39da46941) (cherry picked from commit 5e64b73ef7cdaf20b998b3345a588b462fd30bfb) (cherry picked from commit 31700e5410af3d27654ff0a32c20d30b1a1e10c3) diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index af815d22..746eabfd 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2491,7 +2491,7 @@ if (!verify_certificate(state, errstr)) } #ifndef DISABLE_OCSP -if (require_ocsp) +if (request_ocsp) { DEBUG(D_tls) { @@ -2515,10 +2515,14 @@ if (require_ocsp) { tlsp->ocsp = OCSP_FAILED; tls_error(US"certificate status check failed", NULL, state->host, errstr); - return NULL; + if (require_ocsp) + return FALSE; + } + else + { + DEBUG(D_tls) debug_printf("Passed OCSP checking\n"); + tlsp->ocsp = OCSP_VFIED; } - DEBUG(D_tls) debug_printf("Passed OCSP checking\n"); - tlsp->ocsp = OCSP_VFIED; } #endif commit fbf6767e15a0367d3f3a8462bc3a87d96bf7b71a Author: Jeremy Harris Date: Fri May 10 15:35:58 2019 +0100 Fix listing a named queue by a non-admin user. Bug 2398 (cherry picked from commit e5903596a0) (cherry picked from commit affc23f0d27bfbca773094146d7e62872ed2895b) (cherry picked from commit 772e1c684e79465df71157cdccc57739bb841cae) diff --git a/src/src/exim.c b/src/src/exim.c index f6f15f44..83b5ef51 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -3187,22 +3187,23 @@ for (i = 1; i < argc; i++) /* -q[f][f][l][G]: Run the queue, optionally forced, optionally local only, optionally named, optionally starting from a given message id. */ - if (*argrest == 0 && - (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1]))) - { - queue_interval = 0; - if (i+1 < argc && mac_ismsgid(argv[i+1])) - start_queue_run_id = argv[++i]; - if (i+1 < argc && mac_ismsgid(argv[i+1])) - stop_queue_run_id = argv[++i]; - } + if (!(list_queue || count_queue)) + if (*argrest == 0 + && (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1]))) + { + queue_interval = 0; + if (i+1 < argc && mac_ismsgid(argv[i+1])) + start_queue_run_id = argv[++i]; + if (i+1 < argc && mac_ismsgid(argv[i+1])) + stop_queue_run_id = argv[++i]; + } /* -q[f][f][l][G/]: Run the queue at regular intervals, optionally forced, optionally local only, optionally named. */ - else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i], - 0, FALSE)) <= 0) - exim_fail("exim: bad time value %s: abandoned\n", argv[i]); + else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i], + 0, FALSE)) <= 0) + exim_fail("exim: bad time value %s: abandoned\n", argv[i]); break; commit 7894bfc6ccf7157dc5d8a11e297fb71968dd2904 Author: Jeremy Harris Date: Sun May 19 12:12:36 2019 +0100 GnuTLS: fix the advertising of acceptable certs by the server. Bug 2389 (cherry picked from commit 12d95aa62042377fc9f603245a17a43142972447) (cherry picked from commit 44893ba5249c6c6d5a0d62a1cc57ba3fbf7185b4) (cherry picked from commit 7eb6988c118847820de130c9317f851983e0ba8b) diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 746eabfd..867dbbe3 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -1136,6 +1136,14 @@ else #endif gnutls_certificate_set_x509_trust_file(state->x509_cred, CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM); + +#ifdef SUPPORT_CA_DIR + /* Mimic the behaviour with OpenSSL of not advertising a usable-cert list + when using the directory-of-certs config model. */ + + if ((statbuf.st_mode & S_IFMT) == S_IFDIR) + gnutls_certificate_send_x509_rdn_sequence(state->session, 1); +#endif } if (cert_count < 0) commit 09898a2fe75f7044f9f46bd01dcd0e2f22f61d0d Author: Jeremy Harris Date: Tue Jun 4 18:13:21 2019 +0100 Use dsn_from for success-DSN messages. Bug 2404 (cherry picked from commit 87abcb247b4444bab5fd0bcb212ddb26d5fd9191) (cherry picked from commit 454bab46ae6812e29652d10c390451c962a6f806) (cherry picked from commit 9eebb5a0ed51584c18af8b08a27695b806980775) diff --git a/src/src/deliver.c b/src/src/deliver.c index e1799411..4720f596 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -7365,8 +7365,8 @@ if (addr_senddsn) if (errors_reply_to) fprintf(f, "Reply-To: %s\n", errors_reply_to); + moan_write_from(f); fprintf(f, "Auto-Submitted: auto-generated\n" - "From: Mail Delivery System \n" "To: %s\n" "Subject: Delivery Status Notification\n" "Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n" @@ -7377,7 +7377,7 @@ if (addr_senddsn) "This message was created automatically by mail delivery software.\n" " ----- The following addresses had successful delivery notifications -----\n", - qualify_domain_sender, sender_address, bound, bound); + sender_address, bound, bound); for (addr_dsntmp = addr_senddsn; addr_dsntmp; addr_dsntmp = addr_dsntmp->next) commit d508b5ca595a418667a1ae10e6cadf48a901c6f3 Author: Jeremy Harris Date: Fri Jun 7 11:54:10 2019 +0100 Fix detection of 32b platform at build time. Bug 2405 (cherry picked from commit 26dd3aa007b3b77969610c031f59388e0953bd00) (cherry picked from commit da7f749864e0807f796b8fa19573484c92bdc5c2) (cherry picked from commit a8e52cc464c132b8c88718af4367a01538d65b5a) diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c index 3d404f10..ce01cfb4 100644 --- a/src/src/buildconfig.c +++ b/src/src/buildconfig.c @@ -111,6 +111,7 @@ unsigned long test_ulong_t = 0L; unsigned int test_uint_t = 0; #endif long test_long_t = 0; +long long test_longlong_t = 0; int test_int_t = 0; FILE *base; FILE *new; @@ -155,15 +156,16 @@ This assumption is known to be OK for the common operating systems. */ fprintf(new, "#ifndef OFF_T_FMT\n"); if (sizeof(test_off_t) > sizeof(test_long_t)) - { fprintf(new, "# define OFF_T_FMT \"%%lld\"\n"); - fprintf(new, "# define LONGLONG_T long long int\n"); - } else - { fprintf(new, "# define OFF_T_FMT \"%%ld\"\n"); +fprintf(new, "#endif\n\n"); + +fprintf(new, "#ifndef LONGLONG_T\n"); +if (sizeof(test_longlong_t) > sizeof(test_long_t)) + fprintf(new, "# define LONGLONG_T long long int\n"); +else fprintf(new, "# define LONGLONG_T long int\n"); - } fprintf(new, "#endif\n\n"); /* Now do the same thing for time_t variables. If the length is greater than commit 250dc372cfb64dfb21db2e7bd67ed28822aa132d Author: Phil Pennock Date: Wed Jun 5 05:35:28 2019 -0400 Unbreak heimdal_gssapi auth driver Commit 251b9eb46 broke heimdal_gssapi by changing the function definition in the `.c` without changing the declaration in the `.h`. Was part of 4.92. Make corresponding `.h` change to reflect newer internal API. (cherry picked from commit 6ee110613402e8562c03b4a11c3ffbdbd47bd153) (cherry picked from commit 40fe3ea73eb7524a6143755854633ed8392d39b4) (cherry picked from commit 171adf11d72efb4781a3028a849e0ed6e521a4fa) diff --git a/src/src/auths/heimdal_gssapi.h b/src/src/auths/heimdal_gssapi.h index a606a5c2..b682b5ff 100644 --- a/src/src/auths/heimdal_gssapi.h +++ b/src/src/auths/heimdal_gssapi.h @@ -32,8 +32,7 @@ extern auth_heimdal_gssapi_options_block auth_heimdal_gssapi_option_defaults; extern void auth_heimdal_gssapi_init(auth_instance *); extern int auth_heimdal_gssapi_server(auth_instance *, uschar *); -extern int auth_heimdal_gssapi_client(auth_instance *, smtp_inblock *, - smtp_outblock *, int, uschar *, int); +extern int auth_heimdal_gssapi_client(auth_instance *, void *, int, uschar *, int); extern void auth_heimdal_gssapi_version_report(FILE *f); /* End of heimdal_gssapi.h */ commit f41bc530a8b1a66e811e5c3b4da3df72ecba0e1d Author: Jeremy Harris Date: Wed Jun 26 11:17:52 2019 +0100 Fix DSN Final-Recipient: field (cherry picked from commits 436bda2ac0c4 and 98d4eb7a84) (cherry picked from commit 6b88f51ac13b4fa834796ce12d12c55c95eacc4a) (cherry picked from commit ce4d8eca9d3940bb439cdb74a250090fee5538d4) diff --git a/src/src/deliver.c b/src/src/deliver.c index 4720f596..53562dd5 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -5507,6 +5507,25 @@ while ((addr = *anchor)) +/************************************************/ + +static void +print_dsn_addr_action(FILE * f, address_item * addr, + uschar * action, uschar * status) +{ +address_item * pa; + +if (addr->dsn_orcpt) + fprintf(f,"Original-Recipient: %s\n", addr->dsn_orcpt); + +for (pa = addr; pa->parent; ) pa = pa->parent; +fprintf(f, "Action: %s\n" + "Final-Recipient: rfc822;%s\n" + "Status: %s\n", + action, pa->address, status); +} + + /************************************************* * Deliver one message * *************************************************/ @@ -7410,10 +7429,7 @@ if (addr_senddsn) if (addr_dsntmp->dsn_orcpt) fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt); - fprintf(f, "Action: delivered\n" - "Final-Recipient: rfc822;%s\n" - "Status: 2.0.0\n", - addr_dsntmp->address); + print_dsn_addr_action(f, addr_dsntmp, US"delivered", US"2.0.0"); if (addr_dsntmp->host_used && addr_dsntmp->host_used->name) fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n", @@ -7798,10 +7814,9 @@ wording. */ for (addr = handled_addr; addr; addr = addr->next) { host_item * hu; - fprintf(fp, "Action: failed\n" - "Final-Recipient: rfc822;%s\n" - "Status: 5.0.0\n", - addr->address); + + print_dsn_addr_action(fp, addr, US"failed", US"5.0.0"); + if ((hu = addr->host_used) && hu->name) { fprintf(fp, "Remote-MTA: dns; %s\n", hu->name); @@ -8343,13 +8358,9 @@ else if (addr_defer != (address_item *)(+1)) for ( ; addr_dsndefer; addr_dsndefer = addr_dsndefer->next) { - if (addr_dsndefer->dsn_orcpt) - fprintf(f, "Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt); - fprintf(f, "Action: delayed\n" - "Final-Recipient: rfc822;%s\n" - "Status: 4.0.0\n", - addr_dsndefer->address); + print_dsn_addr_action(f, addr_dsndefer, US"delayed", US"4.0.0"); + if (addr_dsndefer->host_used && addr_dsndefer->host_used->name) { fprintf(f, "Remote-MTA: dns; %s\n", commit ee2d305425037fc3bc00e6e44e990a88a92433ab Author: Jeremy Harris Date: Sat Jun 29 19:37:57 2019 +0100 Fix bounce generation under RFC 3461 request. Bug 2411 Broken-by: ea97267cea (cherry picked from commit df98a6ff2e70887890690ffbf8a8ad583d7d7e38) (cherry picked from commit b4a37a77271a8f6efc887d68265eb7867eff6170) (cherry picked from commit 145416c70b2e4422f0ff03f402da33a4a4db29e2) diff --git a/src/src/deliver.c b/src/src/deliver.c index 53562dd5..d4ed8af0 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -7519,7 +7519,8 @@ while (addr_failed) mark the recipient done. */ if ( addr_failed->prop.ignore_error - || addr_failed->dsn_flags & (rf_dsnflags & ~rf_notify_failure) + || addr_failed->dsn_flags & rf_dsnflags + && !(addr_failed->dsn_flags & rf_notify_failure) ) { addr = addr_failed; commit c8535a954a3ec877083b39088f385ed3174abab7 Author: Jeremy Harris Date: Sun Jul 28 14:47:29 2019 +0100 Fix crash after TLS channel shutdown (cherry picked from commit bd231acd0f24e4c27c6d6885f48c24360700ec7f) (cherry picked from commit 513adf9d59bd8d9515a3c6b9c092a2c376cc6102) diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 867dbbe3..8d911d57 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2569,8 +2569,9 @@ void tls_close(void * ct_ctx, int shutdown) { exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server; +tls_support * tlsp = state->tlsp; -if (!state->tlsp || state->tlsp->active.sock < 0) return; /* TLS was not active */ +if (!tlsp || tlsp->active.sock < 0) return; /* TLS was not active */ if (shutdown) { @@ -2582,12 +2583,26 @@ if (shutdown) ALARM_CLR(0); } +if (!ct_ctx) /* server */ + { + receive_getc = smtp_getc; + receive_getbuf = smtp_getbuf; + 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); +tlsp->active.sock = -1; +tlsp->active.tls_ctx = NULL; +/* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */ +tls_channelbinding_b64 = NULL; + -state->tlsp->active.sock = -1; -state->tlsp->active.tls_ctx = NULL; if (state->xfer_buffer) store_free(state->xfer_buffer); memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init)); } @@ -2637,28 +2652,7 @@ if (sigalrm_seen) else if (inbytes == 0) { DEBUG(D_tls) debug_printf("Got TLS_EOF\n"); - - receive_getc = smtp_getc; - receive_getbuf = smtp_getbuf; - 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.sock = -1; - state->tlsp->active.tls_ctx = NULL; - state->tlsp->bits = 0; - state->tlsp->certificate_verified = FALSE; - tls_channelbinding_b64 = NULL; - state->tlsp->cipher = NULL; - state->tlsp->peercert = NULL; - state->tlsp->peerdn = NULL; - + tls_close(NULL, TLS_NO_SHUTDOWN); return FALSE; } diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index cc0ead02..e751edd9 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -2727,32 +2727,10 @@ switch(error) case SSL_ERROR_ZERO_RETURN: DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); - receive_getc = smtp_getc; - receive_getbuf = smtp_getbuf; - receive_get_cache = smtp_get_cache; - receive_ungetc = smtp_ungetc; - receive_feof = smtp_feof; - receive_ferror = smtp_ferror; - receive_smtp_buffered = smtp_buffered; - if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN) SSL_shutdown(server_ssl); -#ifndef DISABLE_OCSP - sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free); - server_static_cbinfo->verify_stack = NULL; -#endif - SSL_free(server_ssl); - SSL_CTX_free(server_ctx); - server_ctx = NULL; - server_ssl = NULL; - tls_in.active.sock = -1; - tls_in.active.tls_ctx = NULL; - tls_in.bits = 0; - tls_in.cipher = NULL; - tls_in.peerdn = NULL; - tls_in.sni = NULL; - + tls_close(NULL, TLS_NO_SHUTDOWN); return FALSE; /* Handle genuine errors */ @@ -3040,14 +3018,25 @@ if (shutdown) } } -#ifndef DISABLE_OCSP if (!o_ctx) /* server side */ { +#ifndef DISABLE_OCSP sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free); server_static_cbinfo->verify_stack = NULL; - } #endif + receive_getc = smtp_getc; + receive_getbuf = smtp_getbuf; + receive_get_cache = smtp_get_cache; + receive_ungetc = smtp_ungetc; + receive_feof = smtp_feof; + receive_ferror = smtp_ferror; + receive_smtp_buffered = smtp_buffered; + tls_in.active.tls_ctx = NULL; + tls_in.sni = NULL; + /* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */ + } + SSL_CTX_free(*ctxp); SSL_free(*sslp); *ctxp = NULL; commit 2ac2eff3c9914a9c77b03db64b31819f361576b9 Author: Bruce Lee Date: Tue Jul 30 22:43:14 2019 +0100 Auth: handle socket read errors in Dovecot authenticator (cherry picked from commit c9f1be94cc304f0343c93b66efa41a747d307fb1) (cherry picked from commit 4ba26a040b8765dea7134c883d046418a8b053a1) diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c index b1dde06a..b1c2c6f8 100644 --- a/src/src/auths/dovecot.c +++ b/src/src/auths/dovecot.c @@ -212,8 +212,8 @@ for (;;) { if (socket_buffer_left == 0) { - socket_buffer_left = read(fd, sbuffer, sizeof(sbuffer)); - if (socket_buffer_left == 0) { if (count == 0) return NULL; else break; } + if ((socket_buffer_left = read(fd, sbuffer, sizeof(sbuffer))) <= 0) + if (count == 0) return NULL; else break; p = 0; } commit deda0b271ccd27ae76bd69ad1c1d0ef73e20091d Author: Jeremy Harris Date: Tue Aug 27 17:44:52 2019 +0100 Fix ${domain:} for a bare local-part input. Bug 2375 Broken-by: cebd5bd2ab (cherry picked from commit c5b0340697326238b0e2afd9d341185077d60d35) (cherry picked from commit 92b922fae5bbd5a70da4c5aa2f43a457842c30eb) diff --git a/src/src/expand.c b/src/src/expand.c index fbb2dfb1..0a8c5fbc 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -7151,11 +7151,12 @@ while (*s != 0) uschar * t = parse_extract_address(sub, &error, &start, &end, &domain, FALSE); if (t) - yield = c == EOP_DOMAIN - ? string_cat(yield, t + domain) - : c == EOP_LOCAL_PART && domain > 0 - ? string_catn(yield, t, domain - 1 ) - : string_cat(yield, t); + if (c != EOP_DOMAIN) + yield = c == EOP_LOCAL_PART && domain > 0 + ? string_catn(yield, t, domain - 1) + : string_cat(yield, t); + else if (domain > 0) + yield = string_cat(yield, t + domain); continue; } commit 66935633816a88460f5222f40dc29d1a4e877978 Author: Heiko Schlittermann (HS12-RIPE) Date: Thu Sep 5 14:56:22 2019 +0200 exim_dbmbuild: handle { '\\', '\0' } sequence. This fix matches the change introduced for CVE-2019-15846, but isn't considered as a security issue, exim_dbmbuild is not designed to to run on untrusted data. Thanks to Thomas Hoger (RedHat) for pointing out. diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index afd5095d..d7e611ab 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -94,6 +94,7 @@ string_interpret_escape(const uschar **pp) int ch; const uschar *p = *pp; ch = *(++p); +if (ch == '\0') return *pp; if (isdigit(ch) && ch != '8' && ch != '9') { ch -= '0'; commit cdc7f9a9667ecf31d803fc8d1a31b466284360bd Author: Heiko Schlittermann (HS12-RIPE) Date: Fri Sep 6 06:57:11 2019 +0200 fixup! exim_dbmbuild: handle { '\\', '\0' } sequence. Credits to Qualys for double checking and reporting. diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index d7e611ab..63fd691a 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -94,7 +94,7 @@ string_interpret_escape(const uschar **pp) int ch; const uschar *p = *pp; ch = *(++p); -if (ch == '\0') return *pp; +if (ch == '\0') return **pp; if (isdigit(ch) && ch != '8' && ch != '9') { ch -= '0'; commit 478effbfd9c3cc5a627fc671d4bf94d13670d65f Author: Jeremy Harris Date: Fri Sep 27 12:21:49 2019 +0100 Fix buffer overflow in string_vformat. Bug 2449 diff --git a/src/src/string.c b/src/src/string.c index c6549bf9..3445f8a4 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1132,7 +1132,7 @@ store_reset(g->s + (g->size = g->ptr + 1)); Arguments: g the growable-string p current end of data - count amount to grow by + count amount to grow by, offset from p */ static void @@ -1590,7 +1590,7 @@ while (*fp) } else if (g->ptr >= lim - width) { - gstring_grow(g, g->ptr, width - (lim - g->ptr)); + gstring_grow(g, g->ptr, width); lim = g->size - 1; gp = CS g->s + g->ptr; }