commit 173bd1c8f9cf83ad8c0e61a9e32678e7e371d41d Author: Jeremy Harris Date: Tue Jun 2 14:50:31 2020 +0100 Taint: fix pam expansion condition. Bug 2587 (cherry picked from commit f7f933a199be8bb7362c715e0040545b514cddca) diff --git a/src/src/auths/call_pam.c b/src/src/auths/call_pam.c index 2959cbbf3..80bb23ec3 100644 --- a/src/src/auths/call_pam.c +++ b/src/src/auths/call_pam.c @@ -83,8 +83,7 @@ for (int i = 0; i < num_msg; i++) { case PAM_PROMPT_ECHO_ON: case PAM_PROMPT_ECHO_OFF: - arg = string_nextinlist(&pam_args, &sep, big_buffer, big_buffer_size); - if (!arg) + if (!(arg = string_nextinlist(&pam_args, &sep, NULL, 0))) { arg = US""; pam_arg_ended = TRUE; @@ -155,7 +154,7 @@ pam_arg_ended = FALSE; fail. PAM doesn't support authentication with an empty user (it prompts for it, causing a potential mis-interpretation). */ -user = string_nextinlist(&pam_args, &sep, big_buffer, big_buffer_size); +user = string_nextinlist(&pam_args, &sep, NULL, 0); if (user == NULL || user[0] == 0) return FAIL; /* Start off PAM interaction */ commit 63652bbaf66c4bdb388b08fdf3eb8ab1e4d91475 Author: Jeremy Harris Date: Tue Jun 2 15:03:36 2020 +0100 Taint: fix listcount expansion operator. Bug 2586 (cherry picked from commit 44644c2e404a3ea0191db0b0458e86924fb240bb) diff --git a/src/src/expand.c b/src/src/expand.c index 26f7f10ac..6ed22c14d 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -7208,9 +7208,8 @@ while (*s != 0) { int cnt = 0; int sep = 0; - uschar buffer[256]; - while (string_nextinlist(CUSS &sub, &sep, buffer, sizeof(buffer))) cnt++; + while (string_nextinlist(CUSS &sub, &sep, NULL, 0)) cnt++; yield = string_fmt_append(yield, "%d", cnt); continue; } commit aabe0ebe82297d7dec3abdfff9c3b1edc34fd8ab Author: Patrick Boutilier Date: Tue Jun 2 15:16:10 2020 +0100 Docs: fix mistaken variable name (cherry picked from commit eb55cb1d2c5552209e24345e9d21f83ec1eaccf6) diff --git a/src/README.UPDATING b/src/README.UPDATING index a0afa8df0..708027f2c 100644 --- a/src/README.UPDATING +++ b/src/README.UPDATING @@ -31,9 +31,9 @@ Exim version 4.94 Some Transports now refuse to use tainted data in constructing their delivery location; this WILL BREAK configurations which are not updated accordingly. -In particular: any Transport use of $local_user which has been relying upon +In particular: any Transport use of $local_part which has been relying upon check_local_user far away in the Router to make it safe, should be updated to -replace $local_user with $local_part_data. +replace $local_part with $local_part_data. Attempting to remove, in router or transport, a header name that ends with an asterisk (which is a standards-legal name) will now result in all headers commit 623f07cfdcaca96274ca765d0fcf0761bdf7151b Author: Jeremy Harris Date: Wed Jun 3 11:40:17 2020 +0100 Taint: fix multiple ACL actions to properly manage tainted argument data (cherry picked from commit 12b7f811de4a540d0724585aecfa33b5881e2a30) diff --git a/src/src/acl.c b/src/src/acl.c index c1d60bbd9..8619cd5ef 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -3349,11 +3349,11 @@ for (; cb; cb = cb->next) { /* Separate the regular expression and any optional parameters. */ const uschar * list = arg; - uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size); + uschar *ss = string_nextinlist(&list, &sep, NULL, 0); /* Run the dcc backend. */ rc = dcc_process(&ss); /* Modify return code based upon the existence of options. */ - while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) + while ((ss = string_nextinlist(&list, &sep, NULL, 0))) if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER) rc = FAIL; /* FAIL so that the message is passed to the next ACL */ } @@ -3514,7 +3514,7 @@ for (; cb; cb = cb->next) int sep = 0; const uschar *s = arg; uschar * ss; - while ((ss = string_nextinlist(&s, &sep, big_buffer, big_buffer_size))) + while ((ss = string_nextinlist(&s, &sep, NULL, 0))) { if (Ustrcmp(ss, "main") == 0) logbits |= LOG_MAIN; else if (Ustrcmp(ss, "panic") == 0) logbits |= LOG_PANIC; @@ -3567,7 +3567,7 @@ for (; cb; cb = cb->next) { /* Separate the regular expression and any optional parameters. */ const uschar * list = arg; - uschar * ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size); + uschar * ss = string_nextinlist(&list, &sep, NULL, 0); uschar * opt; BOOL defer_ok = FALSE; int timeout = 0; @@ -3672,11 +3672,11 @@ for (; cb; cb = cb->next) { /* Separate the regular expression and any optional parameters. */ const uschar * list = arg; - uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size); + uschar *ss = string_nextinlist(&list, &sep, NULL, 0); rc = spam(CUSS &ss); /* Modify return code based upon the existence of options. */ - while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) + while ((ss = string_nextinlist(&list, &sep, NULL, 0))) if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER) rc = FAIL; /* FAIL so that the message is passed to the next ACL */ } commit 0e8319c3edebfec2158fbaa4898af27cb3225c99 Author: Jeremy Harris Date: Thu Jun 4 15:28:15 2020 +0100 Fix -bi. Bug 2590 Actual fix from pierre.labastie@neuf.fr ; additional coding and testcase bu jgh Broken-by: bdcc6f2bd5 (Cherry-picked from: 0e0e171628) diff --git a/src/src/exim.c b/src/src/exim.c index a60488e95..6143fe989 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -2148,7 +2148,7 @@ on the second character (the one after '-'), to save some effort. */ concept of *the* alias file, but since Sun's YP make script calls sendmail this way, some support must be provided. */ case 'i': - if (!*++argrest) bi_option = TRUE; + if (!*argrest) bi_option = TRUE; else badarg = TRUE; break; commit 701af1005a6effaac5ce249f1c2086dc6c0c2a7f Author: Jeremy Harris Date: Mon Jun 8 13:00:55 2020 +0100 Filters: fix "vacation" in Exim filter. Bug 2593 Broken-by: cfb9cf20cb (4.90) (cherry picked from commit 59eee1bc902f106d20f507ba16f37cb8ab5a5e8d) diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index 4c2c08b70..865abbf4f 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -474,10 +474,10 @@ if (oncelog && *oncelog && to) else { EXIM_DATUM key_datum, result_datum; - uschar * dirname = string_copy(oncelog); - uschar * s; + uschar * dirname, * s; - if ((s = Ustrrchr(dirname, '/'))) *s = '\0'; + dirname = (s = Ustrrchr(oncelog, '/')) + ? string_copyn(oncelog, s - oncelog) : NULL; EXIM_DBOPEN(oncelog, dirname, O_RDWR|O_CREAT, ob->mode, &dbm_file); if (!dbm_file) { commit 3fe5ec41e81831028c992f77a15292872fbbac75 Author: Jeremy Harris Date: Thu Jun 11 20:45:05 2020 +0100 TLS: use RFC 6125 rules for certifucate name checks when CNAMES are present. Bug 2594 (cherry picked from commit 0851a3bbf4667081d47f5d85b6b3a5cb33cbdba6) diff --git a/src/src/host.c b/src/src/host.c index 0e0e0130b..817d4446c 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -1950,6 +1950,13 @@ BOOL temp_error = FALSE; int af; #endif +#ifndef DISABLE_TLS +/* Copy the host name at this point to the value which is used for +TLS certificate name checking, before anything modifies it. */ + +host->certname = host->name; +#endif + /* Make sure DNS options are set as required. This appears to be necessary in some circumstances when the get..byname() function actually calls the DNS. */ @@ -2117,6 +2124,9 @@ for (int i = 1; i <= times; { host_item *next = store_get(sizeof(host_item), FALSE); next->name = host->name; +#ifndef DISABLE_TLS + next->certname = host->certname; +#endif next->mx = host->mx; next->address = text_address; next->port = PORT_NONE; @@ -2260,6 +2270,13 @@ BOOL v6_find_again = FALSE; BOOL dnssec_fail = FALSE; int i; +#ifndef DISABLE_TLS +/* Copy the host name at this point to the value which is used for +TLS certificate name checking, before any CNAME-following modifies it. */ + +host->certname = host->name; +#endif + /* If allow_ip is set, a name which is an IP address returns that value as its address. This is used for MX records when allow_mx_to_ip is set, for those sites that feel they have to flaunt the RFC rules. */ diff --git a/src/src/structs.h b/src/src/structs.h index c6700d513..206237f04 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -80,14 +80,17 @@ typedef enum {DS_UNK=-1, DS_NO, DS_YES} dnssec_status_t; typedef struct host_item { struct host_item *next; - const uschar *name; /* Host name */ - const uschar *address; /* IP address in text form */ - int port; /* port value in host order (if SRV lookup) */ - int mx; /* MX value if found via MX records */ - int sort_key; /* MX*1000 plus random "fraction" */ - int status; /* Usable, unusable, or unknown */ - int why; /* Why host is unusable */ - int last_try; /* Time of last try if known */ + const uschar *name; /* Host name */ +#ifndef DISABLE_TLS + const uschar *certname; /* Name used for certificate checks */ +#endif + const uschar *address; /* IP address in text form */ + int port; /* port value in host order (if SRV lookup) */ + int mx; /* MX value if found via MX records */ + int sort_key; /* MX*1000 plus random "fraction" */ + int status; /* Usable, unusable, or unknown */ + int why; /* Why host is unusable */ + int last_try; /* Time of last try if known */ dnssec_status_t dnssec; } host_item; diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 24114f05e..875c82efa 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2601,9 +2601,9 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) { state->exp_tls_verify_cert_hostnames = #ifdef SUPPORT_I18N - string_domain_utf8_to_alabel(host->name, NULL); + string_domain_utf8_to_alabel(host->certname, NULL); #else - host->name; + host->certname; #endif DEBUG(D_tls) debug_printf("TLS: server cert verification includes hostname: \"%s\".\n", diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 8c9d8aa69..a62322928 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -372,10 +372,10 @@ typedef struct ocsp_resp { } ocsp_resplist; typedef struct tls_ext_ctx_cb { - tls_support * tlsp; - uschar *certificate; - uschar *privatekey; - BOOL is_server; + tls_support * tlsp; + uschar * certificate; + uschar * privatekey; + BOOL is_server; #ifndef DISABLE_OCSP STACK_OF(X509) *verify_stack; /* chain for verifying the proof */ union { @@ -390,14 +390,14 @@ typedef struct tls_ext_ctx_cb { } client; } u_ocsp; #endif - uschar *dhparam; + uschar * dhparam; /* these are cached from first expand */ - uschar *server_cipher_list; + uschar * server_cipher_list; /* only passed down to tls_error: */ - host_item *host; + host_item * host; const uschar * verify_cert_hostnames; #ifndef DISABLE_EVENT - uschar * event_action; + uschar * event_action; #endif } tls_ext_ctx_cb; @@ -2915,9 +2915,9 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) { cbinfo->verify_cert_hostnames = #ifdef SUPPORT_I18N - string_domain_utf8_to_alabel(host->name, NULL); + string_domain_utf8_to_alabel(host->certname, NULL); #else - host->name; + host->certname; #endif DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n", cbinfo->verify_cert_hostnames); commit 94d719d803caf2c0c902dceeb787795eac11a63b Author: Jeremy Harris Date: Fri Jun 12 00:46:34 2020 +0100 Taint: fix radius expansion condition (cherry picked from commit f91219c114a3d95792d052555664a5a7a3984a8d) diff --git a/src/src/auths/call_radius.c b/src/src/auths/call_radius.c index cc269dcd5..9d10b34c6 100644 --- a/src/src/auths/call_radius.c +++ b/src/src/auths/call_radius.c @@ -96,8 +96,7 @@ int sep = 0; #endif -user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size); -if (!user) user = US""; +if (!(user = string_nextinlist(&radius_args, &sep, NULL, 0))) user = US""; DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" " "and \"%s\"\n", user, radius_args); commit c165e95889471bc1a644104dd9a6129c47c56c09 Author: Jeremy Harris Date: Fri Jun 12 20:43:43 2020 +0100 smtp_accept_map_per_host: call search_tidyup in fail path. Bug 2597 (cherry-picked from: d3a538c8fe) diff --git a/src/src/daemon.c b/src/src/daemon.c index 2bed143a1..9d491593f 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -336,6 +336,7 @@ if ((max_for_this_host > 0) && log_write(L_connection_reject, LOG_MAIN, "Connection from %s refused: too many connections " "from that IP address", whofrom->s); + search_tidyup(); goto ERROR_RETURN; } } commit ecf1e77accda6355ebb745a0a03e97ba7eb298b2 Author: Jeremy Harris Date: Sun Jun 14 22:14:11 2020 +0100 Taint: fix verify. Bug 2598 (cherry-picked from 2b60ac1021 and 9eed571fd7) diff --git a/src/src/acl.c b/src/src/acl.c index 8619cd5ef..11d1fd028 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1767,7 +1767,7 @@ switch(vp->value) /* Remaining items are optional; they apply to sender and recipient verification, including "header sender" verification. */ -while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) +while ((ss = string_nextinlist(&list, &sep, NULL, 0))) { if (strcmpic(ss, US"defer_ok") == 0) defer_ok = TRUE; else if (strcmpic(ss, US"no_details") == 0) no_details = TRUE; @@ -1804,7 +1804,7 @@ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) uschar * opt; while (isspace(*sublist)) sublist++; - while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer)))) + while ((opt = string_nextinlist(&sublist, &optsep, NULL, 0))) { callout_opt_t * op; double period = 1.0F; commit 5c608b75d5bd734ddca41e4468fb22544ef96265 Author: Jeremy Harris Date: Sat Jun 20 00:54:05 2020 +0100 Fix string_copy() macro to not multiple-eval args. Bug 2603 Broken-by: a76d120aed (cherry picked from commit 80c2ec2e47c556daff00c79ee068ce68f25fd264) diff --git a/src/src/functions.h b/src/src/functions.h index 0028deb0d..0050cdeeb 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -767,9 +767,9 @@ string_copy_trc(const uschar * s, const char * func, int line) /* Simple string-copy functions maintaining the taint */ #define string_copyn(s, len) \ - string_copyn_taint_trc((s), (len), is_tainted(s), __FUNCTION__, __LINE__) + string_copyn_trc((s), (len), __FUNCTION__, __LINE__) #define string_copy(s) \ - string_copy_taint_trc((s), is_tainted(s), __FUNCTION__, __LINE__) + string_copy_trc((s), __FUNCTION__, __LINE__) /************************************************* commit cdee8a5f76cc013de5622112cd04e42d0dcf333b Author: Jeremy Harris Date: Mon Jun 22 17:27:18 2020 +0100 Cutthrough: handle request when a callout-hold is active. Bug 2604 (cherry picked from commit 99bfcf2b678e7bd8125a7eb44409e46549bfc111) diff --git a/src/src/acl.c b/src/src/acl.c index 11d1fd028..62cb68561 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -3264,37 +3264,41 @@ for (; cb; cb = cb->next) the case where both sides handle prdr and this-node prdr acl is "accept" */ ignored = US"PRDR active"; + else if (f.deliver_freeze) + ignored = US"frozen"; + else if (f.queue_only_policy) + ignored = US"queue-only"; + else if (fake_response == FAIL) + ignored = US"fakereject"; + else if (rcpt_count != 1) + ignored = US"nonfirst rcpt"; + else if (cutthrough.delivery) + ignored = US"repeated"; + else if (cutthrough.callout_hold_only) + { + DEBUG(D_acl) + debug_printf_indent(" cutthrough request upgrades callout hold\n"); + cutthrough.callout_hold_only = FALSE; + cutthrough.delivery = TRUE; /* control accepted */ + } else { - if (f.deliver_freeze) - ignored = US"frozen"; - else if (f.queue_only_policy) - ignored = US"queue-only"; - else if (fake_response == FAIL) - ignored = US"fakereject"; - else + cutthrough.delivery = TRUE; /* control accepted */ + while (*p == '/') { - if (rcpt_count == 1) + const uschar * pp = p+1; + if (Ustrncmp(pp, "defer=", 6) == 0) { - cutthrough.delivery = TRUE; /* control accepted */ - while (*p == '/') - { - const uschar * pp = p+1; - if (Ustrncmp(pp, "defer=", 6) == 0) - { - pp += 6; - if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE; - /* else if (Ustrncmp(pp, "spool") == 0) ; default */ - } - else - while (*pp && *pp != '/') pp++; - p = pp; - } + pp += 6; + if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE; + /* else if (Ustrncmp(pp, "spool") == 0) ; default */ } else - ignored = US"nonfirst rcpt"; + while (*pp && *pp != '/') pp++; + p = pp; } } + DEBUG(D_acl) if (ignored) debug_printf(" cutthrough request ignored on %s item\n", ignored); } diff --git a/src/src/verify.c b/src/src/verify.c index fba1f6e9e..5f4181de9 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -875,12 +875,12 @@ tls_retry_connection: case PENDING_OK: done = TRUE; new_address_record.result = ccache_accept; break; - case FAIL: done = TRUE; + case FAIL: done = TRUE; yield = FAIL; *failure_ptr = US"recipient"; new_address_record.result = ccache_reject; break; - default: break; + default: break; } break; commit 777ee8ae75277c05fb72cc94f568ba4d2bfe15a6 Author: Jeremy Harris Date: Thu Jun 25 11:16:54 2020 +0100 Lookups: Fix "subdir" filter on a dsearch. (cherry picked from commit e0e21929b7426b9b5bbf5e3747797043801b1151) diff --git a/src/src/lookups/dsearch.c b/src/src/lookups/dsearch.c index 455273fb1..501293ac0 100644 --- a/src/src/lookups/dsearch.c +++ b/src/src/lookups/dsearch.c @@ -125,8 +125,7 @@ if ( Ulstat(filename, &statbuf) >= 0 && S_ISDIR(statbuf.st_mode) && ( flags & FILTER_DIR || keystring[0] != '.' - || keystring[1] != '.' - || keystring[1] && keystring[2] + || keystring[1] && keystring[1] != '.' ) ) ) ) { /* Since the filename exists in the filesystem, we can return a @@ -135,10 +134,10 @@ if ( Ulstat(filename, &statbuf) >= 0 return OK; } -if (errno == ENOENT) return FAIL; +if (errno == ENOENT || errno == 0) return FAIL; save_errno = errno; -*errmsg = string_sprintf("%s: lstat failed", filename); +*errmsg = string_sprintf("%s: lstat: %s", filename, strerror(errno)); errno = save_errno; return DEFER; } commit 2be77199fc9009ab796ad2d67eed20d8da4773c7 Author: Jeremy Harris Date: Sun Jun 28 15:24:21 2020 +0100 Sqlite: fix segfault on bad/missing sqlite_dbfile. Bug 2606 (cherry picked from commit 3d0472791a0928963a3f8184fe28479e80d1a47d) diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c index dc4439153..1638ea401 100644 --- a/src/src/lookups/sqlite.c +++ b/src/src/lookups/sqlite.c @@ -24,16 +24,23 @@ sqlite_open(const uschar * filename, uschar ** errmsg) sqlite3 *db = NULL; int ret; -if (!filename || !*filename) filename = sqlite_dbfile; -if (*filename != '/') +if (!filename || !*filename) + { + DEBUG(D_lookup) debug_printf_indent("Using sqlite_dbfile: %s\n", sqlite_dbfile); + filename = sqlite_dbfile; + } +if (!filename || *filename != '/') *errmsg = US"absolute file name expected for \"sqlite\" lookup"; else if ((ret = sqlite3_open(CCS filename, &db)) != 0) { *errmsg = (void *)sqlite3_errmsg(db); + sqlite3_close(db); + db = NULL; DEBUG(D_lookup) debug_printf_indent("Error opening database: %s\n", *errmsg); } -sqlite3_busy_timeout(db, 1000 * sqlite_lock_timeout); +if (db) + sqlite3_busy_timeout(db, 1000 * sqlite_lock_timeout); return db; } commit 5f3e2ac9f39db5c8ef5a408929c8a5aba957b20f Author: Jeremy Harris Date: Mon Jun 29 17:26:36 2020 +0100 Taint: fix ACL "spam" condition, to permit tainted name arguments. Cherry-picked from: 62b2ccce05 diff --git a/src/src/spam.c b/src/src/spam.c index 5eff1ad5c..63ced4f65 100644 --- a/src/src/spam.c +++ b/src/src/spam.c @@ -190,7 +190,6 @@ spam(const uschar **listptr) int sep = 0; const uschar *list = *listptr; uschar *user_name; -uschar user_name_buffer[128]; unsigned long mbox_size; FILE *mbox_file; client_conn_ctx spamd_cctx = {.sock = -1}; @@ -218,9 +217,7 @@ spamd_address_container * sd; result = 0; /* find the username from the option list */ -if ((user_name = string_nextinlist(&list, &sep, - user_name_buffer, - sizeof(user_name_buffer))) == NULL) +if (!(user_name = string_nextinlist(&list, &sep, NULL, 0))) { /* no username given, this means no scanning should be done */ return FAIL; commit cafcab0848e35047a93a8920b5105baf55f8e702 Author: Jeremy Harris Date: Tue Jun 30 21:16:42 2020 +0100 Fix message-reception clock usage. Bug 2615 Broken-by: 6906c131d1 (4.94) (cherry picked from commit c9bce82e3064126be34d85280d0a7fbf65b3abec) diff --git a/src/src/exim.c b/src/src/exim.c index 6143fe989..dde991065 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -384,14 +384,20 @@ return 0; *************************************************/ #ifdef _POSIX_MONOTONIC_CLOCK -/* Amount CLOCK_MONOTONIC is behind realtime, at startup. */ +# ifdef CLOCK_BOOTTIME +# define EXIM_CLOCKTYPE CLOCK_BOOTTIME +# else +# define EXIM_CLOCKTYPE CLOCK_MONOTONIC +# endif + +/* Amount EXIM_CLOCK is behind realtime, at startup. */ static struct timespec offset_ts; static void exim_clock_init(void) { struct timeval tv; -if (clock_gettime(CLOCK_MONOTONIC, &offset_ts) != 0) return; +if (clock_gettime(EXIM_CLOCKTYPE, &offset_ts) != 0) return; (void)gettimeofday(&tv, NULL); offset_ts.tv_sec = tv.tv_sec - offset_ts.tv_sec; offset_ts.tv_nsec = tv.tv_usec * 1000 - offset_ts.tv_nsec; @@ -402,6 +408,29 @@ offset_ts.tv_nsec += 1000*1000*1000; #endif +void +exim_gettime(struct timeval * tv) +{ +#ifdef _POSIX_MONOTONIC_CLOCK +struct timespec now_ts; + +if (clock_gettime(EXIM_CLOCKTYPE, &now_ts) == 0) + { + now_ts.tv_sec += offset_ts.tv_sec; + if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000) + { + now_ts.tv_sec++; + now_ts.tv_nsec -= 1000*1000*1000; + } + tv->tv_sec = now_ts.tv_sec; + tv->tv_usec = now_ts.tv_nsec / 1000; + } +else +#endif + (void)gettimeofday(tv, NULL); +} + + /* Exim uses a time + a pid to generate a unique identifier in two places: its message IDs, and in file names for maildir deliveries. Because some OS now re-use pids within the same second, sub-second times are now being used. @@ -428,28 +457,9 @@ exim_wait_tick(struct timeval * tgt_tv, int resolution) struct timeval now_tv; long int now_true_usec; -#ifdef _POSIX_MONOTONIC_CLOCK -struct timespec now_ts; - -if (clock_gettime(CLOCK_MONOTONIC, &now_ts) == 0) - { - now_ts.tv_sec += offset_ts.tv_sec; - if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000) - { - now_ts.tv_sec++; - now_ts.tv_nsec -= 1000*1000*1000; - } - now_tv.tv_sec = now_ts.tv_sec; - now_true_usec = (now_ts.tv_nsec / (resolution * 1000)) * resolution; - now_tv.tv_usec = now_true_usec; - } -else -#endif - { - (void)gettimeofday(&now_tv, NULL); - now_true_usec = now_tv.tv_usec; - now_tv.tv_usec = (now_true_usec/resolution) * resolution; - } +exim_gettime(&now_tv); +now_true_usec = now_tv.tv_usec; +now_tv.tv_usec = (now_true_usec/resolution) * resolution; while (exim_tvcmp(&now_tv, tgt_tv) <= 0) { @@ -1728,7 +1738,7 @@ make quite sure. */ setlocale(LC_ALL, "C"); -/* Get the offset between CLOCK_MONOTONIC and wallclock */ +/* Get the offset between CLOCK_MONOTONIC/CLOCK_BOOTTIME and wallclock */ #ifdef _POSIX_MONOTONIC_CLOCK exim_clock_init(); diff --git a/src/src/functions.h b/src/src/functions.h index 0050cdeeb..8b17531ed 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -234,6 +234,7 @@ extern void msg_event_raise(const uschar *, const address_item *); extern int exim_chown_failure(int, const uschar*, uid_t, gid_t); extern const uschar * exim_errstr(int); extern void exim_exit(int) NORETURN; +extern void exim_gettimg(struct timeval *); extern void exim_nullstd(void); extern void exim_setugid(uid_t, gid_t, BOOL, uschar *); extern void exim_underbar_exit(int) NORETURN; diff --git a/src/src/receive.c b/src/src/receive.c index 0fbd35f82..0db897e9e 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1784,7 +1784,7 @@ if (sender_host_address) dmarc_init(); /* initialize libopendmarc */ ids, and fractions of a second are required. See the comments that precede the message id creation below. */ -(void)gettimeofday(&message_id_tv, NULL); +exim_gettime(&message_id_tv); /* For other uses of the received time we can operate with granularity of one second, and for that we use the global variable received_time. This is for