diff -urN ../exim-4.93.0.4.orig/exim_monitor/em_version.c ./exim_monitor/em_version.c --- ../exim-4.93.0.4.orig/exim_monitor/em_version.c 2020-01-03 14:08:52.000000000 +0200 +++ ./exim_monitor/em_version.c 2020-08-25 15:32:22.715961000 +0300 @@ -5,6 +5,8 @@ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +#define EM_VERSION_C + #include "mytypes.h" #include "store.h" #include "macros.h" diff -urN ../exim-4.93.0.4.orig/OS/Makefile-Base ./OS/Makefile-Base --- ../exim-4.93.0.4.orig/OS/Makefile-Base 2020-01-03 14:08:52.000000000 +0200 +++ ./OS/Makefile-Base 2020-08-25 15:32:22.708514000 +0300 @@ -659,11 +659,14 @@ .c.o:; @echo "$(CC) $*.c" $(FE)$(CC) -c $(CFLAGS) -I. $(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE) $*.c -# Update Exim's version information and build the version object. +# Update Exim's version information and build the version object. The dependency +# chain here avoids problems under parallel-make. -version.h version.sh:: +version.sh: @../scripts/reversion +version.h: version.sh + cnumber.h: version.h version.o: $(HDRS) cnumber.h version.h version.c diff -urN ../exim-4.93.0.4.orig/src/acl.c ./src/acl.c --- ../exim-4.93.0.4.orig/src/acl.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/acl.c 2020-08-25 15:32:22.718969000 +0300 @@ -2259,7 +2259,7 @@ /* Parse the other options. */ -while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size))) +while ((ss = string_nextinlist(&arg, &sep, NULL, 0))) { if (strcmpic(ss, US"leaky") == 0) leaky = TRUE; else if (strcmpic(ss, US"strict") == 0) strict = TRUE; diff -urN ../exim-4.93.0.4.orig/src/arc.c ./src/arc.c --- ../exim-4.93.0.4.orig/src/arc.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/arc.c 2020-08-25 15:32:22.719410000 +0300 @@ -735,7 +735,7 @@ /* Setup the interface to the signing library */ -if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx))) +if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx, NULL))) { DEBUG(D_acl) debug_printf("ARC verify init: %s\n", errstr); as->ams_verify_done = arc_state_reason = US"internal sigverify init error"; @@ -964,7 +964,7 @@ /* We know the b-tag blob is of a nul-term string, so safe as a string */ pdkim_decode_base64(hdr_as->b.data, &sighash); -if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx))) +if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx, NULL))) { DEBUG(D_acl) debug_printf("ARC verify init: %s\n", errstr); return US"fail"; diff -urN ../exim-4.93.0.4.orig/src/auths/call_radius.c ./src/auths/call_radius.c --- ../exim-4.93.0.4.orig/src/auths/call_radius.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/auths/call_radius.c 2020-08-25 15:32:22.720214000 +0300 @@ -2,6 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 */ /* Copyright (c) University of Cambridge 1995 - 2016 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -115,34 +116,34 @@ *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE); else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0) - *errptr = string_sprintf("RADIUS: can't read dictionary"); + *errptr = US"RADIUS: can't read dictionary"; -else if (rc_avpair_add(&send, PW_USER_NAME, user, 0) == NULL) - *errptr = string_sprintf("RADIUS: add user name failed\n"); +else if (!rc_avpair_add(&send, PW_USER_NAME, user, 0)) + *errptr = US"RADIUS: add user name failed"; -else if (rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0) == NULL) - *errptr = string_sprintf("RADIUS: add password failed\n"); +else if (!rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0)) + *errptr = US"RADIUS: add password failed"); -else if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0) == NULL) - *errptr = string_sprintf("RADIUS: add service type failed\n"); +else if (!rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0)) + *errptr = US"RADIUS: add service type failed"; #else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */ -if ((h = rc_read_config(RADIUS_CONFIG_FILE)) == NULL) +if (!(h = rc_read_config(RADIUS_CONFIG_FILE))) *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE); else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0) - *errptr = string_sprintf("RADIUS: can't read dictionary"); + *errptr = US"RADIUS: can't read dictionary"; -else if (rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0) == NULL) - *errptr = string_sprintf("RADIUS: add user name failed\n"); +else if (!rc_avpair_add(h, &send, PW_USER_NAME, user, Ustrlen(user), 0)) + *errptr = US"RADIUS: add user name failed"; -else if (rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args, - Ustrlen(radius_args), 0) == NULL) - *errptr = string_sprintf("RADIUS: add password failed\n"); +else if (!rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args, + Ustrlen(radius_args), 0)) + *errptr = US"RADIUS: add password failed"; -else if (rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0) == NULL) - *errptr = string_sprintf("RADIUS: add service type failed\n"); +else if (!rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0)) + *errptr = US"RADIUS: add service type failed"; #endif /* RADIUS_LIB_RADIUSCLIENT */ diff -urN ../exim-4.93.0.4.orig/src/auths/cyrus_sasl.c ./src/auths/cyrus_sasl.c --- ../exim-4.93.0.4.orig/src/auths/cyrus_sasl.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/auths/cyrus_sasl.c 2020-08-25 15:32:22.720647000 +0300 @@ -347,10 +347,10 @@ } else { - /* make sure that we have a null-terminated string */ - out2 = string_copyn(output, outlen); + /* auth_get_data() takes a length-specfied block of binary + which can include zeroes; no terminating NUL is needed */ - if ((rc = auth_get_data(&input, out2, outlen)) != OK) + if ((rc = auth_get_data(&input, output, outlen)) != OK) { /* we couldn't get the data, so free up the library before * returning whatever error we get */ diff -urN ../exim-4.93.0.4.orig/src/auths/heimdal_gssapi.c ./src/auths/heimdal_gssapi.c --- ../exim-4.93.0.4.orig/src/auths/heimdal_gssapi.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/auths/heimdal_gssapi.c 2020-08-25 15:32:22.721746000 +0300 @@ -200,16 +200,6 @@ krb5_free_context(context); -/* RFC 4121 section 5.2, SHOULD support 64K input buffers */ -if (big_buffer_size < (64 * 1024)) - { - uschar *newbuf; - big_buffer_size = 64 * 1024; - newbuf = store_malloc(big_buffer_size); - store_free(big_buffer); - big_buffer = newbuf; - } - ablock->server = TRUE; } diff -urN ../exim-4.93.0.4.orig/src/auths/README ./src/auths/README --- ../exim-4.93.0.4.orig/src/auths/README 2020-01-03 14:08:52.000000000 +0200 +++ ./src/auths/README 2020-08-25 15:32:22.719579000 +0300 @@ -34,7 +34,7 @@ the server and/or client functions are available for this authenticator. Typically this depends on whether server or client configuration options have been set, but it is also possible to have an authenticator that has only one of -the server or client functions. +the server or client functions. The function may not touch big_buffer. SERVER AUTHENTICATION diff -urN ../exim-4.93.0.4.orig/src/auths/spa.c ./src/auths/spa.c --- ../exim-4.93.0.4.orig/src/auths/spa.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/auths/spa.c 2020-08-25 15:32:22.722256000 +0300 @@ -139,7 +139,8 @@ SPAAuthResponse response; SPAAuthResponse *responseptr = &response; uschar msgbuf[2048]; -uschar *clearpass; +uschar *clearpass, *s; +unsigned off; /* send a 334, MS Exchange style, and grab the client's request, unless we already have it via an initial response. */ @@ -194,9 +195,19 @@ { int i; - char *p = ((char*)responseptr) + IVAL(&responseptr->uUser.offset,0); + char * p; int len = SVAL(&responseptr->uUser.len,0)/2; + if ( (off = IVAL(&responseptr->uUser.offset,0)) >= sizeof(SPAAuthResponse) + || len >= sizeof(responseptr->buffer)/2 + || (p = (CS responseptr) + off) + len*2 >= CS (responseptr+1) + ) + { + DEBUG(D_auth) + debug_printf("auth_spa_server(): bad uUser spec in response\n"); + return FAIL; + } + if (len + 1 >= sizeof(msgbuf)) return FAIL; for (i = 0; i < len; ++i) { @@ -245,13 +256,17 @@ /* compare NT hash (LM may not be available) */ -if (memcmp(ntRespData, - ((unsigned char*)responseptr)+IVAL(&responseptr->ntResponse.offset,0), - 24) == 0) - /* success. we have a winner. */ +off = IVAL(&responseptr->ntResponse.offset,0); +if (off >= sizeof(SPAAuthResponse) - 24) { - return auth_check_serv_cond(ablock); + DEBUG(D_auth) + debug_printf("auth_spa_server(): bad ntRespData spec in response\n"); + return FAIL; } +s = (US responseptr) + off; + +if (memcmp(ntRespData, s, 24) == 0) + return auth_check_serv_cond(ablock); /* success. we have a winner. */ /* Expand server_condition as an authorization check (PH) */ diff -urN ../exim-4.93.0.4.orig/src/deliver.c ./src/deliver.c --- ../exim-4.93.0.4.orig/src/deliver.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/deliver.c 2020-08-25 15:32:22.729182000 +0300 @@ -5379,7 +5379,8 @@ static void print_dsn_diagnostic_code(const address_item *addr, FILE *f) { -uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL; +uschar * s = testflag(addr, af_pass_message) ? addr->message : NULL; +unsigned cnt; /* af_pass_message and addr->message set ? print remote host answer */ if (s) @@ -5391,19 +5392,32 @@ if (!(s = Ustrstr(addr->message, ": "))) return; /* not found, bail out */ s += 2; /* skip ": " */ - fprintf(f, "Diagnostic-Code: smtp; "); + cnt = fprintf(f, "Diagnostic-Code: smtp; "); } /* no message available. do nothing */ else return; while (*s) + { + if (cnt > 950) /* RFC line length limit: 998 */ + { + DEBUG(D_deliver) debug_printf("print_dsn_diagnostic_code() truncated line\n"); + fputs("[truncated]", f); + break; + } + if (*s == '\\' && s[1] == 'n') { fputs("\n ", f); /* as defined in RFC 3461 */ s += 2; + cnt += 2; } else + { fputc(*s++, f); + cnt++; + } + } fputc('\n', f); } @@ -7809,11 +7823,11 @@ fprintf(fp, "Remote-MTA: X-ip; [%s]%s\n", hu->address, p); } if ((s = addr->smtp_greeting) && *s) - fprintf(fp, "X-Remote-MTA-smtp-greeting: X-str; %s\n", s); + fprintf(fp, "X-Remote-MTA-smtp-greeting: X-str; %.900s\n", s); if ((s = addr->helo_response) && *s) - fprintf(fp, "X-Remote-MTA-helo-response: X-str; %s\n", s); + fprintf(fp, "X-Remote-MTA-helo-response: X-str; %.900s\n", s); if ((s = addr->message) && *s) - fprintf(fp, "X-Exim-Diagnostic: X-str; %s\n", s); + fprintf(fp, "X-Exim-Diagnostic: X-str; %.900s\n", s); } #endif print_dsn_diagnostic_code(addr, fp); diff -urN ../exim-4.93.0.4.orig/src/dkim.c ./src/dkim.c --- ../exim-4.93.0.4.orig/src/dkim.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/dkim.c 2020-08-25 15:32:22.729491000 +0300 @@ -401,7 +401,7 @@ dkim_cur_sig = sig; dkim_signing_domain = US sig->domain; dkim_signing_selector = US sig->selector; - dkim_key_length = sig->sighash.len * 8; + dkim_key_length = sig->keybits; /* These two return static strings, so we can compare the addr later to see if the ACL overwrote them. Check that when logging */ diff -urN ../exim-4.93.0.4.orig/src/drtables.c ./src/drtables.c --- ../exim-4.93.0.4.orig/src/drtables.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/drtables.c 2020-08-25 15:32:22.730532000 +0300 @@ -740,10 +740,11 @@ dl = dlopen(CS big_buffer, RTLD_NOW);// TJ was LAZY if (dl == NULL) { - fprintf(stderr, "Error loading %s: %s\n", name, dlerror()); - moduleerrors++; - log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, dlerror()); - continue; + errormessage = dlerror(); + fprintf(stderr, "Error loading %s: %s\n", name, errormessage); + log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, errormessage); + moduleerrors++; + continue; } /* FreeBSD nsdispatch() can trigger dlerror() errors about @@ -756,16 +757,16 @@ info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info"); if ((errormsg = dlerror()) != NULL) { fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg); + log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg); dlclose(dl); moduleerrors++; - log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg); continue; } if (info->magic != LOOKUP_MODULE_INFO_MAGIC) { fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name); + log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name); dlclose(dl); moduleerrors++; - log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name); continue; } diff -urN ../exim-4.93.0.4.orig/src/exim.c ./src/exim.c --- ../exim-4.93.0.4.orig/src/exim.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/exim.c 2020-08-25 15:32:22.732714000 +0300 @@ -2554,8 +2554,10 @@ #ifdef SUPPORT_I18N allow_utf8_domains = TRUE; #endif - sender_address = parse_extract_address(argrest, &errmess, - &dummy_start, &dummy_end, &sender_address_domain, TRUE); + if (!(sender_address = parse_extract_address(argrest, &errmess, + &dummy_start, &dummy_end, &sender_address_domain, TRUE))) + exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess); + sender_address = string_copy_taint(sender_address, TRUE); #ifdef SUPPORT_I18N message_smtputf8 = string_is_utf8(sender_address); @@ -2563,8 +2565,6 @@ #endif allow_domain_literals = FALSE; strip_trailing_dot = FALSE; - if (!sender_address) - exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess); } f.sender_address_forced = TRUE; } @@ -5021,6 +5021,8 @@ deliver_localpart_orig = NULL; deliver_domain_orig = NULL; callout_address = sending_ip_address = NULL; + deliver_localpart_data = deliver_domain_data = + recipient_data = sender_data = NULL; sender_rate = sender_rate_limit = sender_rate_period = NULL; } smtp_log_no_mail(); @@ -5681,6 +5683,8 @@ #endif callout_address = NULL; sending_ip_address = NULL; + deliver_localpart_data = deliver_domain_data = + recipient_data = sender_data = NULL; acl_var_m = NULL; for(int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; diff -urN ../exim-4.93.0.4.orig/src/expand.c ./src/expand.c --- ../exim-4.93.0.4.orig/src/expand.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/expand.c 2020-08-25 15:32:22.738127000 +0300 @@ -5029,7 +5029,7 @@ { client_conn_ctx cctx; int timeout = 5; - int save_ptr = yield->ptr; + int save_ptr = yield ? yield->ptr : 0; FILE * fp = NULL; uschar * arg; uschar * sub_arg[4]; @@ -5070,8 +5070,9 @@ uschar * item; int sep = 0; - item = string_nextinlist(&list, &sep, NULL, 0); - if ((timeout = readconf_readtime(item, 0, FALSE)) < 0) + if ( !(item = string_nextinlist(&list, &sep, NULL, 0)) + || !*item + || (timeout = readconf_readtime(item, 0, FALSE)) < 0) { expand_string_message = string_sprintf("bad time value %s", item); goto EXPAND_FAILED; @@ -5262,7 +5263,7 @@ if (sigalrm_seen) { - yield->ptr = save_ptr; + if (yield) yield->ptr = save_ptr; expand_string_message = US "socket read timed out"; goto SOCK_FAIL; } @@ -5429,7 +5430,7 @@ case EITEM_TR: { - int oldptr = yield->ptr; + int oldptr = yield ? yield->ptr : 0; int o2m; uschar *sub[3]; @@ -6170,7 +6171,7 @@ case EITEM_REDUCE: { int sep = 0; - int save_ptr = yield->ptr; + int save_ptr = yield ? yield->ptr : 0; uschar outsep[2] = { '\0', '\0' }; const uschar *list, *expr, *temp; uschar *save_iterate_item = iterate_item; @@ -6317,7 +6318,8 @@ item of the output list, add in a space if the new item begins with the separator character, or is an empty string. */ - if (yield->ptr != save_ptr && (temp[0] == *outsep || temp[0] == 0)) + if ( yield && yield->ptr != save_ptr + && (temp[0] == *outsep || temp[0] == 0)) yield = string_catn(yield, US" ", 1); /* Add the string in "temp" to the output list that we are building, @@ -6357,7 +6359,7 @@ the redundant final separator. Even though an empty item at the end of a list does not count, this is tidier. */ - else if (yield->ptr != save_ptr) yield->ptr--; + else if (yield && yield->ptr != save_ptr) yield->ptr--; /* Restore preserved $item */ @@ -7222,7 +7224,7 @@ { uschar outsep[2] = { ':', '\0' }; uschar *address, *error; - int save_ptr = yield->ptr; + int save_ptr = yield ? yield->ptr : 0; int start, end, domain; /* Not really used */ while (isspace(*sub)) sub++; @@ -7253,7 +7255,7 @@ if (address) { - if (yield->ptr != save_ptr && address[0] == *outsep) + if (yield && yield->ptr != save_ptr && address[0] == *outsep) yield = string_catn(yield, US" ", 1); for (;;) @@ -7282,7 +7284,7 @@ /* If we have generated anything, remove the redundant final separator. */ - if (yield->ptr != save_ptr) yield->ptr--; + if (yield && yield->ptr != save_ptr) yield->ptr--; f.parse_allow_group = FALSE; continue; } @@ -7421,10 +7423,10 @@ case EOP_FROM_UTF8: { - while (*sub != 0) + uschar * buff = store_get(4, is_tainted(sub)); + while (*sub) { int c; - uschar buff[4]; GETUTF8INC(c, sub); if (c > 255) c = '_'; buff[0] = c; @@ -7445,7 +7447,17 @@ int complete; uschar seq_buff[4]; /* accumulate utf-8 here */ - while (*sub != 0) + /* Manually track tainting, as we deal in individual chars below */ + + if (is_tainted(sub)) + if (yield->s && yield->ptr) + gstring_rebuffer(yield); + else + yield->s = store_get(yield->size = Ustrlen(sub), TRUE); + + /* Check the UTF-8, byte-by-byte */ + + while (*sub) { complete = 0; uschar c = *sub++; diff -urN ../exim-4.93.0.4.orig/src/functions.h ./src/functions.h --- ../exim-4.93.0.4.orig/src/functions.h 2020-01-03 14:08:52.000000000 +0200 +++ ./src/functions.h 2020-08-25 15:32:22.739216000 +0300 @@ -187,6 +187,7 @@ extern uschar *deliver_get_sender_address (uschar *id); extern void delivery_re_exec(int); +extern void die_tainted(const uschar *, const uschar *, int); extern BOOL directory_make(const uschar *, const uschar *, int, BOOL); #ifndef DISABLE_DKIM extern uschar *dkim_exim_query_dns_txt(const uschar *); @@ -602,6 +603,58 @@ extern ssize_t write_to_fd_buf(int, const uschar *, size_t); +/******************************************************************************/ +/* Predicate: if an address is in a tainted pool. +By extension, a variable pointing to this address is tainted. +*/ + +static inline BOOL +is_tainted(const void * p) +{ +#if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) || defined(EM_VERSION_C) +return FALSE; + +#else +extern BOOL is_tainted_fn(const void *); +return is_tainted_fn(p); +#endif +} + +/******************************************************************************/ +/* String functions */ +static inline uschar * __Ustrcat(uschar * dst, const uschar * src, const char * func, int line) +{ +#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) +if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrcat", CUS func, line); +#endif +return US strcat(CS dst, CCS src); +} +static inline uschar * __Ustrcpy(uschar * dst, const uschar * src, const char * func, int line) +{ +#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) +if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrcpy", CUS func, line); +#endif +return US strcpy(CS dst, CCS src); +} +static inline uschar * __Ustrncat(uschar * dst, const uschar * src, size_t n, const char * func, int line) +{ +#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) +if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrncat", CUS func, line); +#endif +return US strncat(CS dst, CCS src, n); +} +static inline uschar * __Ustrncpy(uschar * dst, const uschar * src, size_t n, const char * func, int line) +{ +#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) +if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrncpy", CUS func, line); +#endif +return US strncpy(CS dst, CCS src, n); +} +/*XXX will likely need unchecked copy also */ + + +/******************************************************************************/ + #if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY) /* exim_chown - in some NFSv4 setups *seemes* to be an issue with chown(, ). @@ -634,8 +687,8 @@ return chown(CCS name, owner, group) ? exim_chown_failure(-1, name, owner, group) : 0; } - #endif /* !MACRO_PREDEF && !COMPILE_UTILITY */ + /******************************************************************************/ /* String functions */ @@ -849,6 +902,18 @@ return g; } + +/* Copy the content of a string to tainted memory */ + +static inline void +gstring_rebuffer(gstring * g) +{ +uschar * s = store_get(g->size, TRUE); +memcpy(s, g->s, g->ptr); +g->s = s; +} + + /******************************************************************************/ #define store_get_dns_answer() store_get_dns_answer_trc(CUS __FUNCTION__, __LINE__) diff -urN ../exim-4.93.0.4.orig/src/globals.c ./src/globals.c --- ../exim-4.93.0.4.orig/src/globals.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/globals.c 2020-08-25 15:32:22.739842000 +0300 @@ -311,6 +311,7 @@ .synchronous_delivery = FALSE, .system_filtering = FALSE, + .taint_check_slow = FALSE, .tcp_fastopen_ok = FALSE, .tcp_in_fastopen = FALSE, .tcp_in_fastopen_data = FALSE, diff -urN ../exim-4.93.0.4.orig/src/globals.h ./src/globals.h --- ../exim-4.93.0.4.orig/src/globals.h 2020-01-03 14:08:52.000000000 +0200 +++ ./src/globals.h 2020-08-25 15:32:22.740324000 +0300 @@ -272,6 +272,7 @@ BOOL synchronous_delivery :1; /* TRUE if -odi is set */ BOOL system_filtering :1; /* TRUE when running system filter */ + BOOL taint_check_slow :1; /* malloc/mmap are not returning distinct ranges */ BOOL tcp_fastopen_ok :1; /* appears to be supported by kernel */ BOOL tcp_in_fastopen :1; /* conn usefully used fastopen */ BOOL tcp_in_fastopen_data :1; /* fastopen carried data */ @@ -339,7 +340,7 @@ extern BOOL allow_domain_literals; /* As it says */ extern BOOL allow_mx_to_ip; /* Allow MX records to -> ip address */ #ifdef EXPERIMENTAL_ARC -struct arc_set *arc_received; /* highest ARC instance evaluation struct */ +extern struct arc_set *arc_received; /* highest ARC instance evaluation struct */ extern int arc_received_instance; /* highest ARC instance number in headers */ extern int arc_oldest_pass; /* lowest passing instance number in headers */ extern const uschar *arc_state; /* verification state */ diff -urN ../exim-4.93.0.4.orig/src/ip.c ./src/ip.c --- ../exim-4.93.0.4.orig/src/ip.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/ip.c 2020-08-25 15:32:22.742109000 +0300 @@ -269,28 +269,34 @@ /*XXX also seen on successful TFO, sigh */ tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA; } - else if (errno == EINPROGRESS) /* expected if we had no cookie for peer */ + else switch (errno) + { + case EINPROGRESS: /* expected if we had no cookie for peer */ /* seen for no-data, proper TFO option, both cookie-request and with-cookie cases */ /* apparently no visibility of the diffference at this point */ /* seen for with-data, proper TFO opt, cookie-req */ /* with netwk delay, post-conn tcp_info sees unacked 1 for R, 2 for C; code in smtp_out.c */ /* ? older Experimental TFO option behaviour ? */ - { /* queue unsent data */ - DEBUG(D_transport|D_v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n", - fastopen_blob->len > 0 ? "with" : "no"); - if (!fastopen_blob->data) - { - tcp_out_fastopen = TFO_ATTEMPTED_NODATA; /* we tried; unknown if useful yet */ - rc = 0; - } - else - rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0); - } - else if(errno == EOPNOTSUPP) - { - DEBUG(D_transport) - debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n"); - goto legacy_connect; + DEBUG(D_transport|D_v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n", + fastopen_blob->len > 0 ? "with" : "no"); + if (!fastopen_blob->data) + { + tcp_out_fastopen = TFO_ATTEMPTED_NODATA; /* we tried; unknown if useful yet */ + rc = 0; + } + else /* queue unsent data */ + rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0); + break; + + case EOPNOTSUPP: + DEBUG(D_transport) + debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n"); + goto legacy_connect; + + case EPIPE: + DEBUG(D_transport) + debug_printf("Tried TCP Fast Open but kernel too old to support it\n"); + goto legacy_connect; } # endif # ifdef EXIM_TFO_CONNECTX diff -urN ../exim-4.93.0.4.orig/src/lookups/dsearch.c ./src/lookups/dsearch.c --- ../exim-4.93.0.4.orig/src/lookups/dsearch.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/lookups/dsearch.c 2020-08-25 15:32:22.743640000 +0300 @@ -28,7 +28,7 @@ dsearch_open(uschar *dirname, uschar **errmsg) { DIR *dp = opendir(CS dirname); -if (dp == NULL) +if (!dp) { int save_errno = errno; *errmsg = string_open_failed(errno, "%s for directory search", dirname); @@ -47,8 +47,8 @@ /* The handle will always be (void *)(-1), but don't try casting it to an integer as this gives warnings on 64-bit systems. */ -BOOL -static dsearch_check(void *handle, uschar *filename, int modemask, uid_t *owners, +static BOOL +dsearch_check(void *handle, uschar *filename, int modemask, uid_t *owners, gid_t *owngroups, uschar **errmsg) { handle = handle; @@ -87,7 +87,9 @@ filename = string_sprintf("%s/%s", dirname, keystring); if (Ulstat(filename, &statbuf) >= 0) { - *result = string_copy(keystring); + /* Since the filename exists in the filesystem, we can return a + non-tainted result. */ + *result = string_copy_taint(keystring, FALSE); return OK; } diff -urN ../exim-4.93.0.4.orig/src/macros.h ./src/macros.h --- ../exim-4.93.0.4.orig/src/macros.h 2020-01-03 14:08:52.000000000 +0200 +++ ./src/macros.h 2020-08-25 15:32:22.747543000 +0300 @@ -152,12 +152,19 @@ into big_buffer_size and in some circumstances increased. It should be at least as long as the maximum path length. */ -#if defined PATH_MAX && PATH_MAX > 16384 +#ifdef AUTH_HEIMDAL_GSSAPI + /* RFC 4121 section 5.2, SHOULD support 64K input buffers */ +# define __BIG_BUFFER_SIZE 65536 +#else +# define __BIG_BUFFER_SIZE 16384 +#endif + +#if defined PATH_MAX && PATH_MAX > __BIG_BUFFER_SIZE # define BIG_BUFFER_SIZE PATH_MAX -#elif defined MAXPATHLEN && MAXPATHLEN > 16384 +#elif defined MAXPATHLEN && MAXPATHLEN > __BIG_BUFFER_SIZE # define BIG_BUFFER_SIZE MAXPATHLEN #else -# define BIG_BUFFER_SIZE 16384 +# define BIG_BUFFER_SIZE __BIG_BUFFER_SIZE #endif /* header size of pipe content diff -urN ../exim-4.93.0.4.orig/src/mytypes.h ./src/mytypes.h --- ../exim-4.93.0.4.orig/src/mytypes.h 2020-01-03 14:08:52.000000000 +0200 +++ ./src/mytypes.h 2020-08-25 15:32:22.749719000 +0300 @@ -100,19 +100,15 @@ #define Uread(f,b,l) read(f,CS(b),l) #define Urename(s,t) rename(CCS(s),CCS(t)) #define Ustat(s,t) stat(CCS(s),t) -#define Ustrcat(s,t) __Ustrcat(s, CUS(t), __FUNCTION__, __LINE__) #define Ustrchr(s,n) US strchr(CCS(s),n) #define CUstrchr(s,n) CUS strchr(CCS(s),n) #define CUstrerror(n) CUS strerror(n) #define Ustrcmp(s,t) strcmp(CCS(s),CCS(t)) -#define Ustrcpy(s,t) __Ustrcpy(s, CUS(t), __FUNCTION__, __LINE__) #define Ustrcpy_nt(s,t) strcpy(CS s, CCS t) /* no taint check */ #define Ustrcspn(s,t) strcspn(CCS(s),CCS(t)) #define Ustrftime(s,m,f,t) strftime(CS(s),m,f,t) #define Ustrlen(s) (int)strlen(CCS(s)) -#define Ustrncat(s,t,n) __Ustrncat(s, CUS(t),n, __FUNCTION__, __LINE__) #define Ustrncmp(s,t,n) strncmp(CCS(s),CCS(t),n) -#define Ustrncpy(s,t,n) __Ustrncpy(s, CUS(t),n, __FUNCTION__, __LINE__) #define Ustrncpy_nt(s,t,n) strncpy(CS s, CCS t, n) /* no taint check */ #define Ustrpbrk(s,t) strpbrk(CCS(s),CCS(t)) #define Ustrrchr(s,n) US strrchr(CCS(s),n) @@ -125,57 +121,17 @@ #define Ustrtoul(s,t,b) strtoul(CCS(s),CSS(t),b) #define Uunlink(s) unlink(CCS(s)) -extern void die_tainted(const uschar *, const uschar *, int); - -/* Predicate: if an address is in a tainted pool. -By extension, a variable pointing to this address is tainted. -*/ - -static inline BOOL -is_tainted(const void * p) -{ -#if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) -return FALSE; - -#elif defined(TAINT_CHECK_SLOW) -extern BOOL is_tainted_fn(const void *); -return is_tainted_fn(p); - +#ifdef EM_VERSION_C +# define Ustrcat(s,t) strcat(CS(s), CCS(t)) +# define Ustrcpy(s,t) strcpy(CS(s), CCS(t)) +# define Ustrncat(s,t,n) strncat(CS(s), CCS(t), n) +# define Ustrncpy(s,t,n) strncpy(CS(s), CCS(t), n) #else -extern void * tainted_base, * tainted_top; -return p >= tainted_base && p < tainted_top; -#endif -} - -static inline uschar * __Ustrcat(uschar * dst, const uschar * src, const char * func, int line) -{ -#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) -if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrcat", CUS func, line); -#endif -return US strcat(CS dst, CCS src); -} -static inline uschar * __Ustrcpy(uschar * dst, const uschar * src, const char * func, int line) -{ -#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) -if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrcpy", CUS func, line); -#endif -return US strcpy(CS dst, CCS src); -} -static inline uschar * __Ustrncat(uschar * dst, const uschar * src, size_t n, const char * func, int line) -{ -#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) -if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrncat", CUS func, line); -#endif -return US strncat(CS dst, CCS src, n); -} -static inline uschar * __Ustrncpy(uschar * dst, const uschar * src, size_t n, const char * func, int line) -{ -#if !defined(COMPILE_UTILITY) && !defined(MACRO_PREDEF) -if (!is_tainted(dst) && is_tainted(src)) die_tainted(US"Ustrncpy", CUS func, line); +# define Ustrcat(s,t) __Ustrcat(s, CUS(t), __FUNCTION__, __LINE__) +# define Ustrcpy(s,t) __Ustrcpy(s, CUS(t), __FUNCTION__, __LINE__) +# define Ustrncat(s,t,n) __Ustrncat(s, CUS(t), n, __FUNCTION__, __LINE__) +# define Ustrncpy(s,t,n) __Ustrncpy(s, CUS(t), n, __FUNCTION__, __LINE__) #endif -return US strncpy(CS dst, CCS src, n); -} -/*XXX will likely need unchecked copy also */ #endif /* End of mytypes.h */ diff -urN ../exim-4.93.0.4.orig/src/pdkim/pdkim.c ./src/pdkim/pdkim.c --- ../exim-4.93.0.4.orig/src/pdkim/pdkim.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/pdkim/pdkim.c 2020-08-25 15:32:22.751504000 +0300 @@ -1430,7 +1430,7 @@ if ((*errstr = exim_dkim_verify_init(&p->key, sig->keytype == KEYTYPE_ED25519 ? KEYFMT_ED25519_BARE : KEYFMT_DER, - vctx))) + vctx, &sig->keybits))) { DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr); sig->verify_status = PDKIM_VERIFY_INVALID; diff -urN ../exim-4.93.0.4.orig/src/pdkim/pdkim.h ./src/pdkim/pdkim.h --- ../exim-4.93.0.4.orig/src/pdkim/pdkim.h 2020-01-03 14:08:52.000000000 +0200 +++ ./src/pdkim/pdkim.h 2020-08-25 15:32:22.751686000 +0300 @@ -140,8 +140,9 @@ int version; /* (a=) The signature algorithm. */ - int keytype; /* pdkim_keytypes index */ - int hashtype; /* pdkim_hashes index */ + int keytype; /* pdkim_keytypes index */ + unsigned keybits; /* size of the key */ + int hashtype; /* pdkim_hashes index */ /* (c=x/) Header canonicalization method. Either PDKIM_CANON_SIMPLE or PDKIM_CANON_RELAXED */ diff -urN ../exim-4.93.0.4.orig/src/pdkim/signing.c ./src/pdkim/signing.c --- ../exim-4.93.0.4.orig/src/pdkim/signing.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/pdkim/signing.c 2020-08-25 15:32:22.751948000 +0300 @@ -155,7 +155,8 @@ Return: NULL for success, or an error string */ const uschar * -exim_dkim_verify_init(blob * pubkey, keyformat fmt, ev_ctx * verify_ctx) +exim_dkim_verify_init(blob * pubkey, keyformat fmt, ev_ctx * verify_ctx, + unsigned * bits) { gnutls_datum_t k; int rc; @@ -182,6 +183,7 @@ ret = US"pubkey format not handled"; break; } +if (!ret && bits) gnutls_pubkey_get_pk_algorithm(verify_ctx->key, bits); return ret; } @@ -552,7 +554,8 @@ Return: NULL for success, or an error string */ const uschar * -exim_dkim_verify_init(blob * pubkey, keyformat fmt, ev_ctx * verify_ctx) +exim_dkim_verify_init(blob * pubkey, keyformat fmt, ev_ctx * verify_ctx, + unsigned * bits) { /* in code sequence per b81207d2bfa92 rsa_parse_public_key() and asn1_get_mpi() @@ -560,6 +563,7 @@ uschar tag_class; int taglen; long alen; +unsigned nbits; int rc; uschar * errstr; gcry_error_t gerr; @@ -608,10 +612,10 @@ /* read two integers */ DEBUG(D_acl) stage = US"MPI"; -if ( (errstr = as_mpi(pubkey, &verify_ctx->n)) - || (errstr = as_mpi(pubkey, &verify_ctx->e)) - ) - return errstr; +nbits = pubkey->len; +if ((errstr = as_mpi(pubkey, &verify_ctx->n))) return errstr; +nbits = (nbits - pubkey->len) * 8; +if ((errstr = as_mpi(pubkey, &verify_ctx->e))) return errstr; #ifdef extreme_debug DEBUG(D_acl) debug_printf_indent("rsa_verify_init:\n"); @@ -624,6 +628,7 @@ } #endif +if (bits) *bits = nbits; return NULL; asn_err: @@ -794,7 +799,8 @@ Return: NULL for success, or an error string */ const uschar * -exim_dkim_verify_init(blob * pubkey, keyformat fmt, ev_ctx * verify_ctx) +exim_dkim_verify_init(blob * pubkey, keyformat fmt, ev_ctx * verify_ctx, + unsigned * bits) { const uschar * s = pubkey->data; uschar * ret = NULL; @@ -818,6 +824,7 @@ break; } +if (!ret && bits) *bits = EVP_PKEY_bits(verify_ctx->key); return ret; } diff -urN ../exim-4.93.0.4.orig/src/pdkim/signing.h ./src/pdkim/signing.h --- ../exim-4.93.0.4.orig/src/pdkim/signing.h 2020-01-03 14:08:52.000000000 +0200 +++ ./src/pdkim/signing.h 2020-08-25 15:32:22.752003000 +0300 @@ -90,7 +90,7 @@ extern const uschar * exim_dkim_signing_init(const uschar *, es_ctx *); extern const uschar * exim_dkim_sign(es_ctx *, hashmethod, blob *, blob *); -extern const uschar * exim_dkim_verify_init(blob *, keyformat, ev_ctx *); +extern const uschar * exim_dkim_verify_init(blob *, keyformat, ev_ctx *, unsigned *); extern const uschar * exim_dkim_verify(ev_ctx *, hashmethod, blob *, blob *); #endif /*DISABLE_DKIM*/ diff -urN ../exim-4.93.0.4.orig/src/readconf.c ./src/readconf.c --- ../exim-4.93.0.4.orig/src/readconf.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/readconf.c 2020-08-25 15:32:22.753876000 +0300 @@ -3788,6 +3788,7 @@ if (!d->driver_name) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "no driver defined for %s \"%s\"", class, d->name); + /* s is using big_buffer, so this call had better not */ (d->info->init)(d); d = NULL; } diff -urN ../exim-4.93.0.4.orig/src/receive.c ./src/receive.c --- ../exim-4.93.0.4.orig/src/receive.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/receive.c 2020-08-25 15:32:22.755223000 +0300 @@ -270,8 +270,8 @@ "check_space = " PR_EXIM_ARITH "K inodes = %d msg_size = %d\n", space, inodes, check_spool_space, check_spool_inodes, msg_size); - if ((space >= 0 && space < check_spool_space) || - (inodes >= 0 && inodes < check_spool_inodes)) + if ( space >= 0 && space + msg_size / 1024 < check_spool_space + || inodes >= 0 && inodes < check_spool_inodes) { log_write(0, LOG_MAIN, "spool directory space check failed: space=" PR_EXIM_ARITH " inodes=%d", space, inodes); @@ -1756,6 +1756,13 @@ message_linecount = body_linecount = body_zerocount = max_received_linelength = 0; +#ifdef WITH_CONTENT_SCAN +/* reset non-per-part mime variables */ +mime_is_coverletter = 0; +mime_is_rfc822 = 0; +mime_part_count = -1; +#endif + #ifndef DISABLE_DKIM /* Call into DKIM to set up the context. In CHUNKING mode we clear the dot-stuffing flag */ diff -urN ../exim-4.93.0.4.orig/src/smtp_in.c ./src/smtp_in.c --- ../exim-4.93.0.4.orig/src/smtp_in.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/smtp_in.c 2020-08-25 15:32:22.761934000 +0300 @@ -2050,7 +2050,8 @@ f.active_local_sender_retain = local_sender_retain; /* Can be set by ACL */ sending_ip_address = NULL; return_path = sender_address = NULL; -sender_data = NULL; /* Can be set by ACL */ +deliver_localpart_data = deliver_domain_data = +recipient_data = sender_data = NULL; /* Can be set by ACL */ deliver_localpart_parent = deliver_localpart_orig = NULL; deliver_domain_parent = deliver_domain_orig = NULL; callout_address = NULL; diff -urN ../exim-4.93.0.4.orig/src/spf.c ./src/spf.c --- ../exim-4.93.0.4.orig/src/spf.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/spf.c 2020-08-25 15:32:22.762605000 +0300 @@ -139,7 +139,12 @@ srr.rr[found++] = (void *) s; } -srr.num_rr = found; +/* Did we filter out all TXT RRs? Return NO_DATA instead of SUCCESS with +empty ANSWER section. */ + +if (!(srr.num_rr = found)) + srr.herrno = NO_DATA; + /* spfrr->rr must have been malloc()d for this */ SPF_dns_rr_dup(&spfrr, &srr); return spfrr; diff -urN ../exim-4.93.0.4.orig/src/store.c ./src/store.c --- ../exim-4.93.0.4.orig/src/store.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/store.c 2020-08-25 15:32:22.763951000 +0300 @@ -102,13 +102,6 @@ static void *next_yield[NPOOLS]; static int yield_length[NPOOLS] = { -1, -1, -1, -1, -1, -1 }; -/* The limits of the tainted pools. Tracking these on new allocations enables -a fast is_tainted implementation. We assume the kernel only allocates mmaps using -one side or the other of data+heap, not both. */ - -void * tainted_base = (void *)-1; -void * tainted_top = (void *)0; - /* pool_malloc holds the amount of memory used by the store pools; this goes up and down as store is reset or released. nonpool_malloc is the total got by malloc from other calls; this doesn't go down because it is just freed by @@ -162,32 +155,34 @@ /******************************************************************************/ -/* Slower version check, for use when platform intermixes malloc and mmap area -addresses. */ +/* Test if a pointer refers to tainted memory. + +Slower version check, for use when platform intermixes malloc and mmap area +addresses. Test against the current-block of all tainted pools first, then all +blocks of all tainted pools. + +Return: TRUE iff tainted +*/ BOOL is_tainted_fn(const void * p) { storeblock * b; -int pool; -for (pool = 0; pool < nelem(chainbase); pool++) +for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++) if ((b = current_block[pool])) { - char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK; - if (CS p >= bc && CS p <= bc + b->length) goto hit; + uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK; + if (US p >= bc && US p <= bc + b->length) return TRUE; } -for (pool = 0; pool < nelem(chainbase); pool++) +for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++) for (b = chainbase[pool]; b; b = b->next) { - char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK; - if (CS p >= bc && CS p <= bc + b->length) goto hit; + uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK; + if (US p >= bc && US p <= bc + b->length) return TRUE; } return FALSE; - -hit: -return pool >= POOL_TAINT_BASE; } @@ -199,6 +194,7 @@ } + /************************************************* * Get a block from the current pool * *************************************************/ @@ -730,7 +726,7 @@ BOOL release_ok = !tainted && store_last_get[pool] == block; uschar * newtext; -#ifndef MACRO_PREDEF +#if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY) if (is_tainted(block) != tainted) die_tainted(US"store_newblock", CUS func, linenumber); #endif @@ -787,9 +783,6 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to mmap %d bytes of memory: " "called from line %d of %s", size, line, func); -if (yield < tainted_base) tainted_base = yield; -if ((top = US yield + size) > tainted_top) tainted_top = top; - return store_alloc_tail(yield, size, func, line, US"Mmap"); } diff -urN ../exim-4.93.0.4.orig/src/string.c ./src/string.c --- ../exim-4.93.0.4.orig/src/string.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/string.c 2020-08-25 15:32:22.764542000 +0300 @@ -12,7 +12,6 @@ #include "exim.h" #include -static void gstring_rebuffer(gstring * g); #ifndef COMPILE_UTILITY /************************************************* @@ -1243,16 +1242,6 @@ -/* Copy the content of a string to tainted memory */ -static void -gstring_rebuffer(gstring * g) -{ -uschar * s = store_get(g->size, TRUE); -memcpy(s, g->s, g->ptr); -g->s = s; -} - - /* Build or append to a growing-string, sprintf-style. diff -urN ../exim-4.93.0.4.orig/src/tls-gnu.c ./src/tls-gnu.c --- ../exim-4.93.0.4.orig/src/tls-gnu.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/tls-gnu.c 2020-08-25 15:32:22.765859000 +0300 @@ -181,6 +181,10 @@ BOOL peer_dane_verified; BOOL trigger_sni_changes; BOOL have_set_peerdn; +#ifdef SUPPORT_CORK + BOOL corked:1; +#endif + const struct host_item *host; /* NULL if server */ gnutls_x509_crt_t peercert; uschar *peerdn; @@ -3309,9 +3313,8 @@ size_t left = len; exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server; #ifdef SUPPORT_CORK -static BOOL corked = FALSE; -if (more && !corked) gnutls_record_cork(state->session); +if (more && !state->corked) gnutls_record_cork(state->session); #endif DEBUG(D_tls) debug_printf("%s(%p, " SIZE_T_FMT "%s)\n", __FUNCTION__, @@ -3352,10 +3355,10 @@ } #ifdef SUPPORT_CORK -if (more != corked) +if (more != state->corked) { if (!more) (void) gnutls_record_uncork(state->session, 0); - corked = more; + state->corked = more; } #endif diff -urN ../exim-4.93.0.4.orig/src/tls-openssl.c ./src/tls-openssl.c --- ../exim-4.93.0.4.orig/src/tls-openssl.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/tls-openssl.c 2020-08-25 15:32:22.766762000 +0300 @@ -2480,7 +2480,7 @@ #endif } - /* If a certificate file is empty, the next function fails with an + /* If a certificate file is empty, the load function fails with an unhelpful error message. If we skip it, we get the correct behaviour (no certificates are recognized, but the error message is still misleading (it says no certificate was supplied). But this is better. */ @@ -2489,9 +2489,9 @@ && !SSL_CTX_load_verify_locations(sctx, CS file, CS dir)) return tls_error(US"SSL_CTX_load_verify_locations", host, NULL, errstr); - /* Load the list of CAs for which we will accept certs, for sending - to the client. This is only for the one-file tls_verify_certificates - variant. + /* On the server load the list of CAs for which we will accept certs, for + sending to the client. This is only for the one-file + tls_verify_certificates variant. If a list isn't loaded into the server, but some verify locations are set, the server end appears to make a wildcard request for client certs. Meanwhile, the client library as default behaviour *ignores* the list @@ -2503,7 +2503,7 @@ { STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file); - SSL_CTX_set_client_CA_list(sctx, names); + if (!host) SSL_CTX_set_client_CA_list(sctx, names); DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n", sk_X509_NAME_num(names)); } diff -urN ../exim-4.93.0.4.orig/src/transport.c ./src/transport.c --- ../exim-4.93.0.4.orig/src/transport.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/transport.c 2020-08-25 15:32:22.767937000 +0300 @@ -253,6 +253,7 @@ else { + sigalrm_seen = FALSE; ALARM(local_timeout); rc = diff -urN ../exim-4.93.0.4.orig/src/transports/smtp.c ./src/transports/smtp.c --- ../exim-4.93.0.4.orig/src/transports/smtp.c 2020-01-03 14:08:52.000000000 +0200 +++ ./src/transports/smtp.c 2020-08-25 15:32:22.773019000 +0300 @@ -309,7 +309,7 @@ .tls_verify_cert_hostnames = US"*", #endif #ifdef SUPPORT_I18N - .utf8_downconvert = NULL, + .utf8_downconvert = US"-1", #endif #ifndef DISABLE_DKIM .dkim = diff -urN ../exim-4.93.0.4.orig/src/version.h ./src/version.h --- ../exim-4.93.0.4.orig/src/version.h 2020-01-07 01:46:10.000000000 +0200 +++ ./src/version.h 2020-08-25 15:32:31.136316000 +0300 @@ -1,5 +1,5 @@ /* automatically generated file - see ../scripts/reversion */ -#define EXIM_RELEASE_VERSION "4.93.0.4" +#define EXIM_RELEASE_VERSION "4.93.0.4-30-5edf9c71f" #ifdef EXIM_VARIANT_VERSION #define EXIM_VERSION_STR EXIM_RELEASE_VERSION "-" EXIM_VARIANT_VERSION #else diff -urN ../exim-4.93.0.4.orig/src/version.sh ./src/version.sh --- ../exim-4.93.0.4.orig/src/version.sh 2020-01-07 01:46:10.000000000 +0200 +++ ./src/version.sh 2020-08-25 15:32:31.135956000 +0300 @@ -1,3 +1,3 @@ # automatically generated file - see ../scripts/reversion -EXIM_RELEASE_VERSION="4.93.0.4" +EXIM_RELEASE_VERSION="4.93.0.4-30-5edf9c71f" EXIM_COMPILE_NUMBER="1"