diff -urN ../exim-4.94.orig/OS/os.h-GNU ./OS/os.h-GNU --- ../exim-4.94.orig/OS/os.h-GNU 2020-05-30 23:35:38.000000000 +0300 +++ ./OS/os.h-GNU 2021-03-17 20:09:01.095144000 +0200 @@ -1,6 +1,8 @@ /* Exim: OS-specific C header file for GNU/Hurd */ /* Copyright (c) The Exim Maintainers 2020 */ +#include + #define CRYPT_H #define GLIBC_IP_OPTIONS #define HAVE_BSD_GETLOADAVG @@ -24,5 +26,9 @@ /* setgroups(0, NULL) succeeds, and drops the gid group as well as any supplementary groups*/ #define OS_SETGROUPS_ZERO_DROPS_ALL + +#if _POSIX_C_SOURCE >= 200809L || _ATFILE_SOURCE +# define EXIM_HAVE_OPENAT +#endif /* End */ diff -urN ../exim-4.94.orig/doc/ChangeLog ./doc/ChangeLog --- ../exim-4.94.orig/doc/ChangeLog 2020-05-30 23:35:38.000000000 +0300 +++ ./doc/ChangeLog 2021-03-17 20:09:33.450324000 +0200 @@ -207,6 +207,43 @@ doesn't work. (Additionally add a new main config option to configure the spf_smtp_comment) +JH/30 Bug 2677: fix matching of long addresses. Since 4.93 a limit of 256 was + applied. This resulted, if any header-line rewrite rules were configured, + in a panic-log trigerrable by sending a message with a long address in + a header. Fix by increaing the arbitrary limit to larger than a single + (dewrapped) 5322 header line maximum size. + +JH/31 The ESMTP option name advertised for the SUPPORT_EARLY_PIPE build option + is changed from X_PIPE_CONNECT to PIPE_CONNECT. This is in line with + RFC 6648 which deprecates X- options in protocols as a general practice. + Changeover between the implementations is handled by the mechanisms + alrready coded. + +JH/32 Bug 2599: fix delay of delivery to a local address where there is also + a remote which uses callout/hold. Previously the local was queued. + +JH/33 Fix a taint trap in the ${listextract } expansion when the source data + was tainted. + +JH/35 Bug 2343: Harden exim_tidydb against corrupt wait- files. + +JH/39 Bug 2691: fix $local_part_data. When the matching list element + referred to a file, bad data was returned. This likely also affected + $domain_part_data. + +JH/41 Fix daemon SIGHUP on FreeBSD. Previously, a named socket for IPC was + left undeleted; the attempt to re-create it then failed - resulting in + the usual "SIGHUP tp have daemon reload configuration" to not work. + This affected any platform not supporting "abstract" Unix-domain + sockets (i.e. not Linux). + +JH/42 Bug 2692: Harden against a peer which reneges on a 452 "too many + recipients" response to RCPT in a later response, with a 250. The + previous coding assumed this would not happen, and under PIPELINING + would result in both lost and duplicate recipients for a message. + + + Exim version 4.93 ----------------- diff -urN ../exim-4.94.orig/doc/spec.txt ./doc/spec.txt --- ../exim-4.94.orig/doc/spec.txt 2020-06-01 17:32:47.000000000 +0300 +++ ./doc/spec.txt 2021-03-17 20:09:16.196974000 +0200 @@ -3690,7 +3690,7 @@ message is active (in the middle of a delivery attempt), it is not altered. This option can be used only by an admin user. --MC +-MC This option is not intended for use by external callers. It is used internally by Exim to invoke another instance of itself to deliver a @@ -15399,7 +15399,7 @@ See also the hosts_pipe_connect smtp transport option. -Currently the option name "X_PIPE_CONNECT" is used. +The SMTP service extension keyword advertised is "PIPE_CONNECT". +--------------------------------------------------+ |prdr_enable|Use: main|Type: boolean|Default: false| @@ -25710,8 +25710,11 @@ client_send = ^username^mysecret The lack of colons means that the entire text is sent with the AUTH command, -with the circumflex characters converted to NULs. A similar example that uses -the LOGIN mechanism is: +with the circumflex characters converted to NULs. +Note that due to the ambiguity of parsing three consectutive circumflex +characters there is no way to provide a password having a leading circumflex. + +A similar example that uses the LOGIN mechanism is: fixed_login: driver = plaintext diff -urN ../exim-4.94.orig/src/EDITME ./src/EDITME --- ../exim-4.94.orig/src/EDITME 2020-05-30 23:35:38.000000000 +0300 +++ ./src/EDITME 2021-03-17 20:08:40.483704000 +0200 @@ -564,9 +564,9 @@ # DISABLE_EVENT=yes -# Uncomment this line to include support for early pipelining, per +# Uncomment this line to remove support for early pipelining, per # https://datatracker.ietf.org/doc/draft-harris-early-pipe/ -# SUPPORT_PIPE_CONNECT=yes +# DISABLE_PIPE_CONNECT=yes #------------------------------------------------------------------------------ diff -urN ../exim-4.94.orig/src/auths/get_data.c ./src/auths/get_data.c --- ../exim-4.94.orig/src/auths/get_data.c 2020-05-30 23:35:38.000000000 +0300 +++ ./src/auths/get_data.c 2021-03-17 20:09:16.181727000 +0200 @@ -168,14 +168,20 @@ len = Ustrlen(ss); /* The character ^ is used as an escape for a binary zero character, which is -needed for the PLAIN mechanism. It must be doubled if really needed. */ +needed for the PLAIN mechanism. It must be doubled if really needed. +The parsing ambiguity of ^^^ is taken as ^^ -> ^ ; ^ -> NUL - and there is +no way to get a leading ^ after a NUL. We would need to intro new syntax to +support that (probably preferring to take a more-standard exim list as a source +and concat the elements with intervening NULs. Either a magic marker on the +source string for client_send, or a new option). */ + for (int i = 0; i < len; i++) if (ss[i] == '^') if (ss[i+1] != '^') ss[i] = 0; else - if (--len > ++i) memmove(ss + i, ss + i + 1, len - i); + if (--len > i+1) memmove(ss + i + 1, ss + i + 2, len - i); /* The first string is attached to the AUTH command; others are sent unembellished. */ diff -urN ../exim-4.94.orig/src/daemon.c ./src/daemon.c --- ../exim-4.94.orig/src/daemon.c 2020-05-30 23:35:38.000000000 +0300 +++ ./src/daemon.c 2021-03-17 20:09:28.740515000 +0200 @@ -130,11 +130,30 @@ /************************************************* *************************************************/ +#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS static void +unlink_notifier_socket(void) +{ +uschar * s = expand_string(notifier_socket); +DEBUG(D_any) debug_printf("unlinking notifier socket %s\n", s); +Uunlink(s); +} +#endif + + +static void close_daemon_sockets(int daemon_notifier_fd, int * listen_sockets, int listen_socket_count) { -if (daemon_notifier_fd >= 0) (void) close(daemon_notifier_fd); +if (daemon_notifier_fd >= 0) + { + (void) close(daemon_notifier_fd); + daemon_notifier_fd = -1; +#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS + unlink_notifier_socket(); +#endif + } + for (int i = 0; i < listen_socket_count; i++) (void) close(listen_sockets[i]); } @@ -971,11 +990,7 @@ close(daemon_notifier_fd); daemon_notifier_fd = -1; #ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS - { - uschar * s = expand_string(notifier_socket); - DEBUG(D_any) debug_printf("unlinking notifier socket %s\n", s); - Uunlink(s); - } + unlink_notifier_socket(); #endif } diff -urN ../exim-4.94.orig/src/deliver.c ./src/deliver.c --- ../exim-4.94.orig/src/deliver.c 2020-05-30 23:35:38.000000000 +0300 +++ ./src/deliver.c 2021-03-17 20:08:45.916304000 +0200 @@ -7066,10 +7066,20 @@ /* If this is a run to continue deliveries to an external channel that is -already set up, defer any local deliveries. */ +already set up, defer any local deliveries. -if (continue_transport) +jgh 2020/12/20: I don't see why; locals should be quick. +The defer goes back to version 1.62 in 1997. A local being still deliverable +during a continued run might result from something like a defer during the +original delivery, eg. in a DB lookup. Unlikely but possible. + +To avoid delaying a local when combined with a callout-hold for a remote +delivery, test continue_sequence rather than continue_transport. */ + +if (continue_sequence > 1 && addr_local) { + DEBUG(D_deliver|D_retry|D_route) + debug_printf("deferring local deliveries due to continued-transport\n"); if (addr_defer) { address_item *addr = addr_defer; diff -urN ../exim-4.94.orig/src/exim_dbutil.c ./src/exim_dbutil.c --- ../exim-4.94.orig/src/exim_dbutil.c 2020-05-30 23:35:38.000000000 +0300 +++ ./src/exim_dbutil.c 2021-03-17 20:09:07.949069000 +0200 @@ -391,7 +391,7 @@ Arguments: dbblock a pointer to an open database block key the key of the record to be read - length where to put the length (or NULL if length not wanted) + length where to put the length (or NULL if length not wanted). Includes overhead. Returns: a pointer to the retrieved record, or NULL if the record is not found @@ -419,7 +419,7 @@ yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE); memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum)); -if (length != NULL) *length = EXIM_DATUM_SIZE(result_datum); +if (length) *length = EXIM_DATUM_SIZE(result_datum); EXIM_DATUM_FREE(result_datum); /* Some DBM libs require freeing */ return yield; @@ -620,6 +620,7 @@ t = wait->text; name[MESSAGE_ID_LENGTH] = 0; + /* Leave corrupt records alone */ if (wait->count > WAIT_NAME_MAX) { fprintf(stderr, @@ -1222,7 +1223,7 @@ /* A continuation record may have been deleted or renamed already, so non-existence is not serious. */ - if (value == NULL) continue; + if (!value) continue; /* Delete if too old */ @@ -1243,10 +1244,31 @@ /* Leave corrupt records alone */ + if (wait->time_stamp > time(NULL)) + { + printf("**** Data for '%s' corrupted\n time in future: %s\n", + key, print_time(((dbdata_generic *)value)->time_stamp)); + continue; + } if (wait->count > WAIT_NAME_MAX) { - printf("**** Data for %s corrupted\n count=%d=0x%x max=%d\n", + printf("**** Data for '%s' corrupted\n count=%d=0x%x max=%d\n", key, wait->count, wait->count, WAIT_NAME_MAX); + continue; + } + if (wait->sequence > WAIT_CONT_MAX) + { + printf("**** Data for '%s' corrupted\n sequence=%d=0x%x max=%d\n", + key, wait->sequence, wait->sequence, WAIT_CONT_MAX); + continue; + } + + /* Record over 1 year old; just remove it */ + + if (wait->time_stamp < time(NULL) - 365*24*60*60) + { + dbfn_delete(dbm, key); + printf("deleted %s (too old)\n", key); continue; } diff -urN ../exim-4.94.orig/src/expand.c ./src/expand.c --- ../exim-4.94.orig/src/expand.c 2020-05-30 23:35:38.000000000 +0300 +++ ./src/expand.c 2021-03-17 20:08:50.314516000 +0200 @@ -1298,15 +1298,16 @@ { const uschar * tlist = list; int sep = 0; -uschar dummy; +/* Tainted mem for the throwaway element copies */ +uschar * dummy = store_get(2, TRUE); if (field < 0) { - for (field++; string_nextinlist(&tlist, &sep, &dummy, 1); ) field++; + for (field++; string_nextinlist(&tlist, &sep, dummy, 1); ) field++; sep = 0; } if (field == 0) return NULL; -while (--field > 0 && (string_nextinlist(&list, &sep, &dummy, 1))) ; +while (--field > 0 && (string_nextinlist(&list, &sep, dummy, 1))) ; return string_nextinlist(&list, &sep, NULL, 0); } diff -urN ../exim-4.94.orig/src/macros.h ./src/macros.h --- ../exim-4.94.orig/src/macros.h 2020-05-30 23:35:38.000000000 +0300 +++ ./src/macros.h 2021-03-17 20:09:07.949688000 +0200 @@ -189,9 +189,10 @@ #define SPOOL_NAME_LENGTH (MESSAGE_ID_LENGTH+2) /* The maximum number of message ids to store in a waiting database -record. */ +record, and the max number of continuation records allowed. */ #define WAIT_NAME_MAX 50 +#define WAIT_CONT_MAX 1000 /* Wait this long before determining that a Proxy Protocol configured host isn't speaking the protocol, and so is disallowed. Can be moved to @@ -1067,8 +1068,8 @@ #define AUTHS_REGEX US"\\n250[\\s\\-]AUTH\\s+([\\-\\w \\t]+)(?:\\n|$)" -#define EARLY_PIPE_FEATURE_NAME "X_PIPE_CONNECT" -#define EARLY_PIPE_FEATURE_LEN 14 +#define EARLY_PIPE_FEATURE_NAME "PIPE_CONNECT" +#define EARLY_PIPE_FEATURE_LEN 12 /* Flags for auth_client_item() */ diff -urN ../exim-4.94.orig/src/match.c ./src/match.c --- ../exim-4.94.orig/src/match.c 2020-05-30 23:35:38.000000000 +0300 +++ ./src/match.c 2021-03-17 20:09:22.008424000 +0200 @@ -850,6 +850,11 @@ (void)fclose(f); HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\" in %s)\n", ot, yield == OK ? "yes" : "no", sss, filename); + + /* The "pattern" being matched came from the file; we use a stack-local. + Copy it to allocated memory now we know it matched. */ + + if (valueptr) *valueptr = string_copy(ss); return file_yield; case DEFER: @@ -1288,9 +1293,11 @@ provided that "caseless" is set. (It is FALSE for calls for matching rewriting patterns.) Otherwise just the domain is lower cases. A magic item "+caseful" in the list can be used to restore a caseful copy of the local part from the -original address. */ +original address. +Limit the subject address size to avoid mem-exhastion attacks. The size chosen +is historical (we used to use big_buffer her). */ -if ((len = Ustrlen(address)) > 255) len = 255; +if ((len = Ustrlen(address)) > BIG_BUFFER_SIZE) len = BIG_BUFFER_SIZE; ab.address = string_copyn(address, len); for (uschar * p = ab.address + len - 1; p >= ab.address; p--) diff -urN ../exim-4.94.orig/src/pdkim/pdkim.c ./src/pdkim/pdkim.c --- ../exim-4.94.orig/src/pdkim/pdkim.c 2020-05-30 23:35:38.000000000 +0300 +++ ./src/pdkim/pdkim.c 2021-03-17 20:08:56.916823000 +0200 @@ -1352,7 +1352,8 @@ int excess = p->key.len - 32; if (excess > 0) { - DEBUG(D_acl) debug_printf("DKIM: unexpected pubkey len %lu\n", p->key.len); + DEBUG(D_acl) + debug_printf("DKIM: unexpected pubkey len %lu\n", (unsigned long) p->key.len); p->key.data += excess; p->key.len = 32; } } diff -urN ../exim-4.94.orig/src/transports/smtp.c ./src/transports/smtp.c --- ../exim-4.94.orig/src/transports/smtp.c 2020-05-30 23:35:38.000000000 +0300 +++ ./src/transports/smtp.c 2021-03-17 20:09:33.451790000 +0200 @@ -1087,7 +1087,7 @@ { DEBUG(D_transport) debug_printf("%s expect mail\n", __FUNCTION__); count--; - sx->pending_MAIL = FALSE; + sx->pending_MAIL = sx->RCPT_452 = FALSE; if (!smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', ob->command_timeout)) { @@ -1227,7 +1227,7 @@ if (addr->more_errno >> 8 == 52 && yield & 3) { - if (!sx->RCPT_452) + if (!sx->RCPT_452) /* initialised at MAIL-ack above */ { DEBUG(D_transport) debug_printf("%s: seen first 452 too-many-rcpts\n", __FUNCTION__); @@ -1274,6 +1274,8 @@ } } } + if (count && !(addr = addr->next)) + return -2; } /* Loop for next RCPT response */ /* Update where to start at for the next block of responses, unless we @@ -3819,9 +3821,10 @@ } /* Process all transported addresses - for LMTP or PRDR, read a status for - each one. */ + each one. We used to drop out at first_addr, until someone returned a 452 + followed by a 250... and we screwed up the accepted addresses. */ - for (address_item * addr = addrlist; addr != sx->first_addr; addr = addr->next) + for (address_item * addr = addrlist; addr; addr = addr->next) { if (addr->transport_return != PENDING_OK) continue;