commit 51894f20e0c03113b4c4e07898ac5e955b21ec41 Merge: caba96329 f70940c94 Author: Jeremy Harris Date: Sat Nov 4 14:20:45 2023 +0000 Merge branch '4.next' diff --git a/src/src/acl.c b/src/src/acl.c index 578cf32cb..cdf60bbb8 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -203,7 +203,14 @@ static condition_def conditions[] = { [ACLC_DELAY] = { US"delay", TRUE, TRUE, ACL_BIT_NOTQUIT }, #ifndef DISABLE_DKIM [ACLC_DKIM_SIGNER] = { US"dkim_signers", TRUE, FALSE, (unsigned int) ~ACL_BIT_DKIM }, - [ACLC_DKIM_STATUS] = { US"dkim_status", TRUE, FALSE, (unsigned int) ~ACL_BIT_DKIM }, + [ACLC_DKIM_STATUS] = { US"dkim_status", TRUE, FALSE, + (unsigned int) + ~(ACL_BIT_DKIM | ACL_BIT_DATA | ACL_BIT_MIME +# ifndef DISABLE_PRDR + | ACL_BIT_PRDR +# endif + ), + }, #endif #ifdef SUPPORT_DMARC [ACLC_DMARC_STATUS] = { US"dmarc_status", TRUE, FALSE, (unsigned int) ~ACL_BIT_DATA }, @@ -3764,8 +3771,14 @@ for (; cb; cb = cb->next) break; case ACLC_DKIM_STATUS: - rc = match_isinlist(dkim_verify_status, - &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL); + { /* return good for any match */ + const uschar * s = dkim_verify_status ? dkim_verify_status : US"none"; + int sep = 0; + for (uschar * ss; ss = string_nextinlist(&s, &sep, NULL, 0); ) + if ( (rc = match_isinlist(ss, &arg, + 0, NULL, NULL, MCL_STRING, TRUE, NULL)) + == OK) break; + } break; #endif diff --git a/src/src/auths/get_data.c b/src/src/auths/get_data.c index 4c67f17e2..0c9fb37fe 100644 --- a/src/src/auths/get_data.c +++ b/src/src/auths/get_data.c @@ -77,7 +77,7 @@ auth_get_data(uschar ** aptr, const uschar * challenge, int challen) { int c; int p = 0; -smtp_printf("334 %s\r\n", FALSE, b64encode(challenge, challen)); +smtp_printf("334 %s\r\n", SP_NO_MORE, b64encode(challenge, challen)); while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF) { if (p >= big_buffer_size - 1) return BAD64; diff --git a/src/src/auths/get_no64_data.c b/src/src/auths/get_no64_data.c index e2cadfbc6..ae11ae5dc 100644 --- a/src/src/auths/get_no64_data.c +++ b/src/src/auths/get_no64_data.c @@ -32,7 +32,7 @@ auth_get_no64_data(uschar **aptr, uschar *challenge) { int c; int p = 0; -smtp_printf("334 %s\r\n", FALSE, challenge); +smtp_printf("334 %s\r\n", SP_NO_MORE, challenge); while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF) { if (p >= big_buffer_size - 1) return BAD64; diff --git a/src/src/daemon.c b/src/src/daemon.c index 9709845e5..f2183c735 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -128,7 +128,7 @@ never_error(uschar *log_msg, uschar *smtp_msg, int was_errno) uschar *emsg = was_errno <= 0 ? US"" : string_sprintf(": %s", strerror(was_errno)); log_write(0, LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg); -if (smtp_out) smtp_printf("421 %s\r\n", FALSE, smtp_msg); +if (smtp_out) smtp_printf("421 %s\r\n", SP_NO_MORE, smtp_msg); } @@ -233,7 +233,7 @@ if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr), { log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC), "getsockname() failed: %s", strerror(errno)); - smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", FALSE); + smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", SP_NO_MORE); goto ERROR_RETURN; } @@ -263,7 +263,7 @@ if (smtp_accept_max > 0 && smtp_accept_count >= smtp_accept_max) DEBUG(D_any) debug_printf("rejecting SMTP connection: count=%d max=%d\n", smtp_accept_count, smtp_accept_max); smtp_printf("421 Too many concurrent SMTP connections; " - "please try again later.\r\n", FALSE); + "please try again later.\r\n", SP_NO_MORE); log_write(L_connection_reject, LOG_MAIN, "Connection from %Y refused: too many connections", whofrom); @@ -282,7 +282,7 @@ if (smtp_load_reserve >= 0) { DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n", (double)load_average/1000.0); - smtp_printf("421 Too much load; please try again later.\r\n", FALSE); + smtp_printf("421 Too much load; please try again later.\r\n", SP_NO_MORE); log_write(L_connection_reject, LOG_MAIN, "Connection from %Y refused: load average = %.2f", whofrom, (double)load_average/1000.0); @@ -351,7 +351,7 @@ if (max_for_this_host > 0 && smtp_accept_count >= max_for_this_host) "IP address: count=%d max=%d\n", host_accept_count, max_for_this_host); smtp_printf("421 Too many concurrent SMTP connections " - "from this IP address; please try again later.\r\n", FALSE); + "from this IP address; please try again later.\r\n", SP_NO_MORE); log_write(L_connection_reject, LOG_MAIN, "Connection from %Y refused: too many connections " "from that IP address", whofrom); @@ -445,7 +445,7 @@ if (pid == 0) "(smtp_active_hostname): %s", raw_active_hostname, expand_string_message); smtp_printf("421 Local configuration error; " - "please try again later.\r\n", FALSE); + "please try again later.\r\n", SP_NO_MORE); mac_smtp_fflush(); search_tidyup(); exim_underbar_exit(EXIT_FAILURE); diff --git a/src/src/macros.h b/src/src/macros.h index 2658b9ab7..969393561 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1159,4 +1159,12 @@ typedef unsigned mcs_flags; #define TSUC_ALLOW_TAINTED_ARGS BIT(1) #define TSUC_ALLOW_RECIPIENTS BIT(2) +/* Flags for smtp_printf */ +#define SP_MORE TRUE +#define SP_NO_MORE FALSE + +/* Flags for smtp_respond */ +#define SR_FINAL TRUE +#define SR_NOT_FINAL FALSE + /* End of macros.h */ diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 36e559b59..c723ae6c8 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -1868,9 +1868,9 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if (*dkim_verify_min_keysizes) { unsigned minbits; - uschar * ss = expand_getkeyed(US pdkim_keytypes[sig->keytype], + const uschar * ss = expand_getkeyed(US pdkim_keytypes[sig->keytype], dkim_verify_min_keysizes); - if (ss && (minbits = atoi(CS ss)) > sig->keybits) + if (ss && (minbits = atoi(CCS ss)) > sig->keybits) { DEBUG(D_acl) debug_printf("Key too short: Actual: %s %u Minima '%s'\n", pdkim_keytypes[sig->keytype], sig->keybits, dkim_verify_min_keysizes); diff --git a/src/src/receive.c b/src/src/receive.c index 8a400caf0..8190c5941 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -570,7 +570,7 @@ smtp_user_msg(uschar *code, uschar *user_msg) { int len = 3; smtp_message_code(&code, &len, &user_msg, NULL, TRUE); -smtp_respond(code, len, TRUE, user_msg); +smtp_respond(code, len, SR_FINAL, user_msg); } #endif @@ -1457,7 +1457,7 @@ if (!(mbox_file = spool_mbox(&mbox_size, NULL, &mbox_filename))) #ifdef EXPERIMENTAL_DCC dcc_ok = 0; #endif - smtp_respond(US"451", 3, TRUE, US"temporary local problem"); + smtp_respond(US"451", 3, SR_FINAL, US"temporary local problem"); message_id[0] = 0; /* Indicate no message accepted */ *smtp_reply_ptr = US""; /* Indicate reply already sent */ return FALSE; /* Indicate skip to end of receive function */ @@ -2309,7 +2309,7 @@ OVERSIZE: sender_address, sender_fullhost ? " H=" : "", sender_fullhost ? sender_fullhost : US"", sender_ident ? " U=" : "", sender_ident ? sender_ident : US""); - smtp_printf("552 Message header not CRLF terminated\r\n", FALSE); + smtp_printf("552 Message header not CRLF terminated\r\n", SP_NO_MORE); bdat_flush_data(); smtp_reply = US""; goto TIDYUP; /* Skip to end of function */ @@ -3251,10 +3251,9 @@ if (!ferror(spool_data_file) && !(receive_feof)() && message_ended != END_DOT) { Uunlink(spool_name); /* Lose data file when closed */ cancel_cutthrough_connection(TRUE, US"sender closed connection"); - message_id[0] = 0; /* Indicate no message_accepted */ smtp_reply = handle_lost_connection(US""); smtp_yield = FALSE; - goto TIDYUP; /* Skip to end of function */ + goto NOT_ACCEPTED; /* Skip to end of function */ } break; @@ -3597,7 +3596,7 @@ else int all_pass = OK; int all_fail = FAIL; - smtp_printf("353 PRDR content analysis beginning\r\n", TRUE); + smtp_printf("353 PRDR content analysis beginning\r\n", SP_MORE); /* Loop through recipients, responses must be in same order received */ for (unsigned int c = 0; recipients_count > c; c++) { @@ -3661,7 +3660,7 @@ else /* Check the recipients count again, as the MIME ACL might have changed them. */ - if (acl_smtp_data != NULL && recipients_count > 0) + if (acl_smtp_data && recipients_count > 0) { rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg); add_acl_headers(ACL_WHERE_DATA, US"DATA"); @@ -3922,7 +3921,7 @@ else if (smtp_input) if (!smtp_batched_input) { - smtp_respond(smtp_code, 3, TRUE, errmsg); + smtp_respond(smtp_code, 3, SR_FINAL, errmsg); smtp_reply = US""; /* Indicate reply already sent */ goto NOT_ACCEPTED; /* Skip to end of function */ } @@ -4030,11 +4029,6 @@ else receive_messagecount++; -/* Add data size to written header size. We do not count the initial file name -that is in the file, but we do add one extra for the notional blank line that -precedes the data. This total differs from message_size in that it include the -added Received: header and any other headers that got created locally. */ - if (fflush(spool_data_file)) { errmsg = string_sprintf("Spool write error: %s", strerror(errno)); @@ -4054,8 +4048,13 @@ if (fflush(spool_data_file)) /* Does not return */ } } -fstat(data_fd, &statbuf); +/* Add data size to written header size. We do not count the initial file name +that is in the file, but we do add one extra for the notional blank line that +precedes the data. This total differs from message_size in that it include the +added Received: header and any other headers that got created locally. */ + +fstat(data_fd, &statbuf); msg_size += statbuf.st_size - spool_data_start_offset(message_id) + 1; /* Generate a "message received" log entry. We do this by building up a dynamic @@ -4349,9 +4348,9 @@ if(!smtp_reply) #endif { log_write(0, LOG_MAIN | - (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) | - (LOGGING(received_sender) ? LOG_SENDER : 0), - "%Y", g); + (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) | + (LOGGING(received_sender) ? LOG_SENDER : 0), + "%Y", g); /* Log any control actions taken by an ACL or local_scan(). */ @@ -4389,9 +4388,16 @@ a queue-runner could grab it in the window. A fflush() was done earlier in the expectation that any write errors on the data file will be flushed(!) out thereby. Nevertheless, it is theoretically -possible for fclose() to fail - but what to do? What has happened to the lock -if this happens? We can at least log it; if it is observed on some platform -then we can think about properly declaring the message not-received. */ +possible for fclose() to fail - and this has been seen on obscure filesystems +(probably one that delayed the actual media write as long as possible) +but what to do? What has happened to the lock if this happens? +It's a mes because we already logged the acceptance. +We can at least log the issue, try to remove spoolfiles and respond with +a temp-reject. We do not want to close before logging acceptance because +we want to hold the lock until we know that logging worked. +Could we make this less likely by doing an fdatasync() just after the fflush()? +That seems like a good thing on data-security grounds, but how much will it hit +performance? */ goto TIDYUP; @@ -4404,8 +4410,27 @@ process_info[process_info_len] = 0; /* Remove message id */ if (spool_data_file && cutthrough_done == NOT_TRIED) { if (fclose(spool_data_file)) /* Frees the lock */ - log_write(0, LOG_MAIN|LOG_PANIC, - "spoolfile error on close: %s", strerror(errno)); + { + log_msg = string_sprintf("spoolfile error on close: %s", strerror(errno)); + log_write(0, LOG_MAIN|LOG_PANIC | + (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) | + (LOGGING(received_sender) ? LOG_SENDER : 0), + "%s", log_msg); + log_write(0, LOG_MAIN | + (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) | + (LOGGING(received_sender) ? LOG_SENDER : 0), + "rescind the above message-accept"); + + Uunlink(spool_name); + Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H")); + Uunlink(spool_fname(US"msglog", message_subdir, message_id, US"")); + + /* Claim a data ACL temp-reject, just to get reject logging and resposponse */ + smtp_handle_acl_fail(ACL_WHERE_DATA, rc, NULL, log_msg); + smtp_reply = US""; /* Indicate reply already sent */ + + message_id[0] = 0; /* no message accepted */ + } spool_data_file = NULL; } @@ -4434,7 +4459,7 @@ if (smtp_input) { if (fake_response != OK) smtp_respond(fake_response == DEFER ? US"450" : US"550", - 3, TRUE, fake_response_text); + 3, SR_FINAL, fake_response_text); /* An OK response is required; use "message" text if present. */ @@ -4443,7 +4468,7 @@ if (smtp_input) uschar *code = US"250"; int len = 3; smtp_message_code(&code, &len, &user_msg, NULL, TRUE); - smtp_respond(code, len, TRUE, user_msg); + smtp_respond(code, len, SR_FINAL, user_msg); } /* Default OK response */ @@ -4471,10 +4496,10 @@ if (smtp_input) else if (smtp_reply[0] != 0) if (fake_response != OK && smtp_reply[0] == '2') - smtp_respond(fake_response == DEFER ? US"450" : US"550", 3, TRUE, - fake_response_text); + smtp_respond(fake_response == DEFER ? US"450" : US"550", + 3, SR_FINAL, fake_response_text); else - smtp_printf("%.1024s\r\n", FALSE, smtp_reply); + smtp_printf("%.1024s\r\n", SP_NO_MORE, smtp_reply); switch (cutthrough_done) { diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 8cc9f74bf..c565d522d 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -764,7 +764,7 @@ for(;;) return EOD; } - smtp_printf("250 %u byte chunk received\r\n", FALSE, chunking_datasize); + smtp_printf("250 %u byte chunk received\r\n", SP_NO_MORE, chunking_datasize); chunking_state = CHUNKING_OFFERED; DEBUG(D_receive) debug_printf("chunking state %d\n", (int)chunking_state); @@ -802,7 +802,7 @@ next_cmd: case NOOP_CMD: HAD(SCH_NOOP); - smtp_printf("250 OK\r\n", FALSE); + smtp_printf("250 OK\r\n", SP_NO_MORE); goto next_cmd; case BDAT_CMD: @@ -1298,7 +1298,7 @@ smtp_closedown(uschar * message) { if (!smtp_in || smtp_batched_input) return; receive_swallow_smtp(); -smtp_printf("421 %s\r\n", FALSE, message); +smtp_printf("421 %s\r\n", SP_NO_MORE, message); for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED)) { @@ -1307,16 +1307,16 @@ for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED)) case QUIT_CMD: f.smtp_in_quit = TRUE; - smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname); + smtp_printf("221 %s closing connection\r\n", SP_NO_MORE, smtp_active_hostname); mac_smtp_fflush(); return; case RSET_CMD: - smtp_printf("250 Reset OK\r\n", FALSE); + smtp_printf("250 Reset OK\r\n", SP_NO_MORE); break; default: - smtp_printf("421 %s\r\n", FALSE, message); + smtp_printf("421 %s\r\n", SP_NO_MORE, message); break; } } @@ -2266,7 +2266,7 @@ if (!f.sender_host_unknown) { log_write(0, LOG_MAIN, "getsockopt() failed from %s: %s", host_and_ident(FALSE), strerror(errno)); - smtp_printf("451 SMTP service not available\r\n", FALSE); + smtp_printf("451 SMTP service not available\r\n", SP_NO_MORE); return FALSE; } } @@ -2370,7 +2370,7 @@ if (!f.sender_host_unknown) log_write(0, LOG_MAIN|LOG_REJECT, "connection from %s refused (IP options)", host_and_ident(FALSE)); - smtp_printf("554 SMTP service not available\r\n", FALSE); + smtp_printf("554 SMTP service not available\r\n", SP_NO_MORE); return FALSE; } @@ -2425,7 +2425,7 @@ if (!f.sender_host_unknown) #ifndef DISABLE_TLS if (!tls_in.on_connect) #endif - smtp_printf("554 SMTP service not available\r\n", FALSE); + smtp_printf("554 SMTP service not available\r\n", SP_NO_MORE); return FALSE; } @@ -2456,7 +2456,7 @@ if (!f.sender_host_unknown) log_write(L_connection_reject, LOG_MAIN|LOG_REJECT, "refused connection from %s " "(tcp wrappers)", host_and_ident(FALSE)); - smtp_printf("554 SMTP service not available\r\n", FALSE); + smtp_printf("554 SMTP service not available\r\n", SP_NO_MORE); } else { @@ -2466,7 +2466,7 @@ if (!f.sender_host_unknown) log_write(L_connection_reject, LOG_MAIN|LOG_REJECT, "temporarily refused connection from %s " "(tcp wrappers errno=%d)", host_and_ident(FALSE), save_errno); - smtp_printf("451 Temporary local problem - please try later\r\n", FALSE); + smtp_printf("451 Temporary local problem - please try later\r\n", SP_NO_MORE); } return FALSE; } @@ -2486,7 +2486,7 @@ if (!f.sender_host_unknown) host_and_ident(FALSE), smtp_accept_count - 1, smtp_accept_max, smtp_accept_reserve, (rc == DEFER)? " (lookup deferred)" : ""); smtp_printf("421 %s: Too many concurrent SMTP connections; " - "please try again later\r\n", FALSE, smtp_active_hostname); + "please try again later\r\n", SP_NO_MORE, smtp_active_hostname); return FALSE; } reserved_host = TRUE; @@ -2507,7 +2507,7 @@ if (!f.sender_host_unknown) LOG_MAIN, "temporarily refused connection from %s: not in " "reserve list and load average = %.2f", host_and_ident(FALSE), (double)load_average/1000.0); - smtp_printf("421 %s: Too much load; please try again later\r\n", FALSE, + smtp_printf("421 %s: Too much load; please try again later\r\n", SP_NO_MORE, smtp_active_hostname); return FALSE; } @@ -2681,7 +2681,7 @@ if (!check_sync()) "synchronization error (input sent without waiting for greeting): " "rejected connection from %s input=\"%s\"", host_and_ident(TRUE), string_printing(string_copyn(smtp_inptr, n))); - smtp_printf("554 SMTP synchronization error\r\n", FALSE); + smtp_printf("554 SMTP synchronization error\r\n", SP_NO_MORE); return FALSE; } @@ -2692,7 +2692,7 @@ smtp_printf("%Y", #ifndef DISABLE_PIPE_CONNECT fl.pipe_connect_acceptable && pipeline_connect_sends(), #else - FALSE, + SP_NO_MORE, #endif ss); @@ -2751,10 +2751,10 @@ if (++synprot_error_count > smtp_max_synprot_errors) if (code > 0) { - smtp_printf("%d%c%s%s%s\r\n", FALSE, code, yield == 1 ? '-' : ' ', + smtp_printf("%d%c%s%s%s\r\n", SP_NO_MORE, code, yield == 1 ? '-' : ' ', data ? data : US"", data ? US": " : US"", errmess); if (yield == 1) - smtp_printf("%d Too many syntax or protocol errors\r\n", FALSE, code); + smtp_printf("%d Too many syntax or protocol errors\r\n", SP_NO_MORE, code); } return yield; @@ -2781,7 +2781,7 @@ Returns: nothing */ void -smtp_respond(uschar* code, int codelen, BOOL final, uschar *msg) +smtp_respond(uschar * code, int codelen, BOOL final, uschar * msg) { int esclen = 0; uschar *esc = US""; @@ -2830,7 +2830,7 @@ for (;;) } else { - smtp_printf("%.3s-%.*s%.*s\r\n", TRUE, code, esclen, esc, (int)(nl - msg), msg); + smtp_printf("%.3s-%.*s%.*s\r\n", SP_MORE, code, esclen, esc, (int)(nl - msg), msg); msg = nl + 1; Uskip_whitespace(&msg); } @@ -2936,7 +2936,7 @@ Returns: 0 in most cases */ int -smtp_handle_acl_fail(int where, int rc, uschar *user_msg, uschar *log_msg) +smtp_handle_acl_fail(int where, int rc, uschar * user_msg, uschar * log_msg) { BOOL drop = rc == FAIL_DROP; int codelen = 3; @@ -3022,7 +3022,7 @@ if (sender_verified_failed && string_sprintf(": %s", sender_verified_failed->message)); if (rc == FAIL && sender_verified_failed->user_message) - smtp_respond(smtp_code, codelen, FALSE, string_sprintf( + smtp_respond(smtp_code, codelen, SR_NOT_FINAL, string_sprintf( testflag(sender_verified_failed, af_verify_pmfail)? "Postmaster verification failed while checking <%s>\n%s\n" "Several RFCs state that you are required to have a postmaster\n" @@ -3054,7 +3054,7 @@ always a 5xx one - see comments at the start of this function. If the original rc was FAIL_DROP we drop the connection and yield 2. */ if (rc == FAIL) - smtp_respond(smtp_code, codelen, TRUE, + smtp_respond(smtp_code, codelen, SR_FINAL, user_msg ? user_msg : US"Administrative prohibition"); /* Send temporary failure response to the command. Don't give any details, @@ -3072,12 +3072,12 @@ else && sender_verified_failed && sender_verified_failed->message ) - smtp_respond(smtp_code, codelen, FALSE, sender_verified_failed->message); + smtp_respond(smtp_code, codelen, SR_NOT_FINAL, sender_verified_failed->message); - smtp_respond(smtp_code, codelen, TRUE, user_msg); + smtp_respond(smtp_code, codelen, SR_FINAL, user_msg); } else - smtp_respond(smtp_code, codelen, TRUE, + smtp_respond(smtp_code, codelen, SR_FINAL, US"Temporary local problem - please try later"); /* Log the incident to the logs that are specified by log_reject_target @@ -3194,7 +3194,7 @@ responses are all internal, they should be reasonable size. */ if (code && defaultrespond) { if (user_msg) - smtp_respond(code, 3, TRUE, user_msg); + smtp_respond(code, 3, SR_FINAL, user_msg); else { gstring * g; @@ -3203,7 +3203,7 @@ if (code && defaultrespond) va_start(ap, defaultrespond); g = string_vformat(NULL, SVFMT_EXTEND|SVFMT_REBUFFER, CS defaultrespond, ap); va_end(ap); - smtp_printf("%s %Y\r\n", FALSE, code, g); + smtp_printf("%s %Y\r\n", SP_NO_MORE, code, g); } mac_smtp_fflush(); } @@ -3360,7 +3360,7 @@ smtp_user_msg(uschar *code, uschar *user_msg) { int len = 3; smtp_message_code(&code, &len, &user_msg, NULL, TRUE); -smtp_respond(code, len, TRUE, user_msg); +smtp_respond(code, len, SR_FINAL, user_msg); } @@ -3495,7 +3495,7 @@ if (f.allow_unqualified_recipient || strcmpic(*recipient, US"postmaster") == 0) *recipient = US rewrite_address_qualify(*recipient, TRUE); return rd; } -smtp_printf("501 %s: recipient address must contain a domain\r\n", FALSE, +smtp_printf("501 %s: recipient address must contain a domain\r\n", SP_NO_MORE, smtp_cmd_data); log_write(L_smtp_syntax_error, LOG_MAIN|LOG_REJECT, "unqualified %s rejected: <%s> %s%s", @@ -3523,9 +3523,9 @@ if ( acl_smtp_quit #endif if (*user_msgp) - smtp_respond(US"221", 3, TRUE, *user_msgp); + smtp_respond(US"221", 3, SR_FINAL, *user_msgp); else - smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname); + smtp_printf("221 %s closing connection\r\n", SP_NO_MORE, smtp_active_hostname); #ifdef SERVERSIDE_CLOSE_NOWAIT # ifndef DISABLE_TLS @@ -3554,7 +3554,7 @@ smtp_rset_handler(void) { HAD(SCH_RSET); incomplete_transaction_log(US"RSET"); -smtp_printf("250 Reset OK\r\n", FALSE); +smtp_printf("250 Reset OK\r\n", SP_NO_MORE); cmd_list[CL_RSET].is_mail_cmd = FALSE; if (chunking_state > CHUNKING_OFFERED) chunking_state = CHUNKING_OFFERED; @@ -3809,7 +3809,7 @@ while (done <= 0) { int rc = smtp_in_auth(au, &smtp_resp, &errmsg); - smtp_printf("%s\r\n", FALSE, smtp_resp); + smtp_printf("%s\r\n", SP_NO_MORE, smtp_resp); if (rc != OK) { uschar * logmsg = NULL; @@ -3870,7 +3870,7 @@ while (done <= 0) if (!check_helo(smtp_cmd_data)) { - smtp_printf("501 Syntactically invalid %s argument(s)\r\n", FALSE, hello); + smtp_printf("501 Syntactically invalid %s argument(s)\r\n", SP_NO_MORE, hello); log_write(0, LOG_MAIN|LOG_REJECT, "rejected %s from %s: syntactically " "invalid argument(s): %s", hello, host_and_ident(FALSE), @@ -3935,7 +3935,7 @@ while (done <= 0) { if (fl.helo_verify_required) { - smtp_printf("%d %s argument does not match calling host\r\n", FALSE, + smtp_printf("%d %s argument does not match calling host\r\n", SP_NO_MORE, tempfail? 451 : 550, hello); log_write(0, LOG_MAIN|LOG_REJECT, "%srejected \"%s %s\" from %s", tempfail? "temporarily " : "", @@ -4288,7 +4288,7 @@ while (done <= 0) done = synprot_error(L_smtp_syntax_error, resp, NULL, errmsg); else { - smtp_printf("%d %s\r\n", FALSE, resp, errmsg); + smtp_printf("%d %s\r\n", SP_NO_MORE, resp, errmsg); log_write(0, LOG_MAIN|LOG_REJECT, "rejected XCLIENT from %s: %s", host_and_ident(FALSE), errmsg); } @@ -4302,7 +4302,7 @@ while (done <= 0) We require that we do; the following HELO/EHLO handling will set sender_helo_name as normal. */ - smtp_printf("%s XCLIENT success\r\n", FALSE, smtp_code); + smtp_printf("%s XCLIENT success\r\n", SP_NO_MORE, smtp_code); } break; /* XCLIENT */ } @@ -4326,7 +4326,7 @@ while (done <= 0) if ( fl.helo_verify_required || verify_check_host(&hosts_require_helo) == OK) { - smtp_printf("503 HELO or EHLO required\r\n", FALSE); + smtp_printf("503 HELO or EHLO required\r\n", SP_NO_MORE); log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no " "HELO/EHLO given", host_and_ident(FALSE)); break; @@ -4353,7 +4353,7 @@ while (done <= 0) if (smtp_mailcmd_max > 0 && smtp_mailcmd_count > smtp_mailcmd_max) { - smtp_printf("421 too many messages in this connection\r\n", FALSE); + smtp_printf("421 too many messages in this connection\r\n", SP_NO_MORE); log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many " "messages in one connection", host_and_ident(TRUE)); break; @@ -4626,7 +4626,7 @@ while (done <= 0) if (thismessage_size_limit > 0 && message_size > thismessage_size_limit) { - smtp_printf("552 Message size exceeds maximum permitted\r\n", FALSE); + smtp_printf("552 Message size exceeds maximum permitted\r\n", SP_NO_MORE); log_write(L_size_reject, LOG_MAIN|LOG_REJECT, "rejected MAIL FROM:<%s> %s: " "message too big: size%s=%d max=%d", @@ -4651,7 +4651,7 @@ while (done <= 0) smtp_check_spool_space && message_size >= 0 ? message_size + 5000 : 0)) { - smtp_printf("452 Space shortage, please try later\r\n", FALSE); + smtp_printf("452 Space shortage, please try later\r\n", SP_NO_MORE); sender_address = NULL; break; } @@ -4673,7 +4673,7 @@ while (done <= 0) } else { - smtp_printf("501 %s: sender address must contain a domain\r\n", FALSE, + smtp_printf("501 %s: sender address must contain a domain\r\n", SP_NO_MORE, smtp_cmd_data); log_write(L_smtp_syntax_error, LOG_MAIN|LOG_REJECT, @@ -4753,7 +4753,7 @@ while (done <= 0) { if (f.smtp_in_pipelining_advertised && last_was_rej_mail) { - smtp_printf("503 sender not yet given\r\n", FALSE); + smtp_printf("503 sender not yet given\r\n", SP_NO_MORE); was_rej_mail = TRUE; } else @@ -4902,7 +4902,7 @@ while (done <= 0) if (recipients_max_reject) { rcpt_fail_count++; - smtp_printf("552 too many recipients\r\n", FALSE); + smtp_printf("552 too many recipients\r\n", SP_NO_MORE); if (!toomany) log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: message " "rejected: sender=<%s> %s", sender_address, host_and_ident(TRUE)); @@ -4910,7 +4910,7 @@ while (done <= 0) else { rcpt_defer_count++; - smtp_printf("452 too many recipients\r\n", FALSE); + smtp_printf("452 too many recipients\r\n", SP_NO_MORE); if (!toomany) log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: excess " "temporarily rejected: sender=<%s> %s", sender_address, @@ -4976,7 +4976,7 @@ while (done <= 0) if (user_msg) smtp_user_msg(US"250", user_msg); else - smtp_printf("250 Accepted\r\n", FALSE); + smtp_printf("250 Accepted\r\n", SP_NO_MORE); rcpt_fail_count++; discarded = TRUE; log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: " @@ -5063,15 +5063,15 @@ while (done <= 0) { uschar *code = US"503"; int len = Ustrlen(rcpt_smtp_response); - smtp_respond(code, 3, FALSE, US"All RCPT commands were rejected with " + smtp_respond(code, 3, SR_NOT_FINAL, US"All RCPT commands were rejected with " "this error:"); /* Responses from smtp_printf() will have \r\n on the end */ if (len > 2 && rcpt_smtp_response[len-2] == '\r') rcpt_smtp_response[len-2] = 0; - smtp_respond(code, 3, FALSE, rcpt_smtp_response); + smtp_respond(code, 3, SR_NOT_FINAL, rcpt_smtp_response); } if (f.smtp_in_pipelining_advertised && last_was_rcpt) - smtp_printf("503 Valid RCPT command must precede %s\r\n", FALSE, + smtp_printf("503 Valid RCPT command must precede %s\r\n", SP_NO_MORE, smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]]); else done = synprot_error(L_smtp_protocol_error, 503, NULL, @@ -5091,7 +5091,7 @@ while (done <= 0) { sender_address = NULL; /* This will allow a new MAIL without RSET */ sender_address_unrewritten = NULL; - smtp_printf("554 Too many recipients\r\n", FALSE); + smtp_printf("554 Too many recipients\r\n", SP_NO_MORE); if (chunking_state > CHUNKING_OFFERED) { @@ -5132,7 +5132,7 @@ while (done <= 0) smtp_user_msg(US"354", user_msg); else smtp_printf( - "354 Enter message, ending with \".\" on a line by itself\r\n", FALSE); + "354 Enter message, ending with \".\" on a line by itself\r\n", SP_NO_MORE); } if (f.bdat_readers_wanted) @@ -5158,7 +5158,7 @@ while (done <= 0) if (!(address = parse_extract_address(smtp_cmd_data, &errmess, &start, &end, &recipient_domain, FALSE))) { - smtp_printf("501 %s\r\n", FALSE, errmess); + smtp_printf("501 %s\r\n", SP_NO_MORE, errmess); break; } @@ -5197,7 +5197,7 @@ while (done <= 0) break; } - smtp_printf("%s\r\n", FALSE, s); + smtp_printf("%s\r\n", SP_NO_MORE, s); } break; } @@ -5325,7 +5325,7 @@ while (done <= 0) if (rc == DEFER) { - smtp_printf("454 TLS currently unavailable\r\n", FALSE); + smtp_printf("454 TLS currently unavailable\r\n", SP_NO_MORE); break; } @@ -5358,15 +5358,15 @@ while (done <= 0) log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s", log_msg); if (user_msg) - smtp_respond(US"221", 3, TRUE, user_msg); + smtp_respond(US"221", 3, SR_FINAL, user_msg); else - smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname); + smtp_printf("221 %s closing connection\r\n", SP_NO_MORE, smtp_active_hostname); log_close_event(US"by QUIT"); done = 2; break; default: - smtp_printf("554 Security failure\r\n", FALSE); + smtp_printf("554 Security failure\r\n", SP_NO_MORE); break; } tls_close(NULL, TLS_SHUTDOWN_NOWAIT); @@ -5394,7 +5394,7 @@ while (done <= 0) case NOOP_CMD: HAD(SCH_NOOP); - smtp_printf("250 OK\r\n", FALSE); + smtp_printf("250 OK\r\n", SP_NO_MORE); break; @@ -5405,23 +5405,23 @@ while (done <= 0) case HELP_CMD: HAD(SCH_HELP); - smtp_printf("214-Commands supported:\r\n214", TRUE); - smtp_printf(" AUTH", TRUE); + smtp_printf("214-Commands supported:\r\n214", SP_MORE); + smtp_printf(" AUTH", SP_MORE); #ifndef DISABLE_TLS if (tls_in.active.sock < 0 && verify_check_host(&tls_advertise_hosts) != FAIL) - smtp_printf(" STARTTLS", TRUE); + smtp_printf(" STARTTLS", SP_MORE); #endif - smtp_printf(" HELO EHLO MAIL RCPT DATA BDAT", TRUE); - smtp_printf(" NOOP QUIT RSET HELP", TRUE); - if (acl_smtp_etrn) smtp_printf(" ETRN", TRUE); - if (acl_smtp_expn) smtp_printf(" EXPN", TRUE); - if (acl_smtp_vrfy) smtp_printf(" VRFY", TRUE); + smtp_printf(" HELO EHLO MAIL RCPT DATA BDAT", SP_MORE); + smtp_printf(" NOOP QUIT RSET HELP", SP_MORE); + if (acl_smtp_etrn) smtp_printf(" ETRN", SP_MORE); + if (acl_smtp_expn) smtp_printf(" EXPN", SP_MORE); + if (acl_smtp_vrfy) smtp_printf(" VRFY", SP_MORE); #ifdef EXPERIMENTAL_XCLIENT if (proxy_session || verify_check_host(&hosts_xclient) != FAIL) - smtp_printf(" XCLIENT", TRUE); + smtp_printf(" XCLIENT", SP_MORE); #endif - smtp_printf("\r\n", FALSE); + smtp_printf("\r\n", SP_NO_MORE); break; @@ -5500,7 +5500,7 @@ while (done <= 0) { log_write(0, LOG_MAIN|LOG_PANIC, "failed to set up ETRN command: %s", error); - smtp_printf("458 Internal failure\r\n", FALSE); + smtp_printf("458 Internal failure\r\n", SP_NO_MORE); break; } } @@ -5531,7 +5531,7 @@ while (done <= 0) debug_printf("ETRN command is: %s\n", etrn_command); debug_printf("ETRN command execution skipped\n"); } - if (user_msg == NULL) smtp_printf("250 OK\r\n", FALSE); + if (user_msg == NULL) smtp_printf("250 OK\r\n", SP_NO_MORE); else smtp_user_msg(US"250", user_msg); break; } @@ -5542,7 +5542,7 @@ while (done <= 0) if (smtp_etrn_serialize && !enq_start(etrn_serialize_key, 1)) { - smtp_printf("458 Already processing %s\r\n", FALSE, smtp_cmd_data); + smtp_printf("458 Already processing %s\r\n", SP_NO_MORE, smtp_cmd_data); break; } @@ -5607,12 +5607,12 @@ while (done <= 0) { log_write(0, LOG_MAIN|LOG_PANIC, "fork of process for ETRN failed: %s", strerror(errno)); - smtp_printf("458 Unable to fork process\r\n", FALSE); + smtp_printf("458 Unable to fork process\r\n", SP_NO_MORE); if (smtp_etrn_serialize) enq_end(etrn_serialize_key); } else if (!user_msg) - smtp_printf("250 OK\r\n", FALSE); + smtp_printf("250 OK\r\n", SP_NO_MORE); else smtp_user_msg(US"250", user_msg); @@ -5632,7 +5632,7 @@ while (done <= 0) done = synprot_error(L_smtp_syntax_error, 0, NULL, /* Just logs */ US"NUL character(s) present (shown as '?')"); smtp_printf("501 NUL characters are not allowed in SMTP commands\r\n", - FALSE); + SP_NO_MORE); break; @@ -5669,7 +5669,7 @@ while (done <= 0) #ifdef SUPPORT_PROXY case PROXY_FAIL_IGNORE_CMD: - smtp_printf("503 Command refused, required Proxy negotiation failed\r\n", FALSE); + smtp_printf("503 Command refused, required Proxy negotiation failed\r\n", SP_NO_MORE); break; #endif diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index efa6004a3..a17597e8b 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -3000,7 +3000,7 @@ exim_gnutls_state_st * state = NULL; if (tls_in.active.sock >= 0) { tls_error(US"STARTTLS received after TLS started", US "", NULL, errstr); - smtp_printf("554 Already in TLS\r\n", FALSE); + smtp_printf("554 Already in TLS\r\n", SP_NO_MORE); return FAIL; } @@ -3079,7 +3079,7 @@ mode, the fflush() happens when smtp_getc() is called. */ if (!state->tlsp->on_connect) { - smtp_printf("220 TLS go ahead\r\n", FALSE); + smtp_printf("220 TLS go ahead\r\n", SP_NO_MORE); fflush(smtp_out); } diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index b02605eae..ef11de593 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -3504,7 +3504,7 @@ static uschar peerdn[256]; if (tls_in.active.sock >= 0) { tls_error(US"STARTTLS received after TLS started", NULL, US"", errstr); - smtp_printf("554 Already in TLS\r\n", FALSE); + smtp_printf("554 Already in TLS\r\n", SP_NO_MORE); return FAIL; } @@ -3624,7 +3624,7 @@ mode, the fflush() happens when smtp_getc() is called. */ SSL_set_session_id_context(ssl, sid_ctx, Ustrlen(sid_ctx)); if (!tls_in.on_connect) { - smtp_printf("220 TLS go ahead\r\n", FALSE); + smtp_printf("220 TLS go ahead\r\n", SP_NO_MORE); fflush(smtp_out); } commit 44e35f5f592b4fb993a6a23ad9e0446af8a6d527 Author: Jeremy Harris Date: Sun Nov 5 21:29:53 2023 +0000 DANE: handle servefail for TLSA during Rverify. Bug 3030 diff --git a/src/src/verify.c b/src/src/verify.c index d8ebf5925..6361aa434 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -677,7 +677,7 @@ coding means skipping this whole loop and doing the append separately. */ sx->conn_args.interface = interface; sx->helo_data = tf->helo_data; sx->conn_args.tblock = addr->transport; - sx->conn_args.sock = -1; + sx->cctx.sock = sx->conn_args.sock = -1; sx->verify = TRUE; tls_retry_connection: @@ -1152,7 +1152,7 @@ no_conn: /* Ensure no cutthrough on multiple verifies that were incompatible */ if (options & vopt_callout_recipsender) cancel_cutthrough_connection(TRUE, US"not usable for cutthrough"); - if (sx->send_quit) + if (sx->send_quit && sx->cctx.sock >= 0) if (smtp_write_command(sx, SCMD_FLUSH, "QUIT\r\n") != -1) /* Wait a short time for response, and discard it */ smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', 1); commit 37b849dca4dfd855212a763662825e967a4d77b1 Author: Jeremy Harris Date: Tue Nov 7 15:02:18 2023 +0000 OpenSSL: fix non-DANE build diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index ef11de593..851ac77c5 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -2605,7 +2605,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) asking for certificate-status under DANE, so this callback won't run for that combination. It still will for non-DANE. */ -#ifdef EXIM_HAVE_OPENSSL_OCSP_RESP_GET0_SIGNER +#if defined(EXIM_HAVE_OPENSSL_OCSP_RESP_GET0_SIGNER) && defined(SUPPORT_DANE) X509 * signer; if ( tls_out.dane_verified commit eb09d0da1fb995ad88f9a1c2998766c3e530be68 Author: Jeremy Harris Date: Tue Nov 7 19:38:22 2023 +0000 Fix use of empty log_reject_target. Bug 3039 Broken-by: 4243a209fd94 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index c565d522d..e19c86ff8 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -2051,16 +2051,19 @@ else DEBUG(D_receive) static void log_connect_tls_drop(const uschar * what, const uschar * log_msg) { -gstring * g = s_tlslog(NULL); -uschar * tls = string_from_gstring(g); - -log_write(L_connection_reject, - log_reject_target, "%s%s%s dropped by %s%s%s", - LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", - host_and_ident(TRUE), - tls ? tls : US"", - what, - log_msg ? US": " : US"", log_msg); +if (log_reject_target) + { + gstring * g = s_tlslog(NULL); + uschar * tls = string_from_gstring(g); + + log_write(L_connection_reject, + log_reject_target, "%s%s%s dropped by %s%s%s", + LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", + host_and_ident(TRUE), + tls ? tls : US"", + what, + log_msg ? US": " : US"", log_msg); + } } @@ -3085,7 +3088,7 @@ else the connection is not forcibly to be dropped, return 0. Otherwise, log why it is closing if required and return 2. */ -if (log_reject_target != 0) +if (log_reject_target) { #ifndef DISABLE_TLS gstring * g = s_tlslog(NULL); commit caf57fe7eb5018b8df196e6d9f99586232798eb3 Author: Jeremy Harris Date: Wed Nov 8 14:22:37 2023 +0000 typoes diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 851ac77c5..237303ba9 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -77,9 +77,9 @@ change this guard and punt the issue for a while longer. */ # define EXIM_HAVE_OPENSSL_KEYLOG # define EXIM_HAVE_OPENSSL_CIPHER_GET_ID # define EXIM_HAVE_SESSION_TICKET -# define EXIM_HAVE_OPESSL_TRACE -# define EXIM_HAVE_OPESSL_GET0_SERIAL -# define EXIM_HAVE_OPESSL_OCSP_RESP_GET0_CERTS +# define EXIM_HAVE_OPENSSL_TRACE +# define EXIM_HAVE_OPENSSL_GET0_SERIAL +# define EXIM_HAVE_OPENSSL_OCSP_RESP_GET0_CERTS # define EXIM_HAVE_SSL_GET0_VERIFIED_CHAIN # ifndef DISABLE_OCSP # define EXIM_HAVE_OCSP @@ -1756,7 +1756,7 @@ level. */ DEBUG(D_tls) { SSL_CTX_set_info_callback(ctx, info_callback); -#if defined(EXIM_HAVE_OPESSL_TRACE) && !defined(OPENSSL_NO_SSL_TRACE) +#if defined(EXIM_HAVE_OPENSSL_TRACE) && !defined(OPENSSL_NO_SSL_TRACE) /* this needs a debug build of OpenSSL */ SSL_CTX_set_msg_callback(ctx, SSL_trace); #endif @@ -2442,7 +2442,7 @@ tls_in.ocsp = OCSP_NOT_RESP; if (!olist) return SSL_TLSEXT_ERR_NOACK; -#ifdef EXIM_HAVE_OPESSL_GET0_SERIAL +#ifdef EXIM_HAVE_OPENSSL_GET0_SERIAL { const X509 * cert_sent = SSL_get_certificate(s); const ASN1_INTEGER * cert_serial = X509_get0_serialNumber(cert_sent); @@ -2646,7 +2646,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) debug_printf("certs contained in basicresp:\n"); x509_stack_dump_cert_s_names( -#ifdef EXIM_HAVE_OPESSL_OCSP_RESP_GET0_CERTS +#ifdef EXIM_HAVE_OPENSSL_OCSP_RESP_GET0_CERTS OCSP_resp_get0_certs(bs) #else bs->certs commit 4f780c09d2ab95bd9562ebe307a01043933adcd9 Author: Jeremy Harris Date: Fri Nov 10 14:37:23 2023 +0000 fix doubled logging of message_id diff --git a/src/src/receive.c b/src/src/receive.c index 8190c5941..041898a6b 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -3380,8 +3380,8 @@ if (extract_recip && (bad_addresses || recipients_count == 0)) } } - log_write(0, LOG_MAIN|LOG_PANIC, "%s %s found in headers", - message_id, bad_addresses ? "bad addresses" : "no recipients"); + log_write(0, LOG_MAIN|LOG_PANIC, "%s found in headers", + bad_addresses ? "bad addresses" : "no recipients"); fseek(spool_data_file, (long int)spool_data_start_offset(message_id), SEEK_SET); commit 5d5ad9fb16a2511ff2e0e7d4528d399f06f608da Author: Jeremy Harris Date: Mon Nov 13 18:12:31 2023 +0000 TLS: fix resumption for TLS-on-connect diff --git a/src/src/macros.h b/src/src/macros.h index 969393561..e2c1d0f94 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1103,14 +1103,22 @@ should not be one active. */ #define RESUME_USED BIT(4) #define RESUME_DECODE_STRING \ - US"not requested or offered : 0x02 :client requested, no server ticket" \ - ": 0x04 : 0x05 : 0x06 :client offered session, no server action" \ - ": 0x08 :no client request: 0x0A :client requested new ticket, server provided" \ - ": 0x0C :client offered session, not used: 0x0E :client offered session, server only provided new ticket" \ - ": 0x10 :session resumed unasked: 0x12 :session resumed unasked" \ - ": 0x14 : 0x15 : 0x16 :session resumed" \ - ": 0x18 :session resumed unasked: 0x1A :session resumed unasked" \ - ": 0x1C :session resumed: 0x1E :session resumed, also new ticket" + US"not requested or offered" \ + ": 0x02 :client requested, no server ticket" \ + ": 0x04 : 0x05 " \ + ": 0x06 :client offered session, no server action" \ + ": 0x08 :no client request" \ + ": 0x0A :client requested new ticket, server provided" \ + ": 0x0C :client offered session, not used" \ + ": 0x0E :client offered session, server only provided new ticket" \ + ": 0x10 :session resumed unasked" \ + ": 0x12 :session resumed unasked" \ + ": 0x14 : 0x15" \ + ": 0x16 :session resumed" \ + ": 0x18 :session resumed unasked" \ + ": 0x1A :session resumed unasked" \ + ": 0x1C :session resumed" \ + ": 0x1E :session resumed, also new ticket" /* Flags for string_vformat */ #define SVFMT_EXTEND BIT(0) diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index a17597e8b..56ea93935 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2851,7 +2851,7 @@ static int tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when, unsigned incoming, const gnutls_datum_t * msg) { -DEBUG(D_tls) debug_printf("newticket cb\n"); +DEBUG(D_tls) debug_printf("newticket cb (on server)\n"); tls_in.resumption |= RESUME_CLIENT_REQUESTED; return 0; } @@ -2888,9 +2888,12 @@ tls_server_resume_posthandshake(exim_gnutls_state_st * state) { if (gnutls_session_resumption_requested(state->session)) { - /* This tells us the client sent a full ticket. We use a + /* This tells us the client sent a full (?) ticket. We use a callback on session-ticket request, elsewhere, to tell - if a client asked for a ticket. */ + if a client asked for a ticket. + XXX As of GnuTLS 3.0.1 it seems to be returning true even for + a pure ticket-req (a zero-length Session Ticket extension + in the Client Hello, for 1.2) which mucks up our logic. */ tls_in.resumption |= RESUME_CLIENT_SUGGESTED; DEBUG(D_tls) debug_printf("client requested resumption\n"); @@ -3319,7 +3322,8 @@ tls_retrieve_session(tls_support * tlsp, gnutls_session_t session, tlsp->resumption = RESUME_SUPPORTED; if (!conn_args->have_lbserver) - { DEBUG(D_tls) debug_printf("resumption not supported on continued-connection\n"); } + { DEBUG(D_tls) debug_printf( + "resumption not supported: no LB detection done (continued-conn?)\n"); } else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, conn_args->host) == OK) { dbdata_tls_session * dt; @@ -3347,6 +3351,7 @@ else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, conn_args->host dbfn_close(dbm_file); } } +else DEBUG(D_tls) debug_printf("no resumption for this host\n"); } @@ -3374,7 +3379,7 @@ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SESSION_TICKET) int dlen = sizeof(dbdata_tls_session) + tkt.size; dbdata_tls_session * dt = store_get(dlen, GET_TAINTED); - DEBUG(D_tls) debug_printf("session data size %u\n", (unsigned)tkt.size); + DEBUG(D_tls) debug_printf(" session data size %u\n", (unsigned)tkt.size); memcpy(dt->session, tkt.data, tkt.size); gnutls_free(tkt.data); @@ -3385,11 +3390,15 @@ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SESSION_TICKET) dbfn_close(dbm_file); DEBUG(D_tls) - debug_printf("wrote session db (len %u)\n", (unsigned)dlen); + debug_printf(" wrote session db (len %u)\n", (unsigned)dlen); } } - else DEBUG(D_tls) - debug_printf("extract session data: %s\n", US gnutls_strerror(rc)); + else + { DEBUG(D_tls) + debug_printf(" extract session data: %s\n", US gnutls_strerror(rc)); + } + else DEBUG(D_tls) + debug_printf(" host not resmable; not saving ticket\n"); } } @@ -3406,7 +3415,7 @@ tls_client_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when, exim_gnutls_state_st * state = gnutls_session_get_ptr(sess); tls_support * tlsp = state->tlsp; -DEBUG(D_tls) debug_printf("newticket cb\n"); +DEBUG(D_tls) debug_printf("newticket cb (on client)\n"); if (!tlsp->ticket_received) tls_save_session(tlsp, sess, state->host); diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index af2e1f2dd..8c00a1ef2 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -203,9 +203,6 @@ smtp_transport_options_block smtp_transport_option_defaults = { .tls_tempfail_tryclear = TRUE, .tls_try_verify_hosts = US"*", .tls_verify_cert_hostnames = US"*", -# ifndef DISABLE_TLS_RESUME - .host_name_extract = US"${if and {{match{$host}{.outlook.com\\$}} {match{$item}{\\N^250-([\\w.]+)\\s\\N}}} {$1}}", -# endif #endif #ifdef SUPPORT_I18N .utf8_downconvert = US"-1", @@ -352,7 +349,7 @@ Returns: nothing void smtp_transport_init(transport_instance *tblock) { -smtp_transport_options_block *ob = SOB tblock->options_block; +smtp_transport_options_block * ob = SOB tblock->options_block; int old_pool = store_pool; /* Retry_use_local_part defaults FALSE if unset */ @@ -769,7 +766,7 @@ return TRUE; resumption when such servers do not share a session-cache */ static void -ehlo_response_lbserver(smtp_context * sx, smtp_transport_options_block * ob) +ehlo_response_lbserver(smtp_context * sx, const uschar * name_extract) { #if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME) const uschar * s; @@ -778,7 +775,7 @@ uschar * save_item = iterate_item; if (sx->conn_args.have_lbserver) return; iterate_item = sx->buffer; -s = expand_cstring(ob->host_name_extract); +s = expand_cstring(name_extract); iterate_item = save_item; sx->conn_args.host_lbserver = s && !*s ? NULL : s; sx->conn_args.have_lbserver = TRUE; @@ -1067,6 +1064,8 @@ sx->pending_EHLO = FALSE; if (pending_BANNER) { + const uschar * s; + DEBUG(D_transport) debug_printf("%s expect banner\n", __FUNCTION__); (*countp)--; if (!smtp_reap_banner(sx)) @@ -1076,7 +1075,10 @@ if (pending_BANNER) goto fail; } /*XXX EXPERIMENTAL_ESMTP_LIMITS ? */ - ehlo_response_lbserver(sx, sx->conn_args.ob); + + s = ((smtp_transport_options_block *)sx->conn_args.ob)->host_name_extract; + if (!s) s = HNE_DEFAULT; + ehlo_response_lbserver(sx, s); } if (pending_EHLO) @@ -2474,10 +2476,20 @@ goto SEND_QUIT; #ifndef DISABLE_TLS if (sx->smtps) { + const uschar * s; + smtp_peer_options |= OPTION_TLS; suppress_tls = FALSE; ob->tls_tempfail_tryclear = FALSE; smtp_command = US"SSL-on-connect"; + + /* Having no EHLO response yet, cannot peek there for a servername to detect + an LB. Call this anyway, so that a dummy host_name_extract option value can + force resumption attempts. */ + + if (!(s = ob->host_name_extract)) s = US"never-LB"; + ehlo_response_lbserver(sx, s); + goto TLS_NEGOTIATE; } #endif @@ -2565,6 +2577,8 @@ goto SEND_QUIT; if (!sx->early_pipe_active) #endif { + const uschar * s; + sx->peer_offered = ehlo_response(sx->buffer, OPTION_TLS /* others checked later */ #ifndef DISABLE_PIPE_CONNECT @@ -2600,7 +2614,8 @@ goto SEND_QUIT; } } #endif - ehlo_response_lbserver(sx, ob); + if (!(s = ob->host_name_extract)) s = HNE_DEFAULT; + ehlo_response_lbserver(sx, s); } /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */ diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index cb1d72625..0d15b9626 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -109,6 +109,7 @@ typedef struct { uschar *tls_privatekey; uschar *tls_require_ciphers; # ifndef DISABLE_TLS_RESUME +# define HNE_DEFAULT US"${if and {{match{$host}{.outlook.com\\$}} {match{$item}{\\N^250-([\\w.]+)\\s\\N}}} {$1}}" uschar *host_name_extract; uschar *tls_resumption_hosts; # endif commit fba5586e6d47f55e024e97681c166e857c4f3d1c Author: Jeremy Harris Date: Tue Nov 14 14:08:36 2023 +0000 constification diff --git a/src/src/deliver.c b/src/src/deliver.c index fa624f9de..9d459167e 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -6388,7 +6388,7 @@ Returns: When the global variable mua_wrapper is FALSE: */ int -deliver_message(uschar * id, BOOL forced, BOOL give_up) +deliver_message(const uschar * id, BOOL forced, BOOL give_up) { int i, rc; int final_yield = DELIVER_ATTEMPTED_NORMAL; diff --git a/src/src/exim.c b/src/src/exim.c index 118fe5c7c..3cc2fa2fb 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1537,7 +1537,7 @@ Returns: DOES NOT RETURN */ static void -exim_usage(uschar *progname) +exim_usage(const uschar * progname) { /* Handle specific program invocation variants */ @@ -1744,9 +1744,9 @@ Returns: EXIT_SUCCESS if terminated successfully */ int -main(int argc, char **cargv) +main(int argc, char ** cargv) { -uschar **argv = USS cargv; +const uschar ** argv = CUSS cargv; int arg_receive_timeout = -1; int arg_smtp_receive_timeout = -1; int arg_error_handling = error_handling; @@ -1795,18 +1795,18 @@ BOOL verify_address_mode = FALSE; BOOL verify_as_sender = FALSE; BOOL rcpt_verify_quota = FALSE; BOOL version_printed = FALSE; -uschar *alias_arg = NULL; -uschar *called_as = US""; -uschar *cmdline_syslog_name = NULL; -uschar *start_queue_run_id = NULL; -uschar *stop_queue_run_id = NULL; -uschar *expansion_test_message = NULL; +const uschar *alias_arg = NULL; +const uschar *called_as = US""; +const uschar *cmdline_syslog_name = NULL; +const uschar *start_queue_run_id = NULL; +const uschar *stop_queue_run_id = NULL; +const uschar *expansion_test_message = NULL; const uschar *ftest_domain = NULL; const uschar *ftest_localpart = NULL; const uschar *ftest_prefix = NULL; const uschar *ftest_suffix = NULL; uschar *log_oneline = NULL; -uschar *malware_test_file = NULL; +const uschar *malware_test_file = NULL; uschar *real_sender_address; uschar *originator_home = US"/"; size_t sz; @@ -2152,8 +2152,8 @@ on the second character (the one after '-'), to save some effort. */ for (i = 1; i < argc; i++) { BOOL badarg = FALSE; - uschar * arg = argv[i]; - uschar * argrest; + const uschar * arg = argv[i]; + const uschar * argrest; uschar switchchar; /* An argument not starting with '-' is the start of a recipients list; @@ -2347,7 +2347,7 @@ on the second character (the one after '-'), to save some effort. */ case 'I': if (Ustrlen(argrest) >= 1 && *argrest == ':') { - uschar *p = argrest+1; + const uschar * p = argrest+1; info_flag = CMDINFO_HELP; if (Ustrlen(p)) if (strcmpic(p, CUS"sieve") == 0) @@ -2674,9 +2674,9 @@ on the second character (the one after '-'), to save some effort. */ #else { int ptr = 0; - macro_item *m; + macro_item * m; uschar name[24]; - uschar *s = argrest; + const uschar * s = argrest; opt_D_used = TRUE; while (isspace(*s)) s++; @@ -2833,7 +2833,7 @@ on the second character (the one after '-'), to save some effort. */ *(sender_address = store_get(1, GET_UNTAINTED)) = '\0'; /* Ensure writeable memory */ else { - uschar * temp = argrest + Ustrlen(argrest) - 1; + const uschar * temp = argrest + Ustrlen(argrest) - 1; while (temp >= argrest && isspace(*temp)) temp--; if (temp >= argrest && *temp == '.') f_end_dot = TRUE; allow_domain_literals = TRUE; @@ -3272,7 +3272,7 @@ on the second character (the one after '-'), to save some effort. */ /* -oB: Set a connection message max value for remote deliveries */ case 'B': { - uschar * p = argrest; + const uschar * p = argrest; if (!*p) if (i+1 < argc && isdigit((argv[i+1][0]))) p = argv[++i]; @@ -4432,7 +4432,7 @@ if (bi_option) if (bi_command && *bi_command) { int i = 0; - uschar *argv[3]; + const uschar * argv[3]; argv[i++] = bi_command; /* nonexpanded option so assume untainted */ if (alias_arg) argv[i++] = alias_arg; argv[i++] = NULL; @@ -4761,7 +4761,7 @@ if (rcpt_verify_quota) exim_fail("exim: missing recipient for quota check\n"); else { - verify_quota(argv[recipients_arg]); + verify_quota(US argv[recipients_arg]); /*XXX we lose track of const here */ exim_exit(EXIT_SUCCESS); } @@ -5768,7 +5768,7 @@ for (BOOL more = TRUE; more; ) { int rcount = 0; int count = argc - recipients_arg; - uschar **list = argv + recipients_arg; + const uschar ** list = argv + recipients_arg; /* These options cannot be changed dynamically for non-SMTP messages */ diff --git a/src/src/filtertest.c b/src/src/filtertest.c index 2426f7feb..2af5f87c2 100644 --- a/src/src/filtertest.c +++ b/src/src/filtertest.c @@ -164,7 +164,7 @@ Returns: TRUE if no errors */ BOOL -filter_runtest(int fd, uschar *filename, BOOL is_system, BOOL dot_ended) +filter_runtest(int fd, const uschar * filename, BOOL is_system, BOOL dot_ended) { int rc, filter_type; BOOL yield; diff --git a/src/src/functions.h b/src/src/functions.h index 39119ca09..ba4fd215c 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -218,7 +218,7 @@ extern void delete_pid_file(void); extern void deliver_local(address_item *, BOOL); extern address_item *deliver_make_addr(uschar *, BOOL); extern void delivery_log(int, address_item *, int, uschar *); -extern int deliver_message(uschar *, BOOL, BOOL); +extern int deliver_message(const uschar *, BOOL, BOOL); extern void deliver_msglog(const char *, ...) PRINTF_FUNCTION(1,2); extern void deliver_set_expansions(address_item *); extern int deliver_split_address(address_item *); @@ -284,7 +284,7 @@ extern BOOL fd_ready(int, time_t); extern int filter_interpret(const uschar *, int, address_item **, uschar **); extern BOOL filter_personal(string_item *, BOOL); -extern BOOL filter_runtest(int, uschar *, BOOL, BOOL); +extern BOOL filter_runtest(int, const uschar *, BOOL, BOOL); extern BOOL filter_system_interpret(address_item **, uschar **); extern uschar * fn_hdrs_added(void); @@ -345,7 +345,7 @@ extern uschar *macros_expand(int, int *, BOOL *); extern void mainlog_close(void); #ifdef WITH_CONTENT_SCAN extern int malware(const uschar *, BOOL, int); -extern int malware_in_file(uschar *); +extern int malware_in_file(const uschar *); extern void malware_init(void); extern gstring * malware_show_supported(gstring *); #endif @@ -408,15 +408,15 @@ extern BOOL proxy_protocol_host(void); extern void proxy_protocol_setup(void); #endif -extern BOOL queue_action(uschar *, int, uschar **, int, int); +extern BOOL queue_action(const uschar *, int, const uschar **, int, int); extern void queue_check_only(void); extern unsigned queue_count(void); extern unsigned queue_count_cached(void); -extern void queue_list(int, uschar **, int); +extern void queue_list(int, const uschar **, int); #ifndef DISABLE_QUEUE_RAMP extern void queue_notify_daemon(const uschar * hostname); #endif -extern void queue_run(qrunner *, uschar *, uschar *, BOOL); +extern void queue_run(qrunner *, const uschar *, const uschar *, BOOL); extern int random_number(int); extern const uschar *rc_to_string(int); @@ -430,7 +430,7 @@ extern void readconf_driver_init(uschar *, driver_instance **, extern uschar *readconf_find_option(void *); extern void readconf_main(BOOL); extern void readconf_options_from_list(optionlist *, unsigned, const uschar *, uschar *); -extern BOOL readconf_print(const uschar *, uschar *, BOOL); +extern BOOL readconf_print(const uschar *, const uschar *, BOOL); extern uschar *readconf_printtime(int); extern const uschar *readconf_readname(uschar *, int, const uschar *); extern int readconf_readtime(const uschar *, int, BOOL); @@ -503,7 +503,7 @@ extern int sieve_interpret(const uschar *, int, const uschar *, const uschar *, const uschar *, const uschar *, address_item **, uschar **); extern void sigalrm_handler(int); -extern void single_queue_run(qrunner *, uschar *, uschar *); +extern void single_queue_run(qrunner *, const uschar *, const uschar *); extern int smtp_boundsock(smtp_connect_args *); extern void smtp_closedown(uschar *); extern void smtp_command_timeout_exit(void) NORETURN; @@ -544,12 +544,12 @@ extern int spam(const uschar **); extern FILE *spool_mbox(unsigned long *, const uschar *, uschar **); #endif extern void spool_clear_header_globals(void); -extern BOOL spool_move_message(uschar *, uschar *, uschar *, uschar *); -extern int spool_open_datafile(uschar *); +extern BOOL spool_move_message(const uschar *, const uschar *, const uschar *, const uschar *); +extern int spool_open_datafile(const uschar *); extern int spool_open_temp(uschar *); extern int spool_read_header(uschar *, BOOL, BOOL); extern uschar *spool_sender_from_msgid(const uschar *); -extern int spool_write_header(uschar *, int, uschar **); +extern int spool_write_header(const uschar *, int, uschar **); extern int stdin_getc(unsigned); extern int stdin_feof(void); extern int stdin_ferror(void); @@ -1144,7 +1144,7 @@ return string_sprintf("%s/%s/%s/%s", # endif static inline uschar * -spool_q_sname(const uschar * purpose, const uschar * q, uschar * subdir) +spool_q_sname(const uschar * purpose, const uschar * q, const uschar * subdir) { return string_sprintf("%s%s%s%s%s", q, *q ? "/" : "", @@ -1153,7 +1153,7 @@ return string_sprintf("%s%s%s%s%s", } static inline uschar * -spool_sname(const uschar * purpose, uschar * subdir) +spool_sname(const uschar * purpose, const uschar * subdir) { return spool_q_sname(purpose, queue_name, subdir); } diff --git a/src/src/globals.c b/src/src/globals.c index e94bef75c..46ca72f20 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -726,7 +726,7 @@ gid_t config_gid = CONFIGURE_GROUP; #else gid_t config_gid = 0; #endif -uschar *config_main_filelist = US CONFIGURE_FILE +const uschar * config_main_filelist = US CONFIGURE_FILE "\0<-----------Space to patch configure_filename->"; uschar *config_main_filename = NULL; uschar *config_main_directory = NULL; @@ -939,8 +939,8 @@ uschar *fake_response_text = US"Your message has been rejected but is " int filter_n[FILTER_VARIABLE_COUNT]; int filter_sn[FILTER_VARIABLE_COUNT]; int filter_test = FTEST_NONE; -uschar *filter_test_sfile = NULL; -uschar *filter_test_ufile = NULL; +const uschar * filter_test_sfile = NULL; +const uschar * filter_test_ufile = NULL; uschar *filter_thisaddress = NULL; int finduser_retries = 0; uid_t fixed_never_users[] = { FIXED_NEVER_USERS }; @@ -1185,7 +1185,7 @@ uschar *message_size_limit = US"50M"; int message_utf8_downconvert = 0; /* -1 ifneeded; 0 never; 1 always */ #endif uschar message_subdir[2] = { 0, 0 }; -uschar *message_reference = NULL; +const uschar *message_reference= NULL; /* MIME ACL expandables */ #ifdef WITH_CONTENT_SCAN @@ -1219,7 +1219,7 @@ uschar *originator_login = NULL; uschar *originator_name = NULL; uid_t originator_uid; uschar *override_local_interfaces = NULL; -uschar *override_pid_file_path = NULL; +const uschar *override_pid_file_path = NULL; BOOL panic_coredump = FALSE; pcre2_general_context * pcre_gen_ctx = NULL; @@ -1229,7 +1229,7 @@ pcre2_general_context * pcre_mlc_ctx = NULL; pcre2_compile_context * pcre_mlc_cmp_ctx = NULL; uschar *percent_hack_domains = NULL; -uschar *pid_file_path = US PID_FILE_PATH +const uschar *pid_file_path = US PID_FILE_PATH "\0<--------------Space to patch pid_file_path->"; #ifndef DISABLE_PIPE_CONNECT uschar *pipe_connect_advertise_hosts = US"*"; @@ -1485,7 +1485,7 @@ uschar *sending_ip_address = NULL; int sending_port = -1; SIGNAL_BOOL sigalrm_seen = FALSE; const uschar *sigalarm_setter = NULL; -uschar **sighup_argv = NULL; +const uschar **sighup_argv = NULL; int slow_lookup_log = 0; /* millisecs, zero disables */ int smtp_accept_count = 0; int smtp_accept_max = 20; @@ -1572,7 +1572,7 @@ int string_datestamp_type = -1; const uschar *submission_domain = NULL; const uschar *submission_name = NULL; int syslog_facility = LOG_MAIL; -uschar *syslog_processname = US"exim"; +const uschar *syslog_processname= US"exim"; uschar *system_filter = NULL; uschar *system_filter_directory_transport = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index 6ec4e619d..9ec44487f 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -438,7 +438,7 @@ extern FILE *config_file; /* Configuration file */ extern const uschar *config_filename; /* Configuration file name */ extern gid_t config_gid; /* Additional group owner */ extern int config_lineno; /* Line number */ -extern uschar *config_main_filelist; /* List of possible config files */ +extern const uschar *config_main_filelist; /* List of possible config files */ extern uschar *config_main_filename; /* File name actually used */ extern uschar *config_main_directory; /* Directory where the main config file was found */ extern uid_t config_uid; /* Additional owner */ @@ -625,8 +625,8 @@ extern uschar *fake_response_text; /* User defined message for the above. De extern int filter_n[FILTER_VARIABLE_COUNT]; /* filter variables */ extern int filter_sn[FILTER_VARIABLE_COUNT]; /* variables set by system filter */ extern int filter_test; /* Filter test type */ -extern uschar *filter_test_sfile; /* System filter test file */ -extern uschar *filter_test_ufile; /* User filter test file */ +extern const uschar *filter_test_sfile;/* System filter test file */ +extern const uschar *filter_test_ufile;/* User filter test file */ extern uschar *filter_thisaddress; /* For address looping */ extern int finduser_retries; /* Retry count for getpwnam() */ extern uid_t fixed_never_users[]; /* Can't be overridden */ @@ -755,7 +755,7 @@ extern int message_utf8_downconvert; /* convert from utf8 */ const extern pcre2_code *regex_UTF8; /* For recognizing SMTPUTF8 settings */ #endif extern uschar message_subdir[]; /* Subdirectory for messages */ -extern uschar *message_reference; /* Reference for error messages */ +extern const uschar *message_reference;/* Reference for error messages */ /* MIME ACL expandables */ #ifdef WITH_CONTENT_SCAN @@ -798,7 +798,7 @@ extern uschar *originator_login; /* Login of same */ extern uschar *originator_name; /* Full name of same */ extern uid_t originator_uid; /* Uid of ditto */ extern uschar *override_local_interfaces; /* Value of -oX argument */ -extern uschar *override_pid_file_path; /* Value of -oP argument */ +extern const uschar *override_pid_file_path; /* Value of -oP argument */ extern BOOL panic_coredump; /* SEGV rather than exit, on LOG_PANIC_DIE */ extern pcre2_general_context * pcre_gen_ctx; /* pcre memory management */ @@ -808,7 +808,7 @@ extern pcre2_general_context * pcre_mlc_ctx; extern pcre2_compile_context * pcre_mlc_cmp_ctx; extern uschar *percent_hack_domains; /* Local domains for which '% operates */ -extern uschar *pid_file_path; /* For writing daemon pids */ +extern const uschar *pid_file_path; /* For writing daemon pids */ #ifndef DISABLE_PIPE_CONNECT extern uschar *pipe_connect_advertise_hosts; /* for banner/EHLO pipelining */ #endif @@ -970,7 +970,7 @@ extern uschar *sending_ip_address; /* Address of outgoing (SMTP) interface * extern int sending_port; /* Port of outgoing interface */ extern SIGNAL_BOOL sigalrm_seen; /* Flag for sigalrm_handler */ extern const uschar *sigalarm_setter; /* For debug, set to callpoint of alarm() */ -extern uschar **sighup_argv; /* Args for re-execing after SIGHUP */ +extern const uschar **sighup_argv; /* Args for re-execing after SIGHUP */ extern int slow_lookup_log; /* Log DNS lookups taking longer than N millisecs */ extern int smtp_accept_count; /* Count of connections */ extern BOOL smtp_accept_keepalive; /* Set keepalive on incoming */ @@ -1065,7 +1065,7 @@ extern const uschar *submission_name; /* User name set from ACL */ extern BOOL syslog_duplication; /* FALSE => no duplicate logging */ extern int syslog_facility; /* As defined by Syslog.h */ extern BOOL syslog_pid; /* TRUE if PID on syslogs */ -extern uschar *syslog_processname; /* 'ident' param to openlog() */ +extern const uschar *syslog_processname; /* 'ident' param to openlog() */ extern BOOL syslog_timestamp; /* TRUE if time on syslogs */ extern uschar *system_filter; /* Name of system filter file */ diff --git a/src/src/malware.c b/src/src/malware.c index 9455d4769..760278079 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -2238,7 +2238,7 @@ Returns: Exim message processing code (OK, FAIL, DEFER, ...) where true means malware was found (condition applies) */ int -malware_in_file(uschar *eml_filename) +malware_in_file(const uschar * eml_filename) { uschar message_id_buf[64]; int ret; diff --git a/src/src/queue.c b/src/src/queue.c index fa4fc0aec..cfe87e953 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -354,7 +354,7 @@ Returns: nothing */ void -queue_run(qrunner * q, uschar * start_id, uschar * stop_id, BOOL recurse) +queue_run(qrunner * q, const uschar * start_id, const uschar * stop_id, BOOL recurse) { BOOL force_delivery = q->queue_run_force || deliver_selectstring || deliver_selectstring_sender; @@ -813,7 +813,7 @@ if (!recurse) void -single_queue_run(qrunner * q, uschar * start_id, uschar * stop_id) +single_queue_run(qrunner * q, const uschar * start_id, const uschar * stop_id) { DEBUG(D_queue_run) debug_printf("Single queue run%s%s%s%s\n", start_id ? US" starting at " : US"", @@ -919,7 +919,7 @@ Returns: nothing */ void -queue_list(int option, uschar ** list, int count) +queue_list(int option, const uschar ** list, int count) { int subcount; int now = (int)time(NULL); @@ -1093,7 +1093,7 @@ Returns: FALSE if there was any problem */ BOOL -queue_action(uschar * id, int action, uschar ** argv, int argc, +queue_action(const uschar * id, int action, const uschar ** argv, int argc, int recipients_arg) { BOOL yield = TRUE; diff --git a/src/src/readconf.c b/src/src/readconf.c index e77458d68..bbcca87f7 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -2741,7 +2741,7 @@ Returns: Boolean success */ BOOL -readconf_print(const uschar *name, uschar *type, BOOL no_labels) +readconf_print(const uschar * name, const uschar * type, BOOL no_labels) { BOOL names_only = FALSE; optionlist *ol2 = NULL; @@ -3121,8 +3121,8 @@ readconf_main(BOOL nowarn) { int sep = 0; struct stat statbuf; -uschar *s, *filename; -const uschar *list = config_main_filelist; +uschar * s, * filename; +const uschar * list = config_main_filelist; /* Loop through the possible file names */ @@ -3459,7 +3459,7 @@ leading "log_". */ if (syslog_facility_str) { int i; - uschar *s = syslog_facility_str; + uschar * s = syslog_facility_str; if ((Ustrlen(syslog_facility_str) >= 4) && (strncmpic(syslog_facility_str, US"log_", 4) == 0)) @@ -3481,10 +3481,11 @@ if (syslog_facility_str) if (*pid_file_path) { - if (!(s = expand_string(pid_file_path))) + const uschar * t = expand_cstring(pid_file_path); + if (!t) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path " "\"%s\": %s", pid_file_path, expand_string_message); - pid_file_path = s; + pid_file_path = t; } /* Set default value of process_log_path */ diff --git a/src/src/spool_in.c b/src/src/spool_in.c index 737a01cdd..588effd2c 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -36,7 +36,7 @@ Side effect: message_subdir is set for the (possibly split) spool directory */ int -spool_open_datafile(uschar * id) +spool_open_datafile(const uschar * id) { struct stat statbuf; flock_t lock_data; diff --git a/src/src/spool_out.c b/src/src/spool_out.c index 9c5a683e3..f3373faed 100644 --- a/src/src/spool_out.c +++ b/src/src/spool_out.c @@ -152,7 +152,7 @@ Returns: the size of the header texts on success; */ int -spool_write_header(uschar * id, int where, uschar ** errmsg) +spool_write_header(const uschar * id, int where, uschar ** errmsg) { int fd, size_correction; FILE * fp; @@ -444,7 +444,7 @@ start-up time. Arguments: dir base directory name - dq destiinationqueue name + dq destination queue name subdir subdirectory name id message id suffix suffix to add to id @@ -457,8 +457,8 @@ Returns: TRUE if all went well */ static BOOL -make_link(uschar * dir, uschar * dq, uschar * subdir, uschar * id, uschar * suffix, - uschar * from, uschar * to, BOOL noentok) +make_link(const uschar * dir, const uschar * dq, const uschar * subdir, const uschar * id, + const uschar * suffix, const uschar * from, const uschar * to, BOOL noentok) { uschar * fname = spool_fname(string_sprintf("%s%s", from, dir), subdir, id, suffix); uschar * tname = spool_q_fname(string_sprintf("%s%s", to, dir), dq, subdir, id, suffix); @@ -494,8 +494,8 @@ Returns: TRUE if all went well */ static BOOL -break_link(uschar * dir, uschar * subdir, uschar * id, uschar * suffix, uschar * from, - BOOL noentok) +break_link(const uschar * dir, const uschar * subdir, const uschar * id, + const uschar * suffix, const uschar * from, BOOL noentok) { uschar * fname = spool_fname(string_sprintf("%s%s", from, dir), subdir, id, suffix); if (Uunlink(fname) < 0 && (!noentok || errno != ENOENT)) @@ -528,7 +528,8 @@ Returns: TRUE if all is well */ BOOL -spool_move_message(uschar * id, uschar * subdir, uschar * from, uschar * to) +spool_move_message(const uschar * id, const uschar * subdir, + const uschar * from, const uschar * to) { uschar * dest_qname = queue_name_dest ? queue_name_dest : queue_name; commit b8e078953178c757578f2e104d9d2c822ae0943c Author: Jeremy Harris Date: Tue Nov 14 12:10:36 2023 +0000 Check for missing commandline arg after options taking one. Bug 3049 diff --git a/src/src/exim.c b/src/src/exim.c index 3cc2fa2fb..14c057f40 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -847,7 +847,7 @@ exit(EXIT_FAILURE); /* fail if a length is too long */ static inline void -exim_len_fail_toolong(int itemlen, int maxlen, const char *description) +exim_len_fail_toolong(int itemlen, int maxlen, const char * description) { if (itemlen <= maxlen) return; @@ -858,8 +858,10 @@ exit(EXIT_FAILURE); /* only pass through the string item back to the caller if it's short enough */ static inline const uschar * -exim_str_fail_toolong(const uschar *item, int maxlen, const char *description) +exim_str_fail_toolong(const uschar * item, int maxlen, const char * description) { +if (!item) + exim_fail("exim: bad item for: %s\n", description); exim_len_fail_toolong(Ustrlen(item), maxlen, description); return item; } @@ -884,10 +886,10 @@ log_write(0, LOG_MAIN|LOG_PANIC, struct stat buf; if (0 == (fd < 0 ? stat(name, &buf) : fstat(fd, &buf))) -{ + { if (buf.st_uid == owner && buf.st_gid == group) return 0; log_write(0, LOG_MAIN|LOG_PANIC, "Wrong ownership on %s", name); -} + } else log_write(0, LOG_MAIN|LOG_PANIC, "Stat failed on %s: %s", name, strerror(errno)); #endif @@ -896,6 +898,18 @@ return -1; } +/* Bump the index for argv, checking for overflow, +and return the argument. */ + +static const uschar * +next_argv(const uschar ** argv, int * pi, int argc, const uschar * where) +{ +int i = *pi; +if (++i >= argc) exim_fail("exim: bad item for: %s\n", where); +return argv[*pi = i]; +} + + /************************************************* * Extract port from host address * *************************************************/ @@ -3151,7 +3165,8 @@ on the second character (the one after '-'), to save some effort. */ { msg_action = MSG_SETQUEUE; queue_name_dest = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"), + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_DRIVERNAME_MAX, "-MG"), GET_TAINTED); } else if (Ustrcmp(argrest, "mad") == 0) msg_action = MSG_MARK_ALL_DELIVERED; @@ -3363,36 +3378,36 @@ on the second character (the one after '-'), to save some effort. */ if (Ustrcmp(argrest, "a") == 0) sender_host_address = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_IPADDR_MAX, "-oMa"), GET_TAINTED); /* -oMaa: Set authenticator name */ else if (Ustrcmp(argrest, "aa") == 0) sender_host_authenticated = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_DRIVERNAME_MAX, "-oMaa"), GET_TAINTED); /* -oMas: setting authenticated sender */ else if (Ustrcmp(argrest, "as") == 0) authenticated_sender = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_EMAILADDR_MAX, "-oMas"), GET_TAINTED); /* -oMai: setting authenticated id */ else if (Ustrcmp(argrest, "ai") == 0) authenticated_id = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMai"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_EMAILADDR_MAX, "-oMai"), GET_TAINTED); /* -oMi: Set incoming interface address */ else if (Ustrcmp(argrest, "i") == 0) interface_address = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_IPADDR_MAX, "-oMi"), GET_TAINTED); /* -oMm: Message reference */ @@ -3402,7 +3417,7 @@ on the second character (the one after '-'), to save some effort. */ exim_fail("-oMm must be a valid message ID\n"); if (!f.trusted_config) exim_fail("-oMm must be called by a trusted user/config\n"); - message_reference = argv[++i]; + message_reference = next_argv(argv, &i, argc, arg); } /* -oMr: Received protocol */ @@ -3412,26 +3427,32 @@ on the second character (the one after '-'), to save some effort. */ if (received_protocol) exim_fail("received_protocol is set already\n"); else - received_protocol = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"), - GET_TAINTED); + if (++i >= argc) badarg = TRUE; + else + received_protocol = string_copy_taint( + exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-oMr"), + GET_TAINTED); /* -oMs: Set sender host name */ else if (Ustrcmp(argrest, "s") == 0) - sender_host_name = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"), - GET_TAINTED); + if (++i >= argc) badarg = TRUE; + else + sender_host_name = string_copy_taint( + exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-oMs"), + GET_TAINTED); /* -oMt: Set sender ident */ else if (Ustrcmp(argrest, "t") == 0) - { - sender_ident_set = TRUE; - sender_ident = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"), - GET_TAINTED); - } + if (++i >= argc) badarg = TRUE; + else + { + sender_ident_set = TRUE; + sender_ident = string_copy_taint( + exim_str_fail_toolong(argv[i], EXIM_IDENTUSER_MAX, "-oMt"), + GET_TAINTED); + } /* Else a bad argument */ @@ -3459,7 +3480,9 @@ on the second character (the one after '-'), to save some effort. */ exim_fail("exim: only uid=%d or uid=%d can use -oP and -oPX " "(uid=%d euid=%d | %d)\n", root_uid, exim_uid, getuid(), geteuid(), real_uid); - if (!*argrest) override_pid_file_path = argv[++i]; + if (!*argrest) + if (++i < argc) override_pid_file_path = argv[i]; + else badarg = TRUE; else if (Ustrcmp(argrest, "X") == 0) delete_pid_file(); else badarg = TRUE; break; @@ -3487,10 +3510,9 @@ on the second character (the one after '-'), to save some effort. */ /* Limits: Is there a real limit we want here? 1024 is very arbitrary. */ case 'X': - if (*argrest) badarg = TRUE; + if (*argrest || ++i >= argc) badarg = TRUE; else override_local_interfaces = string_copy_taint( - exim_str_fail_toolong(argv[++i], 1024, "-oX"), - GET_TAINTED); + exim_str_fail_toolong(argv[i], 1024, "-oX"), GET_TAINTED); break; /* -oY: Override creation of daemon notifier socket */ @@ -3528,7 +3550,7 @@ on the second character (the one after '-'), to save some effort. */ which sets the host protocol and host name */ if (!*argrest) - if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; } + argrest = next_argv(argv, &i, argc, arg); if (*argrest) { @@ -3614,8 +3636,14 @@ on the second character (the one after '-'), to save some effort. */ else { - int intvl = readconf_readtime(*argrest ? argrest : argv[++i], 0, FALSE); - if (intvl <= 0) + int intvl; + const uschar * s; + + if (*argrest) s = argrest; + else if (++i < argc) { badarg = TRUE; break; } + else s = argv[i]; + + if ((intvl = readconf_readtime(s, 0, FALSE)) <= 0) exim_fail("exim: bad time value %s: abandoned\n", argv[i]); for (qrunner * qq = qrunners; qq; qq = qq->next) @@ -3706,8 +3734,8 @@ on the second character (the one after '-'), to save some effort. */ tested. Otherwise variability of clock ticks etc. cause problems. */ case 'T': - if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0) - fudged_queue_times = string_copy_taint(argv[++i], GET_TAINTED); + if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0 && ++i < argc) + fudged_queue_times = string_copy_taint(argv[i], GET_TAINTED); else badarg = TRUE; break; commit fa1c8faf169384bebaa8d172f491574c45ae2aa4 Author: Jeremy Harris Date: Wed Nov 15 02:14:02 2023 +0000 constification diff --git a/src/exim_monitor/em_globals.c b/src/exim_monitor/em_globals.c index cf9b1075e..3822746ba 100644 --- a/src/exim_monitor/em_globals.c +++ b/src/exim_monitor/em_globals.c @@ -204,7 +204,7 @@ recipient_item *recipients_list = NULL; int recipients_list_max = 0; BOOL running_in_test_harness=FALSE; -uschar *sender_address = NULL; +const uschar *sender_address = NULL; uschar *sender_fullhost = NULL; uschar *sender_helo_name = NULL; uschar *sender_host_address = NULL; diff --git a/src/exim_monitor/em_hdr.h b/src/exim_monitor/em_hdr.h index 61f390d2c..feffa6bfc 100644 --- a/src/exim_monitor/em_hdr.h +++ b/src/exim_monitor/em_hdr.h @@ -309,7 +309,7 @@ extern uschar *copystring(uschar *); extern void create_dialog(uschar *, uschar *); extern void create_stripchart(Widget, uschar *); extern void debug(char *, ...); -extern dest_item *find_dest(queue_item *, uschar *, int, BOOL); +extern dest_item *find_dest(queue_item *, const uschar *, int, BOOL); extern queue_item *find_queue(uschar *, int, int); extern void init(int, uschar **); extern void menu_create(Widget, XEvent *, String *, Cardinal *); diff --git a/src/exim_monitor/em_queue.c b/src/exim_monitor/em_queue.c index 4c3d3fd18..c7c61a652 100644 --- a/src/exim_monitor/em_queue.c +++ b/src/exim_monitor/em_queue.c @@ -66,18 +66,16 @@ address is lowercased to start with, unless it begins with "*", which it does for error messages. */ dest_item * -find_dest(queue_item *q, uschar *name, int action, BOOL caseless) +find_dest(queue_item * q, const uschar * name, int action, BOOL caseless) { -dest_item *dd; -dest_item **d = &(q->destinations); +dest_item * dd; +dest_item ** d = &q->destinations; -while (*d != NULL) +while (*d) { if ((caseless? strcmpic(name,(*d)->address) : Ustrcmp(name,(*d)->address)) == 0) { - dest_item *ddd; - if (action != dest_remove) return *d; dd = *d; *d = dd->next; @@ -85,14 +83,12 @@ while (*d != NULL) /* Unset any parent pointers that were to this address */ - for (ddd = q->destinations; ddd != NULL; ddd = ddd->next) - { + for (dest_item * ddd = q->destinations; ddd; ddd = ddd->next) if (ddd->parent == dd) ddd->parent = NULL; - } return NULL; } - d = &((*d)->next); + d = &(*d)->next; } if (action != dest_add) return NULL; @@ -207,8 +203,9 @@ if it's there. */ else { q->update_time = q->input_time = received_time.tv_sec; - if ((p = strstric(sender_address+1, qualify_domain, FALSE)) != NULL && - *(--p) == '@') *p = 0; + /* deconst ok; strstric is actually safe */ + if ((p = strstric(US sender_address+1, qualify_domain, FALSE)) != NULL && + *--p == '@') *p = 0; } /* If we didn't read the whole header successfully, generate an error @@ -279,10 +276,11 @@ been delivered, and removing visible names. */ if (recipients_list) for (i = 0; i < recipients_count; i++) { - uschar * r = recipients_list[i].address; + const uschar * r = recipients_list[i].address; if (tree_search(tree_nonrecipients, r) == NULL) { - if ((p = strstric(r+1, qualify_domain, FALSE)) != NULL && + /* deconst ok; strstric is actually safe */ + if ((p = strstric(US r+1, qualify_domain, FALSE)) != NULL && *(--p) == '@') *p = 0; (void)find_dest(q, r, dest_add, FALSE); } @@ -663,13 +661,14 @@ if (recipients_list) for (i = 0; i < recipients_count; i++) { uschar * pp; - uschar * r = recipients_list[i].address; + const uschar * r = recipients_list[i].address; tree_node * node; if (!(node = tree_search(tree_nonrecipients, r))) node = tree_search(tree_nonrecipients, string_copylc(r)); - if ((pp = strstric(r+1, qualify_domain, FALSE)) && *(--pp) == '@') + /* deconst ok; strstric is actually safe */ + if ((pp = strstric(US r+1, qualify_domain, FALSE)) && *(--pp) == '@') *pp = 0; if (!node) (void)find_dest(p, r, dest_add, FALSE); diff --git a/src/src/acl.c b/src/src/acl.c index cdf60bbb8..9223fcec8 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1711,10 +1711,10 @@ BOOL no_details = FALSE; BOOL success_on_redirect = FALSE; BOOL quota = FALSE; int quota_pos_cache = QUOTA_POS_DEFAULT, quota_neg_cache = QUOTA_NEG_DEFAULT; -address_item *sender_vaddr = NULL; -uschar *verify_sender_address = NULL; -uschar *pm_mailfrom = NULL; -uschar *se_mailfrom = NULL; +address_item * sender_vaddr = NULL; +const uschar * verify_sender_address = NULL; +uschar * pm_mailfrom = NULL; +uschar * se_mailfrom = NULL; /* Some of the verify items have slash-separated options; some do not. Diagnose an error if options are given for items that don't expect them. @@ -4713,8 +4713,8 @@ Returns: OK access is granted by an ACCEPT verb int acl_where = ACL_WHERE_UNKNOWN; int -acl_check(int where, uschar *recipient, uschar *s, uschar **user_msgptr, - uschar **log_msgptr) +acl_check(int where, const uschar * recipient, uschar * s, + uschar ** user_msgptr, uschar ** log_msgptr) { int rc; address_item adb; diff --git a/src/src/deliver.c b/src/src/deliver.c index 9d459167e..e96733f73 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -27,7 +27,7 @@ typedef struct pardata { int transport_count; /* returned transport count value */ BOOL done; /* no more data needed */ uschar *msg; /* error message */ - uschar *return_path; /* return_path for these addresses */ + const uschar *return_path; /* return_path for these addresses */ } pardata; /* Values for the process_recipients variable */ @@ -77,7 +77,7 @@ static pardata *parlist = NULL; static struct pollfd *parpoll; static int return_count; static uschar *frozen_info = US""; -static uschar *used_return_path = NULL; +static const uschar * used_return_path = NULL; @@ -144,7 +144,7 @@ Returns: a pointer to an initialized address_item */ address_item * -deliver_make_addr(uschar *address, BOOL copy) +deliver_make_addr(const uschar * address, BOOL copy) { address_item * addr = store_get(sizeof(address_item), GET_UNTAINTED); *addr = address_defaults; @@ -575,7 +575,7 @@ Returns: TRUE or FALSE */ static BOOL -same_strings(uschar *one, uschar *two) +same_strings(const uschar * one, const uschar * two) { if (one == two) return TRUE; /* Includes the case where both NULL */ if (!one || !two) return FALSE; @@ -898,7 +898,7 @@ void msg_event_raise(const uschar * event, const address_item * addr) { const uschar * save_domain = deliver_domain; -uschar * save_local = deliver_localpart; +const uschar * save_local = deliver_localpart; const uschar * save_host = deliver_host; const uschar * save_address = deliver_host_address; const int save_port = deliver_host_port; @@ -950,13 +950,13 @@ router_name = transport_name = NULL; * Generate local part for logging * *************************************************/ -static uschar * -string_get_lpart_sub(const address_item * addr, uschar * s) +static const uschar * +string_get_lpart_sub(const address_item * addr, const uschar * s) { #ifdef SUPPORT_I18N if (testflag(addr, af_utf8_downcvt)) { - uschar * t = string_localpart_utf8_to_alabel(s, NULL); + const uschar * t = string_localpart_utf8_to_alabel(s, NULL); return t ? t : s; /* t is NULL on a failed conversion */ } #endif @@ -975,7 +975,7 @@ Returns: the new value of the buffer pointer static gstring * string_get_localpart(address_item * addr, gstring * yield) { -uschar * s; +const uschar * s; if (testflag(addr, af_include_affixes) && (s = addr->prefix)) yield = string_cat(yield, string_get_lpart_sub(addr, s)); @@ -5086,7 +5086,7 @@ Returns: OK int deliver_split_address(address_item * addr) { -uschar * address = addr->address; +const uschar * address = addr->address; uschar * domain; uschar * t; int len; @@ -5103,7 +5103,7 @@ where they are locally interpreted. [The new draft "821" is more explicit on this, Jan 1999.] We know the syntax is valid, so this can be done by simply removing quoting backslashes and any unquoted doublequotes. */ -t = addr->cc_local_part = store_get(len+1, address); +addr->cc_local_part = t = store_get(len+1, address); while(len-- > 0) { int c = *address++; @@ -5115,7 +5115,7 @@ while(len-- > 0) } else *t++ = c; } -*t = 0; +*t = '\0'; /* We do the percent hack only for those domains that are listed in percent_hack_domains. A loop is required, to copy with multiple %-hacks. */ @@ -5123,8 +5123,8 @@ percent_hack_domains. A loop is required, to copy with multiple %-hacks. */ if (percent_hack_domains) { int rc; - uschar *new_address = NULL; - uschar *local_part = addr->cc_local_part; + uschar * new_address = NULL; + const uschar * local_part = addr->cc_local_part; deliver_domain = addr->domain; /* set $domain */ @@ -5261,12 +5261,12 @@ Returns: TRUE if the address is not hidden */ static BOOL -print_address_information(address_item *addr, FILE *f, uschar *si, uschar *sc, - uschar *se) +print_address_information(address_item * addr, FILE * f, uschar * si, + uschar * sc, uschar * se) { BOOL yield = TRUE; -uschar *printed = US""; -address_item *ancestor = addr; +const uschar * printed = US""; +address_item * ancestor = addr; while (ancestor->parent) ancestor = ancestor->parent; fprintf(f, "%s", CS si); @@ -5281,8 +5281,8 @@ else if (!testflag(addr, af_pfr) || !addr->parent) else { - uschar *s = addr->address; - uschar *ss; + const uschar * s = addr->address; + const uschar * ss; if (addr->address[0] == '>') { ss = US"mail"; s++; } else if (addr->address[0] == '|') ss = US"pipe"; @@ -5296,7 +5296,7 @@ fprintf(f, "%s", CS string_printing(printed)); if (ancestor != addr) { - uschar *original = ancestor->onetime_parent; + const uschar * original = ancestor->onetime_parent; if (!original) original= ancestor->address; if (strcmpic(original, printed) != 0) fprintf(f, "%s(%sgenerated from %s)", sc, @@ -6973,7 +6973,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) if (!p->transport) { - address_item *badp = p; + address_item * badp = p; p = p->next; if (!addr_last) addr_new = p; else addr_last->next = p; badp->local_part = badp->address; /* Needed for log line */ @@ -7114,9 +7114,10 @@ if (process_recipients != RECIP_IGNORE) #ifndef DISABLE_EVENT if (process_recipients != RECIP_ACCEPT && event_action) { - uschar * save_local = deliver_localpart; + const uschar * save_local = deliver_localpart; const uschar * save_domain = deliver_domain; - uschar * addr = new->address, * errmsg = NULL; + const uschar * addr = new->address; + uschar * errmsg = NULL; int start, end, dom; if (!parse_extract_address(addr, &errmsg, &start, &end, &dom, TRUE)) @@ -8365,7 +8366,7 @@ else if (addr_defer != (address_item *)(+1)) for (i = 0; i < recipients_count; i++) { - uschar *r = recipients_list[i].address; + const uschar * r = recipients_list[i].address; if (Ustrcmp(otaddr->onetime_parent, r) == 0) t = i; if (Ustrcmp(otaddr->address, r) == 0) break; } @@ -8393,7 +8394,7 @@ else if (addr_defer != (address_item *)(+1)) if (sender_address[0]) { - uschar * s = addr->prop.errors_address; + const uschar * s = addr->prop.errors_address; if (!s) s = sender_address; if (Ustrstr(recipients, s) == NULL) recipients = string_sprintf("%s%s%s", recipients, diff --git a/src/src/exim.c b/src/src/exim.c index 14c057f40..4473373b3 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1379,17 +1379,15 @@ Argument: the local part Returns: the local part, quoted if necessary */ -uschar * -local_part_quote(uschar *lpart) +const uschar * +local_part_quote(const uschar * lpart) { BOOL needs_quote = FALSE; gstring * g; -for (uschar * t = lpart; !needs_quote && *t != 0; t++) - { +for (const uschar * t = lpart; !needs_quote && *t; t++) needs_quote = !isalnum(*t) && strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL && (*t != '.' || t == lpart || t[1] == 0); - } if (!needs_quote) return lpart; @@ -1397,8 +1395,8 @@ g = string_catn(NULL, US"\"", 1); for (;;) { - uschar *nq = US Ustrpbrk(lpart, "\\\""); - if (nq == NULL) + uschar * nq = US Ustrpbrk(lpart, "\\\""); + if (!nq) { g = string_cat(g, lpart); break; @@ -1809,20 +1807,20 @@ BOOL verify_address_mode = FALSE; BOOL verify_as_sender = FALSE; BOOL rcpt_verify_quota = FALSE; BOOL version_printed = FALSE; -const uschar *alias_arg = NULL; -const uschar *called_as = US""; -const uschar *cmdline_syslog_name = NULL; -const uschar *start_queue_run_id = NULL; -const uschar *stop_queue_run_id = NULL; -const uschar *expansion_test_message = NULL; -const uschar *ftest_domain = NULL; -const uschar *ftest_localpart = NULL; -const uschar *ftest_prefix = NULL; -const uschar *ftest_suffix = NULL; -uschar *log_oneline = NULL; -const uschar *malware_test_file = NULL; -uschar *real_sender_address; -uschar *originator_home = US"/"; +const uschar * alias_arg = NULL; +const uschar * called_as = US""; +const uschar * cmdline_syslog_name = NULL; +const uschar * start_queue_run_id = NULL; +const uschar * stop_queue_run_id = NULL; +const uschar * expansion_test_message = NULL; +const uschar * ftest_domain = NULL; +const uschar * ftest_localpart = NULL; +const uschar * ftest_prefix = NULL; +const uschar * ftest_suffix = NULL; +uschar * log_oneline = NULL; +const uschar * malware_test_file = NULL; +const uschar * real_sender_address; +uschar * originator_home = US"/"; size_t sz; struct passwd *pw; @@ -2844,7 +2842,11 @@ on the second character (the one after '-'), to save some effort. */ if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; } (void) exim_str_fail_toolong(argrest, EXIM_DISPLAYMAIL_MAX, "-f"); if (!*argrest) - *(sender_address = store_get(1, GET_UNTAINTED)) = '\0'; /* Ensure writeable memory */ + { + uschar * s = store_get(1, GET_UNTAINTED); /* Ensure writeable memory */ + *s = '\0'; + sender_address = s; + } else { const uschar * temp = argrest + Ustrlen(argrest) - 1; diff --git a/src/src/expand.c b/src/src/expand.c index 40cc8d73a..9a88d38ca 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1804,20 +1804,19 @@ return g; /* A recipients list is available only during system message filtering, during ACL processing after DATA, and while expanding pipe commands generated from a system filter, but not elsewhere. Note that this does -not check for comman in the elements, and uses comma-space as seperator - +not check for commas in the elements, and uses comma-space as seperator - so cannot be used as an exim list as-is. */ static uschar * fn_recipients(void) { -uschar * s; gstring * g = NULL; if (!f.enable_dollar_recipients) return NULL; for (int i = 0; i < recipients_count; i++) { - s = recipients_list[i].address; + const uschar * s = recipients_list[i].address; g = string_append2_listele_n(g, US", ", s, Ustrlen(s)); } gstring_release_unused(g); diff --git a/src/src/functions.h b/src/src/functions.h index ba4fd215c..74cd15424 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -100,7 +100,7 @@ extern int tlsa_lookup(const host_item *, dns_answer *, BOOL); /* Everything else... */ extern acl_block *acl_read(uschar *(*)(void), uschar **); -extern int acl_check(int, uschar *, uschar *, uschar **, uschar **); +extern int acl_check(int, const uschar *, uschar *, uschar **, uschar **); extern uschar *acl_current_verb(void); extern int acl_eval(int, uschar *, uschar **, uschar **); extern uschar *acl_standalone_setvar(const uschar *); @@ -216,7 +216,7 @@ extern void decode_bits(unsigned int *, size_t, int *, const uschar *, bit_table *, int, uschar *, int); extern void delete_pid_file(void); extern void deliver_local(address_item *, BOOL); -extern address_item *deliver_make_addr(uschar *, BOOL); +extern address_item *deliver_make_addr(const uschar *, BOOL); extern void delivery_log(int, address_item *, int, uschar *); extern int deliver_message(const uschar *, BOOL, BOOL); extern void deliver_msglog(const char *, ...) PRINTF_FUNCTION(1,2); @@ -335,7 +335,7 @@ extern int ip_streamsocket(const uschar *, uschar **, int, host_item *); extern int ipv6_nmtoa(int *, uschar *); -extern uschar *local_part_quote(uschar *); +extern const uschar *local_part_quote(const uschar *); extern int log_open_as_exim(const uschar * const); extern void log_close_all(void); @@ -375,11 +375,11 @@ extern ssize_t mime_decode_base64(FILE *, FILE *, uschar *); extern int mime_regex(const uschar **, BOOL); extern void mime_set_anomaly(int); #endif -extern uschar *moan_check_errorcopy(uschar *); +extern uschar *moan_check_errorcopy(const uschar *); extern BOOL moan_skipped_syntax_errors(uschar *, error_block *, uschar *, BOOL, uschar *); extern void moan_smtp_batch(uschar *, const char *, ...) PRINTF_FUNCTION(2,3); -extern BOOL moan_send_message(uschar *, int, error_block *eblock, +extern BOOL moan_send_message(const uschar *, int, error_block *eblock, header_line *, FILE *, uschar *); extern void moan_tell_someone(uschar *, address_item *, const uschar *, const char *, ...) PRINTF_FUNCTION(4,5); @@ -440,7 +440,7 @@ extern void readconf_save_config(const uschar *); extern void read_message_body(BOOL); extern void receive_bomb_out(uschar *, uschar *) NORETURN; extern BOOL receive_check_fs(int); -extern BOOL receive_check_set_sender(uschar *); +extern BOOL receive_check_set_sender(const uschar *); extern BOOL receive_msg(BOOL); extern int_eximarith_t receive_statvfs(BOOL, int *); extern void receive_swallow_smtp(void); @@ -636,7 +636,7 @@ extern BOOL transport_pass_socket(const uschar *, const uschar *, const uscha , unsigned, unsigned, unsigned #endif ); -extern uschar *transport_rcpt_address(address_item *, BOOL); +extern const uschar *transport_rcpt_address(address_item *, BOOL); extern BOOL transport_set_up_command(const uschar ***, const uschar *, unsigned, int, address_item *, const uschar *, uschar **); extern void transport_update_waiting(host_item *, uschar *); @@ -644,7 +644,7 @@ extern BOOL transport_write_block(transport_ctx *, uschar *, int, BOOL); extern void transport_write_reset(int); extern BOOL transport_write_string(int, const char *, ...); extern BOOL transport_headers_send(transport_ctx *, - BOOL (*)(transport_ctx *, uschar *, int)); + BOOL (*)(transport_ctx *, const uschar *, int)); extern gstring * transport_show_supported(gstring *); extern BOOL transport_write_message(transport_ctx *, int); extern void tree_add_duplicate(const uschar *, address_item *); @@ -679,7 +679,7 @@ extern int verify_check_notblind(BOOL); extern int verify_check_given_host(const uschar **, const host_item *); extern int verify_check_this_host(const uschar **, unsigned int *, const uschar*, const uschar *, const uschar **); -extern address_item *verify_checked_sender(uschar *); +extern address_item *verify_checked_sender(const uschar *); extern void verify_get_ident(int); extern void verify_quota(uschar *); extern int verify_quota_call(const uschar *, int, int, uschar **); @@ -687,7 +687,7 @@ extern BOOL verify_sender(int *, uschar **); extern BOOL verify_sender_preliminary(int *, uschar **); extern void version_init(void); -extern BOOL write_chunk(transport_ctx *, uschar *, int); +extern BOOL write_chunk(transport_ctx *, const uschar *, int); extern ssize_t write_to_fd_buf(int, const uschar *, size_t); extern uschar *wrap_header(const uschar *, unsigned, unsigned, const uschar *, unsigned); diff --git a/src/src/globals.c b/src/src/globals.c index 46ca72f20..bb5bd6b1a 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -610,8 +610,8 @@ address_item address_defaults = { } }; -uschar *address_file = NULL; -uschar *address_pipe = NULL; +const uschar *address_file = NULL; +const uschar *address_pipe = NULL; tree_node *addresslist_anchor = NULL; int addresslist_count = 0; gid_t *admin_groups = NULL; @@ -683,7 +683,7 @@ int body_linecount = 0; int body_zerocount = 0; uschar *bounce_message_file = NULL; uschar *bounce_message_text = NULL; -uschar *bounce_recipient = NULL; +const uschar *bounce_recipient = NULL; int bounce_return_linesize_limit = 998; int bounce_return_size_limit = 100*1024; uschar *bounce_sender_authentication = NULL; @@ -842,14 +842,14 @@ const uschar *deliver_host_address = NULL; int deliver_host_port = 0; uschar *deliver_in_buffer = NULL; ino_t deliver_inode = 0; -uschar *deliver_localpart = NULL; +const uschar *deliver_localpart= NULL; uschar *deliver_localpart_data = NULL; -uschar *deliver_localpart_orig = NULL; -uschar *deliver_localpart_parent = NULL; -uschar *deliver_localpart_prefix = NULL; -uschar *deliver_localpart_prefix_v = NULL; -uschar *deliver_localpart_suffix = NULL; -uschar *deliver_localpart_suffix_v = NULL; +const uschar *deliver_localpart_orig = NULL; +const uschar *deliver_localpart_parent = NULL; +const uschar *deliver_localpart_prefix = NULL; +const uschar *deliver_localpart_prefix_v = NULL; +const uschar *deliver_localpart_suffix = NULL; +const uschar *deliver_localpart_suffix_v = NULL; uschar *deliver_out_buffer = NULL; int deliver_queue_load_max = -1; address_item *deliver_recipients = NULL; @@ -1276,8 +1276,8 @@ tree_node *ratelimiters_cmd = NULL; tree_node *ratelimiters_conn = NULL; tree_node *ratelimiters_mail = NULL; uschar *raw_active_hostname = NULL; -uschar *raw_sender = NULL; -uschar **raw_recipients = NULL; +const uschar *raw_sender = NULL; +const uschar **raw_recipients = NULL; int raw_recipients_count = 0; int rcpt_count = 0; @@ -1289,7 +1289,7 @@ int receive_linecount = 0; int receive_messagecount = 0; int receive_timeout = 0; int received_count = 0; -uschar *received_for = NULL; +const uschar *received_for = NULL; /* This is the default text for Received headers generated by Exim. The date will be automatically added on the end. */ @@ -1348,7 +1348,7 @@ int retry_data_expire = 7*24*60*60; int retry_interval_max = 24*60*60; int retry_maximum_timeout = 0; /* set from retry config */ retry_config *retries = NULL; -uschar *return_path = NULL; +const uschar *return_path = NULL; int rewrite_existflags = 0; uschar *rfc1413_hosts = US"@[]"; int rfc1413_query_timeout = 0; @@ -1456,10 +1456,10 @@ int runrc = 0; uschar *search_error_message = NULL; uschar *self_hostname = NULL; -uschar *sender_address = NULL; +const uschar *sender_address = NULL; unsigned int sender_address_cache[(MAX_NAMED_LIST * 2)/32]; uschar *sender_address_data = NULL; -uschar *sender_address_unrewritten = NULL; +const uschar *sender_address_unrewritten = NULL; uschar *sender_data = NULL; unsigned int sender_domain_cache[(MAX_NAMED_LIST * 2)/32]; uschar *sender_fullhost = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index 9ec44487f..dff3762a8 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -350,8 +350,8 @@ extern uschar *acl_wherecodes[]; /* Response codes for ACL fails */ extern uschar *acl_wherenames[]; /* Names for messages */ extern address_item *addr_duplicate; /* Duplicate address list */ extern address_item address_defaults; /* Default data for address item */ -extern uschar *address_file; /* Name of file when delivering to one */ -extern uschar *address_pipe; /* Pipe command when delivering to one */ +extern const uschar *address_file; /* Name of file when delivering to one */ +extern const uschar *address_pipe; /* Pipe command when delivering to one */ extern tree_node *addresslist_anchor; /* Tree of defined address lists */ extern int addresslist_count; /* Number defined */ extern gid_t *admin_groups; /* List of admin groups */ @@ -400,7 +400,7 @@ extern int bsmtp_transaction_linecount; /* Start of last transaction */ extern int body_8bitmime; /* sender declared BODY= ; 7=7BIT, 8=8BITMIME */ extern uschar *bounce_message_file; /* Template file */ extern uschar *bounce_message_text; /* One-liner */ -extern uschar *bounce_recipient; /* When writing an errmsg */ +extern const uschar *bounce_recipient; /* When writing an errmsg */ extern BOOL bounce_return_body; /* Include body in returned message */ extern int bounce_return_linesize_limit; /* Max line length in return */ extern BOOL bounce_return_message; /* Include message in bounce */ @@ -517,14 +517,14 @@ extern const uschar *deliver_host_address; /* Address for remote delivery filter extern int deliver_host_port; /* Address for remote delivery filter */ extern uschar *deliver_in_buffer; /* Buffer for copying file */ extern ino_t deliver_inode; /* Inode for appendfile */ -extern uschar *deliver_localpart; /* The local part for delivery */ +extern const uschar *deliver_localpart;/* The local part for delivery */ extern uschar *deliver_localpart_data; /* From local part lookup (de-tainted) */ -extern uschar *deliver_localpart_orig; /* The original local part for delivery */ -extern uschar *deliver_localpart_parent; /* The parent local part for delivery */ -extern uschar *deliver_localpart_prefix; /* The stripped prefix, if any */ -extern uschar *deliver_localpart_prefix_v; /* The stripped-prefix variable portion, if any */ -extern uschar *deliver_localpart_suffix; /* The stripped suffix, if any */ -extern uschar *deliver_localpart_suffix_v; /* The stripped-suffix variable portion, if any */ +extern const uschar *deliver_localpart_orig; /* The original local part for delivery */ +extern const uschar *deliver_localpart_parent; /* The parent local part for delivery */ +extern const uschar *deliver_localpart_prefix; /* The stripped prefix, if any */ +extern const uschar *deliver_localpart_prefix_v; /* The stripped-prefix variable portion, if any */ +extern const uschar *deliver_localpart_suffix; /* The stripped suffix, if any */ +extern const uschar *deliver_localpart_suffix_v; /* The stripped-suffix variable portion, if any */ extern uschar *deliver_out_buffer; /* Buffer for copying file */ extern int deliver_queue_load_max; /* Different value for queue running */ extern address_item *deliver_recipients; /* Current set of addresses */ @@ -872,8 +872,8 @@ extern tree_node *ratelimiters_cmd; /* Results of command ratelimit checks */ extern tree_node *ratelimiters_conn; /* Results of connection ratelimit checks */ extern tree_node *ratelimiters_mail; /* Results of per-mail ratelimit checks */ extern uschar *raw_active_hostname; /* Pre-expansion */ -extern uschar *raw_sender; /* Before rewriting */ -extern uschar **raw_recipients; /* Before rewriting */ +extern const uschar *raw_sender; /* Before rewriting */ +extern const uschar **raw_recipients; /* Before rewriting */ extern int raw_recipients_count; extern const uschar * rc_names[]; /* Mostly for debug output */ extern int rcpt_count; /* Count of RCPT commands in a message */ @@ -885,7 +885,7 @@ extern int receive_linecount; /* Mainly for BSMTP errors */ extern int receive_messagecount; /* Mainly for BSMTP errors */ extern int receive_timeout; /* For non-SMTP acceptance */ extern int received_count; /* Count of Received: headers */ -extern uschar *received_for; /* For "for" field */ +extern const uschar *received_for; /* For "for" field */ extern uschar *received_header_text; /* Definition of Received: header */ extern int received_headers_max; /* Max count of Received: headers */ extern struct timeval received_time; /* Time the message started to be received */ @@ -926,7 +926,7 @@ extern retry_config *retries; /* Chain of retry config information */ extern int retry_data_expire; /* When to expire retry data */ extern int retry_interval_max; /* Absolute maximum */ extern int retry_maximum_timeout; /* The maximum timeout */ -extern uschar *return_path; /* Return path for a message */ +extern const uschar *return_path; /* Return path for a message */ extern BOOL return_path_remove; /* Remove return-path headers */ extern int rewrite_existflags; /* Indicate which headers have rewrites */ extern uschar *rfc1413_hosts; /* RFC hosts */ @@ -947,7 +947,7 @@ extern uschar *search_error_message; /* Details of lookup problem */ extern uschar *self_hostname; /* Self host after routing->directors */ extern unsigned int sender_address_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for sender */ extern uschar *sender_address_data; /* address_data from sender verify */ -extern uschar *sender_address_unrewritten; /* Set if rewritten by verify */ +extern const uschar *sender_address_unrewritten; /* Set if rewritten by verify */ extern uschar *sender_data; /* lookup result for senders */ extern unsigned int sender_domain_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for sender domain */ extern uschar *sender_fullhost; /* Sender host name + address */ diff --git a/src/src/local_scan.h b/src/src/local_scan.h index 153b4cb3c..ed9f26d62 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -153,9 +153,9 @@ field is always NULL except for one_time aliases that had errors_to on the routers that generated them. */ typedef struct recipient_item { - uschar *address; /* the recipient address */ + const uschar *address; /* the recipient address */ int pno; /* parent number for "one_time" alias, or -1 */ - uschar *errors_to; /* the errors_to address or NULL */ + const uschar *errors_to; /* the errors_to address or NULL */ uschar *orcpt; /* DSN orcpt */ int dsn_flags; /* DSN flags */ #ifdef EXPERIMENTAL_BRIGHTMAIL @@ -181,7 +181,7 @@ extern uschar *message_id; /* Internal id of message being handled * extern uschar *received_protocol; /* Name of incoming protocol */ extern int recipients_count; /* Number of recipients */ extern recipient_item *recipients_list;/* List of recipient addresses */ -extern unsigned char *sender_address; /* Sender address */ +extern const unsigned char *sender_address; /* Sender address */ extern uschar *sender_host_address; /* IP address of sender, as chars */ extern uschar *sender_host_authenticated; /* Name of authentication mechanism */ extern uschar *sender_host_name; /* Host name from lookup */ @@ -207,8 +207,8 @@ extern int lss_match_domain(uschar *, uschar *); extern int lss_match_local_part(uschar *, uschar *, BOOL); extern int lss_match_address(uschar *, uschar *, BOOL); extern int lss_match_host(uschar *, uschar *, uschar *); -extern void receive_add_recipient(uschar *, int); -extern BOOL receive_remove_recipient(uschar *); +extern void receive_add_recipient(const uschar *, int); +extern BOOL receive_remove_recipient(const uschar *); extern uschar *rfc2047_decode(uschar *, BOOL, const uschar *, int, int *, uschar **); extern int smtp_fflush(void); diff --git a/src/src/log.c b/src/src/log.c index af6e8b01b..f85823520 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1032,11 +1032,10 @@ if ( flags & LOG_RECIPIENTS && g->ptr < LOG_BUFFER_SIZE - 6 && raw_recipients_count > 0) { - int i; g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " for", NULL); - for (i = 0; i < raw_recipients_count; i++) + for (int i = 0; i < raw_recipients_count; i++) { - uschar * s = raw_recipients[i]; + const uschar * s = raw_recipients[i]; if (LOG_BUFFER_SIZE - g->ptr < Ustrlen(s) + 3) break; g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s", s); } diff --git a/src/src/moan.c b/src/src/moan.c index 25595816c..c2e38d4f7 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -158,8 +158,8 @@ Returns: TRUE if message successfully sent */ BOOL -moan_send_message(uschar *recipient, int ident, error_block *eblock, - header_line *headers, FILE *message_file, uschar *firstline) +moan_send_message(const uschar * recipient, int ident, error_block * eblock, + header_line * headers, FILE * message_file, uschar * firstline) { int written = 0; int fd; @@ -631,7 +631,7 @@ if (addr) fprintf(f, "\nThe following address(es) have yet to be delivered:\n"); for (; addr; addr = addr->next) { - uschar * parent = addr->parent ? addr->parent->address : NULL; + const uschar * parent = addr->parent ? addr->parent->address : NULL; fprintf(f, " %s", addr->address); if (parent) fprintf(f, " <%s>", parent); if (addr->basic_errno > 0) fprintf(f, ": %s", strerror(addr->basic_errno)); @@ -734,22 +734,23 @@ Returns: additional recipient list or NULL */ uschar * -moan_check_errorcopy(uschar *recipient) +moan_check_errorcopy(const uschar * recipient) { -uschar *item, *localpart, *domain; -const uschar *listptr = errors_copy; +uschar * item; +const uschar * localpart, * domain; +const uschar * listptr = errors_copy; uschar *yield = NULL; int sep = 0; int llen; -if (errors_copy == NULL) return NULL; +if (!errors_copy) return NULL; /* Set up pointer to the local part and domain, and compute the length of the local part. */ localpart = recipient; domain = Ustrrchr(recipient, '@'); -if (domain == NULL) return NULL; /* should not occur, but avoid crash */ +if (!domain) return NULL; /* should not occur, but avoid crash */ llen = domain++ - recipient; /* Scan through the configured items */ diff --git a/src/src/queue.c b/src/src/queue.c index cfe87e953..deedcde6f 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -585,7 +585,7 @@ for (int i = queue_run_in_order ? -1 : 0; else if ( deliver_selectstring_sender && !(f.deliver_selectstring_sender_regex ? regex_match(selectstring_regex_sender, sender_address, -1, NULL) - : (strstric(sender_address, deliver_selectstring_sender, FALSE) + : (strstric_c(sender_address, deliver_selectstring_sender, FALSE) != NULL) ) ) { @@ -601,10 +601,10 @@ for (int i = queue_run_in_order ? -1 : 0; int i; for (i = 0; i < recipients_count; i++) { - uschar *address = recipients_list[i].address; + const uschar * address = recipients_list[i].address; if ( (f.deliver_selectstring_regex ? regex_match(selectstring_regex, address, -1, NULL) - : (strstric(address, deliver_selectstring, FALSE) != NULL) + : (strstric_c(address, deliver_selectstring, FALSE) != NULL) ) && tree_search(tree_nonrecipients, address) == NULL ) @@ -1369,9 +1369,10 @@ switch(action) tree_search(tree_nonrecipients, recipients_list[i].address); if (!delivered) { - uschar * save_local = deliver_localpart; + const uschar * save_local = deliver_localpart; const uschar * save_domain = deliver_domain; - uschar * addr = recipients_list[i].address, * errmsg = NULL; + const uschar * addr = recipients_list[i].address; + uschar * errmsg = NULL; int start, end, dom; if (!parse_extract_address(addr, &errmsg, &start, &end, &dom, TRUE)) diff --git a/src/src/rda.c b/src/src/rda.c index 9c2aa5022..7d329c580 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -466,7 +466,7 @@ Returns: FALSE if data missing */ static BOOL -rda_read_string(int fd, uschar **sp) +rda_read_string(int fd, uschar ** sp) { int len; @@ -866,9 +866,9 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED || for (;;) { int i, reply_options; - address_item *addr; - uschar *recipient; - uschar *expandn[EXPAND_MAXN + 2]; + address_item * addr; + uschar * recipient, * s; + uschar * expandn[EXPAND_MAXN + 2]; /* First string is the address; NULL => end of addresses */ @@ -885,10 +885,11 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED || if ( read(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode) || read(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags) - || !rda_read_string(fd, &addr->prop.errors_address) + || !rda_read_string(fd, &s) || read(fd, &i, sizeof(i)) != sizeof(i) ) goto DISASTER; + addr->prop.errors_address = s; addr->prop.ignore_error = (i != 0); /* Next comes a possible setting for $thisaddress and any numerical diff --git a/src/src/receive.c b/src/src/receive.c index 041898a6b..a459061ef 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -137,9 +137,9 @@ Returns: TRUE for a trusted caller */ BOOL -receive_check_set_sender(uschar *newsender) +receive_check_set_sender(const uschar * newsender) { -uschar *qnewsender; +const uschar * qnewsender; if (f.trusted_caller) return TRUE; if (!newsender || !untrusted_set_sender) return FALSE; qnewsender = Ustrchr(newsender, '@') @@ -514,7 +514,7 @@ Returns: nothing */ void -receive_add_recipient(uschar * recipient, int pno) +receive_add_recipient(const uschar * recipient, int pno) { if (recipients_count >= recipients_list_max) { @@ -591,7 +591,7 @@ Returns: TRUE if it did remove something; FALSE otherwise */ BOOL -receive_remove_recipient(uschar *recipient) +receive_remove_recipient(const uschar * recipient) { DEBUG(D_receive) debug_printf("receive_remove_recipient(\"%s\") called\n", recipient); @@ -3600,7 +3600,7 @@ else /* Loop through recipients, responses must be in same order received */ for (unsigned int c = 0; recipients_count > c; c++) { - uschar * addr= recipients_list[c].address; + const uschar * addr = recipients_list[c].address; uschar * msg= US"PRDR R=<%s> %s"; uschar * code; DEBUG(D_receive) diff --git a/src/src/rewrite.c b/src/src/rewrite.c index ec5c2cffc..c0d173abf 100644 --- a/src/src/rewrite.c +++ b/src/src/rewrite.c @@ -119,9 +119,9 @@ for (rewrite_rule * rule = rewrite_rules; { int start, end, pdomain; int count = 0; - uschar *save_localpart; - const uschar *save_domain; - uschar *error, *new; + const uschar * save_localpart; + const uschar * save_domain; + uschar * error, * new; const uschar * newparsed; /* Come back here for a repeat after a successful rewrite. We do this diff --git a/src/src/route.c b/src/src/route.c index 82d51bc68..0bd87b837 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -859,12 +859,12 @@ Returns: OK if all the tests succeed */ static BOOL -check_router_conditions(router_instance *r, address_item *addr, int verify, - struct passwd **pw, uschar **perror) +check_router_conditions(router_instance * r, address_item * addr, int verify, + struct passwd ** pw, uschar ** perror) { int rc; -uschar *check_local_part; -unsigned int *localpart_cache; +uschar * check_local_part; +unsigned int * localpart_cache; /* Reset variables to hold a home directory and data from lookup of a domain or local part, and ensure search_find_defer is unset, in case there aren't any @@ -928,15 +928,12 @@ because that doesn't have the prefix or suffix stripped. A bit of massaging is required. Also, we only use the match cache for local parts that have not had a prefix or suffix stripped. */ +check_local_part = string_copy(addr->cc_local_part); if (!addr->prefix && !addr->suffix) - { localpart_cache = addr->localpart_cache; - check_local_part = addr->cc_local_part; - } else { localpart_cache = NULL; - check_local_part = string_copy(addr->cc_local_part); if (addr->prefix) check_local_part += Ustrlen(addr->prefix); if (addr->suffix) diff --git a/src/src/routers/accept.c b/src/src/routers/accept.c index 63c8c22e4..8b72bfac1 100644 --- a/src/src/routers/accept.c +++ b/src/src/routers/accept.c @@ -104,9 +104,9 @@ accept_router_options_block *ob = (accept_router_options_block *)(rblock->options_block); */ int rc; -uschar *errors_to; -uschar *remove_headers; -header_line *extra_headers; +const uschar * errors_to; +uschar * remove_headers; +header_line * extra_headers; DEBUG(D_route) debug_printf("%s router called for %s\n domain = %s\n", rblock->name, addr->address, addr->domain); diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 6a17c2f8d..4c8e30563 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -306,9 +306,8 @@ redirect_router_options_block *ob = while (generated) { - address_item *parent; - address_item *next = generated; - uschar *errors_address = next->prop.errors_address; + address_item * next = generated, * parent; + const uschar * errors_address = next->prop.errors_address; generated = next->next; next->parent = addr; diff --git a/src/src/routers/rf_functions.h b/src/src/routers/rf_functions.h index 91ccfb132..40d4cde1c 100644 --- a/src/src/routers/rf_functions.h +++ b/src/src/routers/rf_functions.h @@ -15,7 +15,7 @@ extern void rf_add_generated(router_instance *, address_item **, extern void rf_change_domain(address_item *, const uschar *, BOOL, address_item **); extern uschar *rf_expand_data(address_item *, uschar *, int *); extern int rf_get_errors_address(address_item *, router_instance *, - int, uschar **); + int, const uschar **); extern int rf_get_munge_headers(address_item *, router_instance *, header_line **, uschar **); extern BOOL rf_get_transport(uschar *, transport_instance **, address_item *, diff --git a/src/src/routers/rf_get_errors_address.c b/src/src/routers/rf_get_errors_address.c index f70bdf25e..222d157d8 100644 --- a/src/src/routers/rf_get_errors_address.c +++ b/src/src/routers/rf_get_errors_address.c @@ -35,13 +35,13 @@ Returns: OK if no problem */ int -rf_get_errors_address(address_item *addr, router_instance *rblock, - int verify, uschar **errors_to) +rf_get_errors_address(address_item * addr, router_instance * rblock, + int verify, const uschar ** errors_to) { uschar *s; *errors_to = addr->prop.errors_address; -if (rblock->errors_to == NULL) return OK; +if (!rblock->errors_to) return OK; s = expand_string(rblock->errors_to); @@ -84,17 +84,14 @@ if (verify != v_none) else { BOOL save_address_test_mode = f.address_test_mode; - int save1 = 0; + const uschar * save_sender = sender_address; int i; const uschar ***p; const uschar *address_expansions_save[ADDRESS_EXPANSIONS_COUNT]; address_item *snew = deliver_make_addr(s, FALSE); if (sender_address) - { - save1 = sender_address[0]; - sender_address[0] = 0; - } + sender_address = US""; for (i = 0, p = address_expansions; *p;) address_expansions_save[i++] = **p++; @@ -124,7 +121,7 @@ else for (i = 0, p = address_expansions; *p; ) **p++ = address_expansions_save[i++]; - if (sender_address) sender_address[0] = save1; + sender_address = save_sender; } return OK; diff --git a/src/src/spf.c b/src/src/spf.c index e72051708..2e3f861eb 100644 --- a/src/src/spf.c +++ b/src/src/spf.c @@ -341,7 +341,8 @@ else for (int i = 0; i < SPF_response_messages(spf_response); i++) Return: OK/FAIL */ int -spf_process(const uschar **listptr, uschar *spf_envelope_sender, int action) +spf_process(const uschar ** listptr, const uschar * spf_envelope_sender, + int action) { int sep = 0; const uschar *list = *listptr; diff --git a/src/src/spf.h b/src/src/spf.h index 76c7522bd..afee742ed 100644 --- a/src/src/spf.h +++ b/src/src/spf.h @@ -29,7 +29,7 @@ typedef struct spf_result_id { gstring * spf_lib_version_report(gstring *); BOOL spf_init(void); BOOL spf_conn_init(uschar *, uschar *); -int spf_process(const uschar **, uschar *, int); +int spf_process(const uschar **, const uschar *, int); void spf_response_debug(SPF_response_t *); #define SPF_PROCESS_NORMAL 0 diff --git a/src/src/spool_in.c b/src/src/spool_in.c index 588effd2c..3e3b246ab 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -456,9 +456,12 @@ n = Ustrlen(big_buffer); if (n < 3 || big_buffer[0] != '<' || big_buffer[n-2] != '>') goto SPOOL_FORMAT_ERROR; -sender_address = store_get(n-2, GET_TAINTED); -Ustrncpy(sender_address, big_buffer+1, n-3); -sender_address[n-3] = 0; + { + uschar * s = store_get(n-2, GET_TAINTED); + Ustrncpy(s, big_buffer+1, n-3); + s[n-3] = '\0'; + sender_address = s; + } where = US"time"; if (Ufgets(big_buffer, big_buffer_size, fp) == NULL) goto SPOOL_READ_ERROR; diff --git a/src/src/structs.h b/src/src/structs.h index 214819482..209d657c6 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -526,7 +526,7 @@ typedef struct address_item_propagated { uschar *address_data; /* arbitrary data to keep with the address */ uschar *domain_data; /* from "domains" lookup */ uschar *localpart_data; /* from "local_parts" lookup */ - uschar *errors_address; /* where to send errors (NULL => sender) */ + const uschar *errors_address; /* where to send errors (NULL => sender) */ header_line *extra_headers; /* additional headers */ uschar *remove_headers; /* list of those to remove */ void *variables; /* router-vasriables */ @@ -561,15 +561,15 @@ typedef struct address_item { reply_item *reply; /* data for autoreply */ retry_item *retries; /* chain of retry information */ - uschar *address; /* address being delivered or routed */ + const uschar *address; /* address being delivered or routed */ uschar *unique; /* used for disambiguating */ - uschar *cc_local_part; /* caseful local part */ - uschar *lc_local_part; /* lowercased local part */ - uschar *local_part; /* points to cc or lc version */ - uschar *prefix; /* stripped prefix of local part */ - uschar *prefix_v; /* variable part of above */ - uschar *suffix; /* stripped suffix of local part */ - uschar *suffix_v; /* variable part of above */ + const uschar *cc_local_part; /* caseful local part */ + const uschar *lc_local_part; /* lowercased local part */ + const uschar *local_part; /* points to cc or lc version */ + const uschar *prefix; /* stripped prefix of local part */ + const uschar *prefix_v; /* variable part of above */ + const uschar *suffix; /* stripped suffix of local part */ + const uschar *suffix_v; /* variable part of above */ const uschar *domain; /* working domain (lower cased) */ uschar *address_retry_key; /* retry key including full address */ @@ -580,7 +580,7 @@ typedef struct address_item { uschar *message; /* error message */ uschar *user_message; /* error message that can be sent over SMTP or quoted in bounce message */ - uschar *onetime_parent; /* saved original parent for onetime */ + const uschar *onetime_parent; /* saved original parent for onetime */ uschar **pipe_expandn; /* numeric expansions for pipe from filter */ uschar *return_filename; /* name of return file */ uschar *self_hostname; /* after self=pass */ diff --git a/src/src/transport.c b/src/src/transport.c index b3b05c0a3..a0f097579 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -434,10 +434,10 @@ Returns: TRUE on success, FALSE on failure (with errno preserved) */ BOOL -write_chunk(transport_ctx * tctx, uschar *chunk, int len) +write_chunk(transport_ctx * tctx, const uschar * chunk, int len) { -uschar *start = chunk; -uschar *end = chunk + len; +const uschar * start = chunk; +const uschar * end = chunk + len; int mlen = DELIVER_OUT_BUFFER_SIZE - nl_escape_length - 2; /* The assumption is made that the check string will never stretch over move @@ -474,7 +474,7 @@ if (nl_partial_match >= 0) for possible escaping. The code for the non-NL route should be as fast as possible. */ -for (uschar * ptr = start; ptr < end; ptr++) +for (const uschar * ptr = start; ptr < end; ptr++) { int ch, len; @@ -580,7 +580,7 @@ Arguments: Returns: a string */ -uschar * +const uschar * transport_rcpt_address(address_item *addr, BOOL include_affixes) { uschar *at; @@ -704,7 +704,7 @@ Returns: TRUE on success; FALSE on failure. */ BOOL transport_headers_send(transport_ctx * tctx, - BOOL (*sendfn)(transport_ctx * tctx, uschar * s, int len)) + BOOL (*sendfn)(transport_ctx * tctx, const uschar * s, int len)) { const uschar * list; transport_instance * tblock = tctx ? tctx->tblock : NULL; @@ -2302,7 +2302,7 @@ if (flags & TSUC_EXPAND_ARGS) address_pipe_argv = store_get((address_pipe_max_args+1)*sizeof(uschar *), GET_UNTAINTED); /* +1 because addr->local_part[0] == '|' since af_force_command is set */ - s = expand_string(addr->local_part + 1); + s = expand_cstring(addr->local_part + 1); if (!s || !*s) { diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 2c7bea11d..ec41ca035 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -502,7 +502,7 @@ Returns: nothing */ static void -notify_comsat(uschar *user, off_t offset) +notify_comsat(const uschar * user, off_t offset) { struct servent *sp; host_item host; diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index b9cc32df1..64c70e719 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -292,7 +292,7 @@ Returns: TRUE if all went well; otherwise an error will be */ static BOOL -set_up_direct_command(const uschar *** argvptr, uschar * cmd, +set_up_direct_command(const uschar *** argvptr, const uschar * cmd, BOOL expand_arguments, int expand_fail, address_item * addr, uschar * tname, pipe_transport_options_block * ob) { @@ -414,8 +414,8 @@ Returns: TRUE if all went well; otherwise an error will be */ static BOOL -set_up_shell_command(const uschar ***argvptr, uschar *cmd, - BOOL expand_arguments, int expand_fail, address_item *addr, uschar *tname) +set_up_shell_command(const uschar *** argvptr, const uschar * cmd, + BOOL expand_arguments, int expand_fail, address_item * addr, uschar * tname) { const uschar **argv; @@ -462,10 +462,10 @@ if (expand_arguments) } g = string_cat(g, q); - argv[2] = (cmd = string_from_gstring(g)) ? expand_string(cmd) : NULL; + argv[2] = (cmd = string_from_gstring(g)) ? expand_cstring(cmd) : NULL; } else - argv[2] = expand_string(cmd); + argv[2] = expand_cstring(cmd); f.enable_dollar_recipients = FALSE; @@ -518,11 +518,12 @@ pipe_transport_options_block *ob = int timeout = ob->timeout; BOOL written_ok = FALSE; BOOL expand_arguments; -const uschar **argv; -uschar *envp[50]; -const uschar *envlist = ob->environment; -uschar *cmd, *ss; -uschar *eol = ob->use_crlf ? US"\r\n" : US"\n"; +const uschar ** argv; +uschar * envp[50]; +const uschar * envlist = ob->environment; +const uschar * cmd; +uschar * ss; +uschar * eol = ob->use_crlf ? US"\r\n" : US"\n"; transport_ctx tctx = { .tblock = tblock, .addr = addr, diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 8c00a1ef2..c53e1000f 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -656,8 +656,7 @@ static void deferred_event_raise(address_item * addr, host_item * host, uschar * evstr) { uschar * action = addr->transport->event_action; -const uschar * save_domain; -uschar * save_local; +const uschar * save_domain, * save_local; if (!action) return; @@ -1793,7 +1792,7 @@ return FALSE; typedef struct smtp_compare_s { - uschar * current_sender_address; + const uschar * current_sender_address; struct transport_instance * tblock; } smtp_compare_t; @@ -1803,7 +1802,7 @@ sender_address, helo_data and tls_certificate if enabled. */ static uschar * -smtp_local_identity(uschar * sender, struct transport_instance * tblock) +smtp_local_identity(const uschar * sender, struct transport_instance * tblock) { address_item * addr1; uschar * if1 = US""; @@ -1811,7 +1810,7 @@ uschar * helo1 = US""; #ifndef DISABLE_TLS uschar * tlsc1 = US""; #endif -uschar * save_sender_address = sender_address; +const uschar * save_sender_address = sender_address; uschar * local_identity = NULL; smtp_transport_options_block * ob = SOB tblock->options_block; @@ -3434,7 +3433,7 @@ buffer. */ sx->pending_MAIL = TRUE; /* The block starts with MAIL */ { - uschar * s = sx->from_addr; + const uschar * s = sx->from_addr; #ifdef SUPPORT_I18N uschar * errstr = NULL; @@ -3505,7 +3504,7 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; { int cmds_sent; BOOL no_flush; - uschar * rcpt_addr; + const uschar * rcpt_addr; #ifdef EXPERIMENTAL_ESMTP_LIMITS if ( sx->single_rcpt_domain /* restriction on domains */ diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index 0d15b9626..1f888ee0b 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -140,7 +140,7 @@ typedef struct { /* smtp connect context */ typedef struct { - uschar * from_addr; + const uschar * from_addr; address_item * addrlist; smtp_connect_args conn_args; diff --git a/src/src/verify.c b/src/src/verify.c index 6361aa434..bc3666285 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -105,8 +105,8 @@ Return: TRUE if result found */ static BOOL -cached_callout_lookup(address_item * addr, uschar * address_key, - uschar * from_address, int * opt_ptr, uschar ** pm_ptr, +cached_callout_lookup(address_item * addr, const uschar * address_key, + const uschar * from_address, int * opt_ptr, uschar ** pm_ptr, int * yield, uschar ** failure_ptr, dbdata_callout_cache * new_domain_record, int * old_domain_res) { @@ -278,10 +278,10 @@ return FALSE; */ static void cache_callout_write(dbdata_callout_cache * dom_rec, const uschar * domain, - int done, dbdata_callout_cache_address * addr_rec, uschar * address_key) + int done, dbdata_callout_cache_address * addr_rec, const uschar * address_key) { open_db dbblock; -open_db *dbm_file = NULL; +open_db * dbm_file = NULL; /* If we get here with done == TRUE, a successful callout happened, and yield will be set OK or FAIL according to the response to the RCPT command. @@ -502,11 +502,11 @@ do_callout(address_item *addr, host_item *host_list, transport_feedback *tf, int yield = OK; int old_domain_cache_result = ccache_accept; BOOL done = FALSE; -uschar *address_key; -uschar *from_address; -uschar *random_local_part = NULL; -const uschar *save_deliver_domain = deliver_domain; -uschar **failure_ptr = options & vopt_is_recipient +const uschar * address_key; +const uschar * from_address; +uschar * random_local_part = NULL; +const uschar * save_deliver_domain = deliver_domain; +uschar ** failure_ptr = options & vopt_is_recipient ? &recipient_verify_failure : &sender_verify_failure; dbdata_callout_cache new_domain_record; dbdata_callout_cache_address new_address_record; @@ -771,7 +771,7 @@ tls_retry_connection: if (random_local_part) { - uschar * main_address = addr->address; + const uschar * main_address = addr->address; const uschar * rcpt_domain = addr->domain; #ifdef SUPPORT_I18N @@ -942,7 +942,7 @@ tls_retry_connection: if (done) { - uschar * main_address = addr->address; + const uschar * main_address = addr->address; /*XXX oops, affixes */ addr->address = string_sprintf("postmaster@%.1000s", addr->domain); @@ -1286,7 +1286,7 @@ return FALSE; static BOOL -_cutthrough_puts(uschar * cp, int n) +_cutthrough_puts(const uschar * cp, int n) { while(n--) { @@ -1301,7 +1301,7 @@ return TRUE; /* Buffered output of counted data block. Return boolean success */ static BOOL -cutthrough_puts(uschar * cp, int n) +cutthrough_puts(const uschar * cp, int n) { if (cutthrough.cctx.sock < 0) return TRUE; if (_cutthrough_puts(cp, n)) return TRUE; @@ -1407,9 +1407,9 @@ return cutthrough_response(&cutthrough.cctx, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) /* tctx arg only to match write_chunk() */ static BOOL -cutthrough_write_chunk(transport_ctx * tctx, uschar * s, int len) +cutthrough_write_chunk(transport_ctx * tctx, const uschar * s, int len) { -uschar * s2; +const uschar * s2; while(s && (s2 = Ustrchr(s, '\n'))) { if(!cutthrough_puts(s, s2-s) || !cutthrough_put_nl()) @@ -1697,16 +1697,16 @@ int yield = OK; int verify_type = expn ? v_expn : f.address_test_mode ? v_none : options & vopt_is_recipient ? v_recipient : v_sender; -address_item *addr_list; -address_item *addr_new = NULL; -address_item *addr_remote = NULL; -address_item *addr_local = NULL; -address_item *addr_succeed = NULL; -uschar **failure_ptr = options & vopt_is_recipient +address_item * addr_list; +address_item * addr_new = NULL; +address_item * addr_remote = NULL; +address_item * addr_local = NULL; +address_item * addr_succeed = NULL; +uschar ** failure_ptr = options & vopt_is_recipient ? &recipient_verify_failure : &sender_verify_failure; -uschar *ko_prefix, *cr; -uschar *address = vaddr->address; -uschar *save_sender; +uschar * ko_prefix, * cr; +const uschar * address = vaddr->address; +const uschar * save_sender; uschar null_sender[] = { 0 }; /* Ensure writeable memory */ /* Clear, just in case */ @@ -1751,9 +1751,8 @@ may have been set by domains and local part tests during an ACL. */ if (global_rewrite_rules) { - uschar *old = address; - /* deconst ok as address was not const */ - address = US rewrite_address(address, options & vopt_is_recipient, FALSE, + const uschar * old = address; + address = rewrite_address(address, options & vopt_is_recipient, FALSE, global_rewrite_rules, rewrite_existflags); if (address != old) { @@ -1919,8 +1918,8 @@ while (addr_new) if (tf.hosts && (!host_list || tf.hosts_override)) { uschar *s; - const uschar *save_deliver_domain = deliver_domain; - uschar *save_deliver_localpart = deliver_localpart; + const uschar * save_deliver_domain = deliver_domain; + const uschar * save_deliver_localpart = deliver_localpart; host_list = NULL; /* Ignore the router's hosts */ @@ -2455,11 +2454,11 @@ verify_check_notblind(BOOL case_sensitive) for (int i = 0; i < recipients_count; i++) { BOOL found = FALSE; - uschar *address = recipients_list[i].address; + const uschar * address = recipients_list[i].address; for (header_line * h = header_list; !found && h; h = h->next) { - uschar *colon, *s; + uschar * colon, * s; if (h->type != htype_to && h->type != htype_cc) continue; @@ -2533,7 +2532,7 @@ Returns: pointer to an address item, or NULL */ address_item * -verify_checked_sender(uschar *sender) +verify_checked_sender(const uschar * sender) { for (address_item * addr = sender_verified_list; addr; addr = addr->next) if (Ustrcmp(sender, addr->address) == 0) return addr; commit 9643095d7cae6866b716d361a45c9a95f605040c Author: Andrew Aitchison Date: Thu Nov 16 17:09:57 2023 +0000 Compiler quiteneing diff --git a/src/src/globals.h b/src/src/globals.h index dff3762a8..fe4a1610a 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -323,7 +323,7 @@ extern uschar *acl_smtp_connect; /* ACL run on SMTP connection */ extern uschar *acl_smtp_data; /* ACL run after DATA received */ #ifndef DISABLE_PRDR extern uschar *acl_smtp_data_prdr; /* ACL run after DATA received if in PRDR mode*/ -const extern pcre2_code *regex_PRDR; /* For recognizing PRDR settings */ +extern const pcre2_code *regex_PRDR; /* For recognizing PRDR settings */ #endif #ifndef DISABLE_DKIM extern uschar *acl_smtp_dkim; /* ACL run for DKIM signatures / domains */ @@ -752,7 +752,7 @@ extern uschar *message_size_limit; /* As it says */ #ifdef SUPPORT_I18N extern BOOL message_smtputf8; /* Internationalized mail handling */ extern int message_utf8_downconvert; /* convert from utf8 */ -const extern pcre2_code *regex_UTF8; /* For recognizing SMTPUTF8 settings */ +extern const pcre2_code *regex_UTF8; /* For recognizing SMTPUTF8 settings */ #endif extern uschar message_subdir[]; /* Subdirectory for messages */ extern const uschar *message_reference;/* Reference for error messages */ commit 79670d3c32ccb37fe06f25d8192943b58606a32a Author: Jeremy Harris Date: Fri Nov 17 16:55:17 2023 +0000 Lookups: Fix dnsdb lookup of multi-chunk TXT. Bug 3054 Broken=by: f6b1f8e7d642 diff --git a/src/src/dns.c b/src/src/dns.c index a652dcd31..74c5a58c5 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -431,7 +431,9 @@ namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, dnss->aptr, if (namelen < 0) goto null_return; /* Move the pointer past the name and fill in the rest of the data structure -from the following bytes. */ +from the following bytes. We seem to be assuming here that the RR blob passed +to us by the resolver library is the same as that defined for an RR by RFC 1035 +section 3.2.1 */ TRACE trace = "R-name"; if (dnss_inc_aptr(dnsa, dnss, namelen)) goto null_return; diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index ff51dec23..8288896ca 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -387,38 +387,31 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) } /* Other kinds of record just have one piece of data each, but there may be - several of them, of course. */ + several of them, of course. TXT & SPF can have data in multiple chunks. */ if (yield->ptr) yield = string_catn(yield, outsep, 1); if (type == T_TXT || type == T_SPF) - { - if (!outsep2) /* output only the first item of data */ + for (unsigned data_offset = 0; data_offset + 1 < rr->size; ) { - uschar n = (rr->data)[0]; - /* size byte + data bytes must not excced the RRs length */ - if (n + 1 <= rr->size) - yield = string_catn(yield, US (rr->data+1), n); + uschar chunk_len = (rr->data)[data_offset]; + int remain; + + if (outsep2 && *outsep2 && data_offset != 0) + yield = string_catn(yield, outsep2, 1); + + /* Apparently there are resolvers that do not check RRs before passing + them on, and glibc fails to do so. So every application must... + Check for chunk len exceeding RR */ + + remain = rr->size - ++data_offset; + if (chunk_len > remain) + chunk_len = remain; + yield = string_catn(yield, US ((rr->data) + data_offset), chunk_len); + data_offset += chunk_len; + + if (!outsep2) break; /* output only the first chunk of the RR */ } - else - for (unsigned data_offset = 0; data_offset < rr->size; ) - { - uschar chunk_len = (rr->data)[data_offset]; - int remain = rr->size - data_offset; - - /* Apparently there are resolvers that do not check RRs before passing - them on, and glibc fails to do so. So every application must... - Check for chunk len exceeding RR */ - - if (chunk_len > remain) - chunk_len = remain; - - if (*outsep2 && data_offset != 0) - yield = string_catn(yield, outsep2, 1); - yield = string_catn(yield, US ((rr->data) + ++data_offset), --chunk_len); - data_offset += chunk_len; - } - } else if (type == T_TLSA) if (rr->size < 3) continue; commit 1d19531abc45f656eff8f3dd5ba6986d919fee11 Author: Jeremy Harris Date: Sun Nov 19 11:31:45 2023 +0000 Support old-format message_id spoolfiles for mailq / -bp. Bug 3050 Broken-by: 46a36afae41f diff --git a/src/src/queue.c b/src/src/queue.c index deedcde6f..2c3d014f5 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -961,7 +961,9 @@ each time. */ if (option == QL_MSGID_ONLY) /* Print only the message IDs from the chain */ for (; qf; qf = qf->next) - fprintf(stdout, "%.*s\n", MESSAGE_ID_LENGTH, qf->text); + fprintf(stdout, "%.*s\n", + is_old_message_id(qf->text) ? MESSAGE_ID_LENGTH_OLD : MESSAGE_ID_LENGTH, + qf->text); else for (; qf && (reset_point = store_mark()); @@ -1021,7 +1023,9 @@ else for (; } fprintf(stdout, "%s %.*s", - string_format_size(size, big_buffer), MESSAGE_ID_LENGTH, qf->text); + string_format_size(size, big_buffer), + is_old_message_id(qf->text) ? MESSAGE_ID_LENGTH_OLD : MESSAGE_ID_LENGTH, + qf->text); if (env_read && sender_address) { commit 8213f508a8c66e7ed8e00a9123f72763ff99010b Author: Jeremy Harris Date: Sat Nov 25 15:46:12 2023 +0000 DMARC: fix reporting, no-ARC-support case diff --git a/src/src/dmarc.c b/src/src/dmarc.c index 042ebe982..f684e08ea 100644 --- a/src/src/dmarc.c +++ b/src/src/dmarc.c @@ -311,7 +311,7 @@ g = string_fmt_append(g, "align_dkim %d\nalign_spf %d\naction %d\n", # ifdef EXPERIMENTAL_ARC g = arc_dmarc_hist_append(g); # else -g = string_fmt_append(g, "arc %d\narc_policy $d json:[]\n", +g = string_fmt_append(g, "arc %d\narc_policy %d json:[]\n", ARES_RESULT_UNKNOWN, DMARC_ARC_POLICY_RESULT_UNUSED); # endif #endif commit 33c9e43ec040c0a29394d8e3b745180ddddc0ed8 Author: Jeremy Harris Date: Sat Nov 25 16:47:35 2023 +0000 DMARC: fix reporting, ARC-support but not in message diff --git a/src/src/arc.c b/src/src/arc.c index defe9b171..bd2fa3bae 100644 --- a/src/src/arc.c +++ b/src/src/arc.c @@ -2011,7 +2011,7 @@ if (arc_state) g = string_catn(g, US" ]\n", 3); } else - g = string_fmt_append(g, "arc %d\narc_policy $d json:[]\n", + g = string_fmt_append(g, "arc %d\narc_policy %d json:[]\n", ARES_RESULT_UNKNOWN, DMARC_ARC_POLICY_RESULT_UNUSED); return g; } commit 5d0d124a8b49b484cda869bcb0d3e5224716d276 Author: Jeremy Harris Date: Sun Nov 26 20:28:07 2023 +0000 Unbreak DISABLE_TLS_RESUME build Broken-by: 5d5ad9fb16a2 diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index c53e1000f..4cf58436d 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -761,13 +761,14 @@ return TRUE; } +#if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME) + /* Grab a string differentiating server behind a loadbalancer, for TLS resumption when such servers do not share a session-cache */ static void ehlo_response_lbserver(smtp_context * sx, const uschar * name_extract) { -#if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME) const uschar * s; uschar * save_item = iterate_item; @@ -778,8 +779,8 @@ s = expand_cstring(name_extract); iterate_item = save_item; sx->conn_args.host_lbserver = s && !*s ? NULL : s; sx->conn_args.have_lbserver = TRUE; -#endif } +#endif @@ -1075,9 +1076,11 @@ if (pending_BANNER) } /*XXX EXPERIMENTAL_ESMTP_LIMITS ? */ +# ifndef DISABLE_TLS_RESUME s = ((smtp_transport_options_block *)sx->conn_args.ob)->host_name_extract; if (!s) s = HNE_DEFAULT; ehlo_response_lbserver(sx, s); +# endif } if (pending_EHLO) @@ -2482,13 +2485,14 @@ goto SEND_QUIT; ob->tls_tempfail_tryclear = FALSE; smtp_command = US"SSL-on-connect"; +# ifndef DISABLE_TLS_RESUME /* Having no EHLO response yet, cannot peek there for a servername to detect an LB. Call this anyway, so that a dummy host_name_extract option value can force resumption attempts. */ if (!(s = ob->host_name_extract)) s = US"never-LB"; ehlo_response_lbserver(sx, s); - +# endif goto TLS_NEGOTIATE; } #endif @@ -2613,8 +2617,10 @@ goto SEND_QUIT; } } #endif +#ifndef DISABLE_TLS_RESUME if (!(s = ob->host_name_extract)) s = HNE_DEFAULT; ehlo_response_lbserver(sx, s); +#endif } /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */ commit 5bca25510e7313419c4ed0107ae153177bee938c Author: Jeremy Harris Date: Mon Nov 27 17:51:25 2023 +0000 Build: fix for Solaris 11 diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 8288896ca..050baa3b7 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -445,20 +445,20 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) switch (type) { case T_MXH: - if (rr_bad_size(rr, sizeof(u_int16_t))) continue; + if (rr_bad_size(rr, sizeof(uint16_t))) continue; /* mxh ignores the priority number and includes only the hostnames */ GETSHORT(priority, p); break; case T_MX: - if (rr_bad_size(rr, sizeof(u_int16_t))) continue; + if (rr_bad_size(rr, sizeof(uint16_t))) continue; GETSHORT(priority, p); sprintf(CS s, "%d%c", priority, *outsep2); yield = string_cat(yield, s); break; case T_SRV: - if (rr_bad_size(rr, 3*sizeof(u_int16_t))) continue; + if (rr_bad_size(rr, 3*sizeof(uint16_t))) continue; GETSHORT(priority, p); GETSHORT(weight, p); GETSHORT(port, p); @@ -468,7 +468,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) break; case T_CSA: - if (rr_bad_size(rr, 3*sizeof(u_int16_t))) continue; + if (rr_bad_size(rr, 3*sizeof(uint16_t))) continue; /* See acl_verify_csa() for more comments about CSA. */ GETSHORT(priority, p); GETSHORT(weight, p); commit e4520c7817b76d6a5453237d94b1ed10fa6d2ef3 Author: Jeremy Harris Date: Fri Dec 1 15:44:57 2023 +0000 Avoid trying to send smtp repoonse for non-smtp input, on datafile close error Broken-by: f70940c9489d diff --git a/src/src/receive.c b/src/src/receive.c index a459061ef..c4b80c236 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -4425,8 +4425,8 @@ if (spool_data_file && cutthrough_done == NOT_TRIED) Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H")); Uunlink(spool_fname(US"msglog", message_subdir, message_id, US"")); - /* Claim a data ACL temp-reject, just to get reject logging and resposponse */ - smtp_handle_acl_fail(ACL_WHERE_DATA, rc, NULL, log_msg); + /* Claim a data ACL temp-reject, just to get reject logging and response */ + if (smtp_input) smtp_handle_acl_fail(ACL_WHERE_DATA, rc, NULL, log_msg); smtp_reply = US""; /* Indicate reply already sent */ message_id[0] = 0; /* no message accepted */ commit 87229a18d1fbe959d38f82bde661b57fed11d220 Author: Jeremy Harris Date: Tue Dec 5 17:49:06 2023 +0000 Compiler quietening diff --git a/src/src/verify.c b/src/src/verify.c index bc3666285..d080ddd63 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -3005,6 +3005,8 @@ if ((semicolon = Ustrchr(ss, ';'))) endname = semicolon; opts = NULL; } +else + opts = NULL; /* If we are doing an IP address only match, then all lookups must be IP address lookups, even if there is no "net-". */ commit 2658a023286fcce529031e9f071c5579650687b8 Author: Jeremy Harris Date: Tue Dec 5 21:23:46 2023 +0000 DKIM: tighten up parsing for DKIM DNS and header records. Bug 3056 diff --git a/src/src/functions.h b/src/src/functions.h index 74cd15424..b201467b2 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -760,7 +760,7 @@ return US strncpy(CS dst, CCS src, n); /* Advance the string pointer given over any whitespace. -Return the next char as there's enought places using it to be useful. */ +Return the next char as there's enough places using it to be useful. */ #define Uskip_whitespace(sp) skip_whitespace(CUSS sp) diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index c723ae6c8..21e17c61e 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -512,10 +512,6 @@ for (uschar * p = raw_hdr; ; p++) } if (where == PDKIM_HDR_TAG) - { - if (c >= 'a' && c <= 'z') - cur_tag = string_catn(cur_tag, p, 1); - if (c == '=') { if (Ustrcmp(string_from_gstring(cur_tag), "b") == 0) @@ -526,7 +522,8 @@ for (uschar * p = raw_hdr; ; p++) where = PDKIM_HDR_VALUE; goto NEXT_CHAR; } - } + else if (!isspace(c)) + cur_tag = string_catn(cur_tag, p, 1); if (where == PDKIM_HDR_VALUE) { @@ -553,17 +550,17 @@ for (uschar * p = raw_hdr; ; p++) switch (cur_tag->s[1]) { case '\0': pdkim_decode_base64(cur_val->s, &sig->sighash); break; - case 'h': if (cur_tag->ptr == 2) - pdkim_decode_base64(cur_val->s, &sig->bodyhash); + case 'h': if (cur_tag->ptr != 2) goto bad_tag; + pdkim_decode_base64(cur_val->s, &sig->bodyhash); break; - default: break; + default: goto bad_tag; } break; case 'v': /* version */ /* We only support version 1, and that is currently the only version there is. */ sig->version = - Ustrcmp(cur_val->s, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1; + Ustrcmp(cur_val->s, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1; break; case 'a': /* algorithm */ { @@ -578,6 +575,7 @@ for (uschar * p = raw_hdr; ; p++) if (Ustrcmp(elem, pdkim_hashes[i].dkim_hashname) == 0) { sig->hashtype = i; break; } } + break; case 'c': /* canonicalization */ pdkim_cstring_to_canons(cur_val->s, 0, @@ -586,15 +584,15 @@ for (uschar * p = raw_hdr; ; p++) case 'q': /* Query method (for pubkey)*/ for (int i = 0; pdkim_querymethods[i]; i++) if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0) - { + { sig->querymethod = i; /* we never actually use this */ break; } break; case 's': /* Selector */ - sig->selector = string_copyn(cur_val->s, cur_val->ptr); break; + sig->selector = string_copy_from_gstring(cur_val); break; case 'd': /* SDID */ - sig->domain = string_copyn(cur_val->s, cur_val->ptr); break; + sig->domain = string_copy_from_gstring(cur_val); break; case 'i': /* AUID */ sig->identity = pdkim_decode_qp(cur_val->s); break; case 't': /* Timestamp */ @@ -604,16 +602,18 @@ for (uschar * p = raw_hdr; ; p++) case 'l': /* Body length count */ sig->bodylength = strtol(CS cur_val->s, NULL, 10); break; case 'h': /* signed header fields */ - sig->headernames = string_copyn(cur_val->s, cur_val->ptr); break; + sig->headernames = string_copy_from_gstring(cur_val); break; case 'z': /* Copied headfields */ sig->copiedheaders = pdkim_decode_qp(cur_val->s); break; /*XXX draft-ietf-dcrup-dkim-crypto-05 would need 'p' tag support for rsafp signatures. But later discussion is dropping those. */ default: - DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); - break; + goto bad_tag; } } + else +bad_tag: DEBUG(D_acl) debug_printf(" Unknown tag encountered: %Y\n", cur_tag); + cur_tag = cur_val = NULL; in_b_val = FALSE; where = PDKIM_HDR_LIMBO; @@ -659,25 +659,37 @@ return sig; /* -------------------------------------------------------------------------- */ pdkim_pubkey * -pdkim_parse_pubkey_record(const uschar *raw_record) +pdkim_parse_pubkey_record(const uschar * raw_record) { -const uschar * ele; -int sep = ';'; -pdkim_pubkey * pub; +pdkim_pubkey * pub = store_get(sizeof(pdkim_pubkey), GET_TAINTED); -pub = store_get(sizeof(pdkim_pubkey), GET_TAINTED); memset(pub, 0, sizeof(pdkim_pubkey)); -while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0))) +for (const uschar * ele = raw_record, * tspec, * end, * val; *ele; ele = end) { - const uschar * val; + Uskip_whitespace(&ele); + end = US strchrnul(CS ele, ';'); + tspec = string_copyn(ele, end - ele); + if (*end) end++; /* skip the ; */ - if ((val = Ustrchr(ele, '='))) + if ((val = Ustrchr(tspec, '='))) { - int taglen = val++ - ele; + int taglen = val++ - tspec; + + DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, tspec, val); + while (taglen > 1 && isspace(tspec[taglen-1])) + taglen--; /* Ignore whitespace before = */ + while (isspace(*val)) + val++; /* Ignore whitespace after = */ + if (isspace(val[ Ustrlen(val)-1 ])) + { /* Ignore whitespace after value */ + gstring * g = string_cat(NULL, val); + while (isspace(gstring_last_char(g))) + gstring_trim(g, 1); + val = string_from_gstring(g); + } - DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val); - switch (ele[0]) + if (taglen == 1) switch (tspec[0]) { case 'v': pub->version = val; break; case 'h': pub->hashes = val; break; @@ -689,8 +701,11 @@ while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0))) case 't': if (Ustrchr(val, 'y')) pub->testing = 1; if (Ustrchr(val, 's')) pub->no_subdomaining = 1; break; - default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break; + default: goto bad_tag; } + else +bad_tag: + DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); } } commit 5930166b443390a522f210c2e60ec447a7dbd080 Author: Jeremy Harris Date: Wed Dec 6 12:25:14 2023 +0000 Supply strchrnul() for platforms apparently missing it Broken-by: 2658a023286f diff --git a/src/OS/os.h-FreeBSD b/src/OS/os.h-FreeBSD index 6756d42f6..11f8b1ae7 100644 --- a/src/OS/os.h-FreeBSD +++ b/src/OS/os.h-FreeBSD @@ -78,5 +78,7 @@ extern ssize_t os_sendfile(int, int, off_t *, size_t); /*******************/ #define EXIM_HAVE_KEVENT +#define EXIM_HAVE_STRCHRNUL + /* End */ diff --git a/src/OS/os.h-Linux b/src/OS/os.h-Linux index 25a12862b..cebda3367 100644 --- a/src/OS/os.h-Linux +++ b/src/OS/os.h-Linux @@ -102,4 +102,6 @@ then change the 0 to 1 in the next block. */ # define NS_MAXMSG 65535 #endif +#define EXIM_HAVE_STRCHRNUL + /* End */ diff --git a/src/src/os.c b/src/src/os.c index 5c52c6d4d..5e5899eeb 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -893,6 +893,21 @@ return buffer ? buffer : realloc(b, strlen(b) + 1); #endif /* ----------------------------------------------------------------------- */ +/*********************************************************** +* strchrnul() * +***********************************************************/ + +#if !defined(EXIM_HAVE_STRCHRNUL) +char * +strchrnul(const char * s, int c) +{ +while (*s != c && *s) s++ +return CS s; +} +#endif + + +/* ----------------------------------------------------------------------- */ commit b0e63c7efdc2133c61545b051042d3617ecd2bbd Author: Jeremy Harris Date: Wed Dec 6 19:54:40 2023 +0000 Logging: ensure that an error for a mistyped IPv6 address in a search list is available for logging. Bug 3057 diff --git a/src/src/match.c b/src/src/match.c index df440108e..8b1a3bef6 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -886,14 +886,19 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error); goto OK_RETURN; - case ERROR: /* host name lookup failed - this can only */ - if (ignore_unknown) /* be for an incoming host (not outgoing) */ + /* The ERROR return occurs when checking hosts, when either a forward + or reverse lookup has failed. It can also occur in a match_ip list if a + non-IP address item is encountered. The error string gives details of + which it was. */ + + case ERROR: + if (ignore_unknown) { HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_unknown\n", error); } else - { + { HDEBUG(D_lists) debug_printf_indent("%s %s (%s)\n", ot, include_unknown? "yes":"no", error); (void)fclose(f); diff --git a/src/src/string.c b/src/src/string.c index dfe0f2451..3bf2f1df7 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -57,6 +57,7 @@ union { /* we do not need this, but inet_pton() needs a place for storage */ we return failure, as we do if the mask isn't a pure numerical value, or if it is negative. The actual length is checked later, once we know the address family. */ + if (slash = Ustrchr(ip_addr, '/')) { uschar * rest; @@ -74,10 +75,11 @@ if (slash = Ustrchr(ip_addr, '/')) return 0; } - *maskptr = slash - ip_addr; /* offset of the slash */ + *maskptr = slash - ip_addr; /* offset of the slash */ endp = slash; } -else if (maskptr) *maskptr = 0; /* no slash found */ +else if (maskptr) + *maskptr = 0; /* no slash found */ /* The interface-ID suffix (%) is optional (for IPv6). If it exists, we check it syntactically. Later, if we know the address @@ -160,7 +162,7 @@ switch (af) int string_is_ip_address(const uschar * ip_addr, int * maskptr) { -return string_is_ip_addressX(ip_addr, maskptr, 0); +return string_is_ip_addressX(ip_addr, maskptr, NULL); } #endif /* COMPILE_UTILITY */ diff --git a/src/src/verify.c b/src/src/verify.c index d080ddd63..194e9a76a 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -2971,7 +2971,7 @@ if (*ss == '@') a (possibly masked) comparison with the current IP address. */ if (string_is_ip_address(ss, &maskoffset) != 0) - return (host_is_in_net(cb->host_address, ss, maskoffset)? OK : FAIL); + return host_is_in_net(cb->host_address, ss, maskoffset) ? OK : FAIL; /* The pattern is not an IP address. A common error that people make is to omit one component of an IPv4 address, either by accident, or believing that, for @@ -2982,13 +2982,25 @@ ancient specification.) To aid in debugging these cases, we give a specific error if the pattern contains only digits and dots or contains a slash preceded only by digits and dots (a slash at the start indicates a file name and of course slashes may be present in lookups, but not preceded only by digits and -dots). */ +dots). Then the equivalent for IPv6 (roughly). */ -for (t = ss; isdigit(*t) || *t == '.'; ) t++; -if (!*t || (*t == '/' && t != ss)) +if (Ustrchr(ss, ':')) { - *error = string_sprintf("malformed IPv4 address or address mask: %.*s", (int)(t - ss), ss); - return ERROR; + for (t = ss; isxdigit(*t) || *t == ':' || *t == '.'; ) t++; + if (!*t || (*t == '/' || *t == '%') && t != ss) + { + *error = string_sprintf("malformed IPv6 address or address mask: %.*s", (int)(t - ss), ss); + return ERROR; + } + } +else + { + for (t = ss; isdigit(*t) || *t == '.'; ) t++; + if (!*t || (*t == '/' && t != ss)) + { + *error = string_sprintf("malformed IPv4 address or address mask: %.*s", (int)(t - ss), ss); + return ERROR; + } } /* See if there is a semicolon in the pattern, separating a searchtype commit b037dd69615b2ce9e084932e8a61477afc67345e Author: Jeremy Harris Date: Wed Dec 6 22:08:08 2023 +0000 typo Broken-by: 5930166b4433 diff --git a/src/src/os.c b/src/src/os.c index 5e5899eeb..c6d1e06c2 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -901,7 +901,7 @@ return buffer ? buffer : realloc(b, strlen(b) + 1); char * strchrnul(const char * s, int c) { -while (*s != c && *s) s++ +while (*s != c && *s) s++; return CS s; } #endif commit ce336ea1afd8d5f6b79d36fc7ec4313f3d80146b Author: Jeremy Harris Date: Thu Dec 7 19:59:35 2023 +0000 Handle expansion fails in router "set" options. Bug 3058 diff --git a/src/src/route.c b/src/src/route.c index 0bd87b837..3401f15b4 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -1492,7 +1492,11 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); ) { addr->message = string_sprintf("expansion of \"%s\" failed " "in %s router: %s", ele, r->name, expand_string_message); - return DEFER; + /* Caller will replace that for logging, if a DB lookup, to avoid exposing + passwords */ + DEBUG(D_route) debug_printf("%s\n", addr->message); + if (!f.search_find_defer) + return f.search_find_defer ? DEFER : FAIL; } if (!(node = tree_search(*root, name))) @@ -1546,8 +1550,8 @@ route_address(address_item *addr, address_item **paddr_local, { int yield = OK; BOOL unseen; -router_instance *r, *nextr; -const uschar *old_domain = addr->domain; +router_instance * r, * nextr; +const uschar * old_domain = addr->domain; HDEBUG(D_route) { @@ -1561,8 +1565,8 @@ instead of at the first router. */ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) { - uschar *error; - struct passwd *pw = NULL; + uschar * error; + struct passwd * pw = NULL; struct passwd pwcopy; BOOL loop_detected = FALSE; BOOL more; @@ -1736,11 +1740,11 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) router traversal. On the addr string they are held as a variable tree, so as to maintain the post-expansion taints separate. */ - switch (set_router_vars(addr, r)) + switch (rc = set_router_vars(addr, r)) { case OK: break; case PASS: continue; /* with next router */ - default: goto ROUTE_EXIT; + default: yield = rc; goto ROUTE_EXIT; } /* Finally, expand the address_data field in the router. Forced failure commit ced0bbf43860a2e4ddc88e3ba20ae731324586c5 Author: Jeremy Harris Date: Fri Dec 15 21:05:32 2023 +0000 Fix periodic queue runs. Bug 3046 Broken-by: 7d5055276a22 diff --git a/src/src/daemon.c b/src/src/daemon.c index f2183c735..aff05120a 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -1258,10 +1258,9 @@ static const uschar * queuerun_msg_qname; /* The notifier socket has something to read. Pull the message from it, decode and do the action. +*/ -Return TRUE if a sigalrm should be emulated */ - -static BOOL +static void daemon_notification(void) { uschar buf[256], cbuf[256]; @@ -1277,8 +1276,8 @@ struct msghdr msg = { .msg_name = &sa_un, ssize_t sz; buf[sizeof(buf)-1] = 0; -if ((sz = recvmsg(daemon_notifier_fd, &msg, 0)) <= 0) return FALSE; -if (sz >= sizeof(buf)) return FALSE; +if ((sz = recvmsg(daemon_notifier_fd, &msg, 0)) <= 0) return; +if (sz >= sizeof(buf)) return; #ifdef notdef debug_printf("addrlen %d\n", msg.msg_namelen); @@ -1351,7 +1350,7 @@ switch (buf[0]) : !buf[1+MESSAGE_ID_LENGTH+1] ) { queuerun_msg_qname = q->name; break; } - return TRUE; + return; #endif case NOTIFY_QUEUE_SIZE_REQ: @@ -1373,7 +1372,7 @@ switch (buf[0]) regex_at_daemon(buf); break; } -return FALSE; +return; } @@ -1432,7 +1431,7 @@ for (qrunner * q = qrunners, * next; q; q = next) if (sorted) { qrunner ** p = &sorted; - for (qrunner * qq; qq = *p; p = &(qq->next)) + for (qrunner * qq; qq = *p; p = &qq->next) if ( q->next_tick < qq->next_tick || q->next_tick == qq->next_tick && q->interval < qq->interval ) @@ -1451,6 +1450,13 @@ qrunners = sorted; return qrunners ? qrunners->next_tick - time(NULL) : 0; } +/* See if we can do a queue run. If policy limit permit, kick one off. +If both notification and timer events are present, handle the former +and leave the timer outstanding. + +Return the number of seconds until the next due runner. +*/ + static int daemon_qrun(int local_queue_run_max, struct pollfd * fd_polls, int listen_socket_count) { @@ -1464,13 +1470,16 @@ DEBUG(D_any) debug_printf("%s received\n", enough queue runners on the go. If we are not running as root, a re-exec is required. In the calling process, restart the alamr timer for the next run. */ -if (is_multiple_qrun()) +if (is_multiple_qrun()) /* we are managing periodic runs */ if (local_queue_run_max <= 0 || queue_run_count < local_queue_run_max) { qrunner * q = NULL; #ifndef DISABLE_QUEUE_RAMP - if (*queuerun_msgid) /* See if we can start another runner for this queue */ + /* If this is a triggered run for a specific message, see if we can start + another runner for this queue. */ + + if (*queuerun_msgid) { for (qrunner * qq = qrunners; qq; qq = qq->next) if (qq->name == queuerun_msg_qname) @@ -1481,13 +1490,13 @@ if (is_multiple_qrun()) } else #endif - /* In order of run priority, find the first queue for which we can start - a runner */ + /* Normal periodic runL in order of run priority, find the first queue + for which we can start a runner */ for (q = qrunners; q; q = q->next) if (q->run_count < q->run_max) break; - if (q) + if (q) /* found a queue to run */ { pid_t pid; @@ -1619,19 +1628,23 @@ if (is_multiple_qrun()) } } -sigalrm_seen = FALSE; +/* The queue run has been initiated (unless we were already running enough) */ + #ifndef DISABLE_QUEUE_RAMP -if (*queuerun_msgid) /* it was a fast-ramp kick */ +if (*queuerun_msgid) /* it was a fast-ramp kick; dealt with */ *queuerun_msgid = 0; else /* periodic or one-time queue run */ #endif - { /* Impose a minimum 1s tick, even when a run was outstanding */ + /* Set up next timer callback. Impose a minimum 1s tick, + even when a run was outstanding */ + { int interval = next_qrunner_interval(); if (interval <= 0) interval = 1; + sigalrm_seen = FALSE; if (qrunners) /* there are still periodic qrunners */ { - ALARM(interval); + ALARM(interval); /* set up next qrun tick */ return interval; } } @@ -2612,7 +2625,7 @@ for (;;) The other option is that we have an inetd wait timeout specified to -bw. */ - if (sigalrm_seen) + if (sigalrm_seen || *queuerun_msgid) if (inetd_wait_timeout > 0) daemon_inetd_wtimeout(last_connection_time); /* Might not return */ else @@ -2641,7 +2654,9 @@ for (;;) select() was interrupted so that we reap the child. This might still leave a small window when a SIGCHLD could get lost. However, since we use SIGCHLD only to do the reaping more quickly, it shouldn't result in anything other - than a delay until something else causes a wake-up. */ + than a delay until something else causes a wake-up. + For the normal case, wait for either a pollable fd (eg. new connection) or + or a SIGALRM (for a periodic queue run) */ if (sigchld_seen) { @@ -2706,10 +2721,13 @@ for (;;) break; /* to top of daemon loop */ } #endif + /* Handle the daemon-notifier socket. If it was a fast-ramp + notification then queuerun_msgid will have a nonzerolength string. */ + if (dnotify_poll && dnotify_poll->revents & POLLIN) { dnotify_poll->revents = 0; - sigalrm_seen = daemon_notification(); + daemon_notification(); break; /* to top of daemon loop */ } for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count; diff --git a/src/src/structs.h b/src/src/structs.h index 209d657c6..256560ef8 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -964,7 +964,7 @@ typedef struct qrunner { struct qrunner * next; /* list sorted by next tick */ uschar * name; /* NULL for the default queue */ - unsigned interval; /* tick rate, seconds */ + unsigned interval; /* tick rate, seconds. Zero for a one-time run */ time_t next_tick; /* next run should, or should have, start(ed) */ unsigned run_max; /* concurrent queue runner limit */ unsigned run_count; /* current runners */ commit 5ce637f7a74d392ddafb1d38e3cefb744996b287 Author: Jeremy Harris Date: Sat Dec 16 16:31:06 2023 +0000 tidying diff --git a/src/src/EDITME b/src/src/EDITME index f68b3f104..85d24f73f 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -52,6 +52,7 @@ # they are correctly installed, via their compatibility interfaces. However, # Exim can also be configured to use the native calls for Berkeley DB (obsolete # versions 1.85, 2.x, 3.x, or the current 4.x version) and also for gdbm. +# See definitions for DBMLIB below. # For some operating systems, a default DBM library (other than ndbm) is # selected by a setting in the OS-specific Makefile. Most modern OS now have diff --git a/src/src/receive.c b/src/src/receive.c index c4b80c236..e35400aec 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -4391,7 +4391,7 @@ data file will be flushed(!) out thereby. Nevertheless, it is theoretically possible for fclose() to fail - and this has been seen on obscure filesystems (probably one that delayed the actual media write as long as possible) but what to do? What has happened to the lock if this happens? -It's a mes because we already logged the acceptance. +It's a mess because we already logged the acceptance. We can at least log the issue, try to remove spoolfiles and respond with a temp-reject. We do not want to close before logging acceptance because we want to hold the lock until we know that logging worked. diff --git a/src/src/store.c b/src/src/store.c index 684f83cf0..03322a097 100644 --- a/src/src/store.c +++ b/src/src/store.c @@ -1145,11 +1145,11 @@ Returns: pointer to gotten store (panic on failure) */ static void * -internal_store_malloc(size_t size, const char *func, int line) +internal_store_malloc(size_t size, const char * func, int line) { void * yield; -/* Check specifically for a possibly result of conversion from +/* Check specifically for a possible result of conversion from a negative int, to the (unsigned, wider) size_t */ if (size >= INT_MAX/2) commit 322ae953e144d9e1fdc06d993d2e4551f5fb1322 Author: Jeremy Harris Date: Thu Dec 21 23:33:10 2023 +0000 tweak observability diff --git a/src/src/functions.h b/src/src/functions.h index b201467b2..ef84e3d7c 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1400,6 +1400,11 @@ HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP%c> %s\n", client_cmd_log = string_catn(client_cmd_log, US"|", 1); (void) string_from_gstring(client_cmd_log); } + else if (mode == SCMD_MORE) + { + client_cmd_log = string_catn(client_cmd_log, US"+", 1); + (void) string_from_gstring(client_cmd_log); + } store_pool = old_pool; } # endif diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 90a0eb23e..62557072e 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -649,7 +649,7 @@ Arguments: sx SMTP connection, contains buffer for pipelining, and socket mode buffer, write-with-more-likely, write format a format, starting with one of - of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT. + of HELO, MAIL FROM, RCPT TO, DATA, BDAT, ".", or QUIT. If NULL, flush pipeline buffer only. ... data for the format diff --git a/src/src/transport.c b/src/src/transport.c index a0f097579..79a69f941 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -1658,6 +1658,10 @@ another message waiting for the same host. However, it doesn't do this if the current continue sequence is greater than the maximum supplied as an argument, or greater than the global connection_max_messages, which, if set, overrides. +It is also called if conditions are otherwise right for pipelining a QUIT after +the message data, since if there is another message waiting we do not want to +send that QUIT. + Arguments: transport_name name of the transport hostname name of the host commit cf1376206284f2a4f11e32d931d4aade34c206c5 Author: Jeremy Harris Date: Fri Dec 22 23:57:05 2023 +0000 Reject "dot, LF" as ending data phase. Bug 3063 diff --git a/src/src/receive.c b/src/src/receive.c index e35400aec..c6f612832 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1960,8 +1960,10 @@ for (;;) if (ch == '\n') { - if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = FALSE; - else if (first_line_ended_crlf) receive_ungetc(' '); + if (first_line_ended_crlf == TRUE_UNSET) + first_line_ended_crlf = FALSE; + else if (first_line_ended_crlf) + receive_ungetc(' '); goto EOL; } @@ -1970,6 +1972,7 @@ for (;;) This implements the dot-doubling rule, though header lines starting with dots aren't exactly common. They are legal in RFC 822, though. If the following is CRLF or LF, this is the line that that terminates the + entire message. We set message_ended to indicate this has happened (to prevent further reading), and break out of the loop, having freed the empty header, and set next = NULL to indicate no data line. */ @@ -1977,7 +1980,11 @@ for (;;) if (f.dot_ends && ptr == 0 && ch == '.') { ch = (receive_getc)(GETC_BUFFER_UNLIMITED); - if (ch == '\r') + if (ch == '\n' && first_line_ended_crlf == TRUE /* and not TRUE_UNSET */ ) + /* dot, LF but we are in CRLF mode. Attack? */ + ch = ' '; /* replace the LF with a space */ + + else if (ch == '\r') { ch = (receive_getc)(GETC_BUFFER_UNLIMITED); if (ch != '\n') @@ -2013,7 +2020,8 @@ for (;;) ch = (receive_getc)(GETC_BUFFER_UNLIMITED); if (ch == '\n') { - if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = TRUE; + if (first_line_ended_crlf == TRUE_UNSET) + first_line_ended_crlf = TRUE; goto EOL; } diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index e19c86ff8..aeaffeb37 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -5105,15 +5105,18 @@ while (done <= 0) } if (chunking_state > CHUNKING_OFFERED) - rc = OK; /* No predata ACL or go-ahead output for BDAT */ + rc = OK; /* There is no predata ACL or go-ahead output for BDAT */ else { - /* If there is an ACL, re-check the synchronization afterwards, since the - ACL may have delayed. To handle cutthrough delivery enforce a dummy call - to get the DATA command sent. */ + /* If there is a predata-ACL, re-check the synchronization afterwards, + since the ACL may have delayed. To handle cutthrough delivery enforce a + dummy call to get the DATA command sent. */ if (!acl_smtp_predata && cutthrough.cctx.sock < 0) + { + if (!check_sync()) goto SYNC_FAILURE; rc = OK; + } else { uschar * acl = acl_smtp_predata ? acl_smtp_predata : US"accept"; commit 4596719398f6f2365bed563aafd757a6433ce7b4 Author: Jeremy Harris Date: Sat Dec 23 15:59:53 2023 +0000 Use enum for body data input state-machine diff --git a/src/src/receive.c b/src/src/receive.c index c6f612832..e8bd80596 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -836,93 +836,95 @@ Returns: One of the END_xxx values indicating why it stopped reading */ static int -read_message_data_smtp(FILE *fout) +read_message_data_smtp(FILE * fout) { -int ch_state = 0; -int ch; -int linelength = 0; +enum { s_linestart, s_normal, s_had_cr, s_had_nl_dot, s_had_dot_cr } ch_state = + s_linestart; +int linelength = 0, ch; while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF) { if (ch == 0) body_zerocount++; switch (ch_state) { - case 0: /* After LF or CRLF */ - if (ch == '.') - { - ch_state = 3; - continue; /* Don't ever write . after LF */ - } - ch_state = 1; + case s_linestart: /* After LF or CRLF */ + if (ch == '.') + { + ch_state = s_had_nl_dot; + continue; /* Don't ever write . after LF */ + } + ch_state = s_normal; - /* Else fall through to handle as normal uschar. */ + /* Else fall through to handle as normal uschar. */ - case 1: /* Normal state */ - if (ch == '\n') - { - ch_state = 0; - body_linecount++; + case s_normal: /* Normal state */ + if (ch == '\r') + { + ch_state = s_had_cr; + continue; /* Don't write the CR */ + } + if (ch == '\n') /* Bare NL ends line */ + { + ch_state = s_linestart; + body_linecount++; + if (linelength > max_received_linelength) + max_received_linelength = linelength; + linelength = -1; + } + break; + + case s_had_cr: /* After (unwritten) CR */ + body_linecount++; /* Any char ends line */ if (linelength > max_received_linelength) - max_received_linelength = linelength; + max_received_linelength = linelength; linelength = -1; - } - else if (ch == '\r') - { - ch_state = 2; - continue; - } - break; + if (ch == '\n') /* proper CRLF */ + ch_state = s_linestart; + else + { + message_size++; /* convert the dropped CR to a stored NL */ + if (fout && fputc('\n', fout) == EOF) return END_WERROR; + cutthrough_data_put_nl(); + if (ch == '\r') /* CR; do not write */ + continue; + ch_state = s_normal; /* not LF or CR; process as standard */ + } + break; - case 2: /* After (unwritten) CR */ - body_linecount++; - if (linelength > max_received_linelength) - max_received_linelength = linelength; - linelength = -1; - if (ch == '\n') - { - ch_state = 0; - } - else - { - message_size++; - if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR; - cutthrough_data_put_nl(); - if (ch != '\r') ch_state = 1; else continue; - } - break; + case s_had_nl_dot: /* After [CR] LF . */ + if (ch == '\n') /* [CR] LF . LF */ + return END_DOT; + if (ch == '\r') /* [CR] LF . CR */ + { + ch_state = s_had_dot_cr; + continue; /* Don't write the CR */ + } + /* The dot was removed on reaching s_had_nl_dot. For a doubled dot, here, + reinstate it to cutthrough. The current ch, dot or not, is passed both to + cutthrough and to file below. */ + if (ch == '.') + { + uschar c = ch; + cutthrough_data_puts(&c, 1); + } + ch_state = s_normal; + break; - case 3: /* After [CR] LF . */ - if (ch == '\n') - return END_DOT; - if (ch == '\r') - { - ch_state = 4; - continue; - } - /* The dot was removed at state 3. For a doubled dot, here, reinstate - it to cutthrough. The current ch, dot or not, is passed both to cutthrough - and to file below. */ - if (ch == '.') - { - uschar c= ch; - cutthrough_data_puts(&c, 1); - } - ch_state = 1; - break; + case s_had_dot_cr: /* After [CR] LF . CR */ + if (ch == '\n') + return END_DOT; /* Preferred termination */ - case 4: /* After [CR] LF . CR */ - if (ch == '\n') return END_DOT; - message_size++; - body_linecount++; - if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR; - cutthrough_data_put_nl(); - if (ch == '\r') - { - ch_state = 2; - continue; - } - ch_state = 1; - break; + message_size++; /* convert the dropped CR to a stored NL */ + body_linecount++; + if (fout && fputc('\n', fout) == EOF) return END_WERROR; + cutthrough_data_put_nl(); + if (ch == '\r') + { + ch_state = s_had_cr; + continue; /* CR; do not write */ + } + ch_state = s_normal; + break; } /* Add the character to the spool file, unless skipping; then loop for the @@ -1979,6 +1981,7 @@ for (;;) if (f.dot_ends && ptr == 0 && ch == '.') { + /* leading dot while in headers-read mode */ ch = (receive_getc)(GETC_BUFFER_UNLIMITED); if (ch == '\n' && first_line_ended_crlf == TRUE /* and not TRUE_UNSET */ ) /* dot, LF but we are in CRLF mode. Attack? */ @@ -3169,7 +3172,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.delivery) /* Open a new spool file for the data portion of the message. We need -to access it both via a file descriptor and a stream. Try to make the +to access it both via a file descriptor and a stdio stream. Try to make the directory if it isn't there. */ spool_name = spool_fname(US"input", message_subdir, message_id, US"-D"); commit 5bb786d5ad568a88d50d15452aacc8404047e5ca Author: Jeremy Harris Date: Sat Dec 23 17:42:57 2023 +0000 Reject "dot, LF" as ending data phase (pt. 2). Bug 3063 diff --git a/src/src/receive.c b/src/src/receive.c index e8bd80596..ae7045068 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -829,14 +829,20 @@ July 2003: Bare CRs cause trouble. We now treat them as line terminators as well, so that there are no CRs in spooled messages. However, the message terminating dot is not recognized between two bare CRs. +Dec 2023: getting a site to send a body including an "LF . LF" sequence +followed by SMTP commands is a possible "smtp smuggling" attack. If +the first (header) line for the message has a proper CRLF then enforce +that for the body: convert bare LF to a space. + Arguments: - fout a FILE to which to write the message; NULL if skipping + fout a FILE to which to write the message; NULL if skipping + strict_crlf require full CRLF sequence as a line ending Returns: One of the END_xxx values indicating why it stopped reading */ static int -read_message_data_smtp(FILE * fout) +read_message_data_smtp(FILE * fout, BOOL strict_crlf) { enum { s_linestart, s_normal, s_had_cr, s_had_nl_dot, s_had_dot_cr } ch_state = s_linestart; @@ -863,14 +869,17 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF) ch_state = s_had_cr; continue; /* Don't write the CR */ } - if (ch == '\n') /* Bare NL ends line */ - { - ch_state = s_linestart; - body_linecount++; - if (linelength > max_received_linelength) - max_received_linelength = linelength; - linelength = -1; - } + if (ch == '\n') /* Bare LF at end of line */ + if (strict_crlf) + ch = ' '; /* replace LF with space */ + else + { /* treat as line ending */ + ch_state = s_linestart; + body_linecount++; + if (linelength > max_received_linelength) + max_received_linelength = linelength; + linelength = -1; + } break; case s_had_cr: /* After (unwritten) CR */ @@ -893,8 +902,11 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF) case s_had_nl_dot: /* After [CR] LF . */ if (ch == '\n') /* [CR] LF . LF */ - return END_DOT; - if (ch == '\r') /* [CR] LF . CR */ + if (strict_crlf) + ch = ' '; /* replace LF with space */ + else + return END_DOT; + else if (ch == '\r') /* [CR] LF . CR */ { ch_state = s_had_dot_cr; continue; /* Don't write the CR */ @@ -902,7 +914,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF) /* The dot was removed on reaching s_had_nl_dot. For a doubled dot, here, reinstate it to cutthrough. The current ch, dot or not, is passed both to cutthrough and to file below. */ - if (ch == '.') + else if (ch == '.') { uschar c = ch; cutthrough_data_puts(&c, 1); @@ -1140,7 +1152,7 @@ receive_swallow_smtp(void) { if (message_ended >= END_NOTENDED) message_ended = chunking_state <= CHUNKING_OFFERED - ? read_message_data_smtp(NULL) + ? read_message_data_smtp(NULL, FALSE) : read_message_bdat_smtp_wire(NULL); } @@ -3241,7 +3253,7 @@ if (!ferror(spool_data_file) && !(receive_feof)() && message_ended != END_DOT) if (smtp_input) { message_ended = chunking_state <= CHUNKING_OFFERED - ? read_message_data_smtp(spool_data_file) + ? read_message_data_smtp(spool_data_file, first_line_ended_crlf) : spool_wireformat ? read_message_bdat_smtp_wire(spool_data_file) : read_message_bdat_smtp(spool_data_file); commit f78e417c3c2e7348ce58bb03efc7343bb6d32383 Author: Jeremy Harris Date: Mon Dec 25 16:50:23 2023 +0000 Testsuite: testcase for "smtp smuggling". Bug 3063 Also remove the unneeded sync point added in cf1376206284 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index aeaffeb37..541288301 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -5113,10 +5113,7 @@ while (done <= 0) dummy call to get the DATA command sent. */ if (!acl_smtp_predata && cutthrough.cctx.sock < 0) - { - if (!check_sync()) goto SYNC_FAILURE; rc = OK; - } else { uschar * acl = acl_smtp_predata ? acl_smtp_predata : US"accept"; commit 80bacd22c5aaacd7fca966af7384ac6f2679cb21 Author: Jeremy Harris Date: Fri Dec 29 12:40:22 2023 +0000 DKIM: logging for signing in transport. Bug 3062 diff --git a/src/src/deliver.c b/src/src/deliver.c index e96733f73..2cef3d731 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -1245,6 +1245,14 @@ else g = string_catn(g, US" K", 2); } +#ifndef DISABLE_DKIM + if (addr->dkim_used && LOGGING(dkim_verbose)) + { + g = string_catn(g, US" DKIM=", 6); + g = string_cat(g, addr->dkim_used); + } +#endif + /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */ if ( LOGGING(smtp_confirmation) @@ -3571,7 +3579,14 @@ while (!done) switch (*subid) { - case 3: /* explicit notification of continued-connection (non)use; +#ifndef DISABLE_DKIM + case '4': /* DKIM information */ + addr->dkim_used = string_copy(ptr); + while(*ptr++); + break; +#endif + + case '3': /* explicit notification of continued-connection (non)use; overrides caller's knowlege. */ if (*ptr & BIT(1)) setflag(addr, af_new_conn); else if (*ptr & BIT(2)) setflag(addr, af_cont_conn); @@ -4886,6 +4901,15 @@ all pipes, so I do not see a reason to use non-blocking IO here rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer); } +#ifndef DISABLE_DKIM + if (addr->dkim_used && LOGGING(dkim_verbose)) + { + DEBUG(D_deliver) debug_printf("dkim used: %s\n", addr->dkim_used); + ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->dkim_used) + 1; + rmt_dlv_checked_write(fd, 'A', '4', big_buffer, ptr - big_buffer); + } +#endif + if (testflag(addr, af_new_conn) || testflag(addr, af_cont_conn)) { DEBUG(D_deliver) debug_printf("%scontinued-connection\n", diff --git a/src/src/dkim.c b/src/src/dkim.c index ea82f34ea..59025608f 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -741,6 +741,9 @@ if (dkim_domain) if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig)) goto bad; + dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_domain); + dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_selector); + if (!dkim_sign_ctx.sig) /* link sig to context chain */ dkim_sign_ctx.sig = sig; else diff --git a/src/src/dkim_transport.c b/src/src/dkim_transport.c index fae2f4891..38f849af6 100644 --- a/src/src/dkim_transport.c +++ b/src/src/dkim_transport.c @@ -384,6 +384,8 @@ BOOL dkim_transport_write_message(transport_ctx * tctx, struct ob_dkim * dkim, const uschar ** err) { +BOOL yield; + /* If we can't sign, just call the original function. */ if ( !(dkim->dkim_private_key && dkim->dkim_domain && dkim->dkim_selector) @@ -398,12 +400,16 @@ if ( !transport_filter_argv || !*transport_filter_argv || !**transport_filter_argv ) - return dkt_direct(tctx, dkim, err); + yield = dkt_direct(tctx, dkim, err); + +else + /* Use the transport path to write a file, calculate a dkim signature, + send the signature and then send the file. */ -/* Use the transport path to write a file, calculate a dkim signature, -send the signature and then send the file. */ + yield = dkt_via_kfile(tctx, dkim, err); -return dkt_via_kfile(tctx, dkim, err); +tctx->addr->dkim_used = string_from_gstring(dkim_signing_record); +return yield; } #endif /* whole file */ diff --git a/src/src/globals.c b/src/src/globals.c index bb5bd6b1a..c535ea121 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -864,6 +864,7 @@ void *dkim_signatures = NULL; uschar *dkim_signers = NULL; uschar *dkim_signing_domain = NULL; uschar *dkim_signing_selector = NULL; +gstring *dkim_signing_record = NULL; uschar *dkim_verify_hashes = US"sha256:sha512"; uschar *dkim_verify_keytypes = US"ed25519:rsa"; uschar *dkim_verify_min_keysizes = US"rsa=1024 ed25519=250"; diff --git a/src/src/globals.h b/src/src/globals.h index fe4a1610a..ffc7150f2 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -541,6 +541,7 @@ extern uschar *dkim_cur_signer; /* Expansion variable, holds the current extern int dkim_key_length; /* Expansion variable, length of signing key in bits */ extern void *dkim_signatures; /* Actually a (pdkim_signature *) but most files do not need to know */ extern uschar *dkim_signers; /* Expansion variable, holds colon-separated list of domains and identities that have signed a message */ +extern gstring *dkim_signing_record; /* domains+selectors used */ extern uschar *dkim_signing_domain; /* Expansion variable, domain used for signing a message. */ extern uschar *dkim_signing_selector; /* Expansion variable, selector used for signing a message. */ extern uschar *dkim_verify_hashes; /* Preference order for signatures */ diff --git a/src/src/structs.h b/src/src/structs.h index 256560ef8..b16a8a3f2 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -586,6 +586,9 @@ typedef struct address_item { uschar *self_hostname; /* after self=pass */ uschar *shadow_message; /* info about shadow transporting */ + uid_t uid; /* uid for transporting */ + gid_t gid; /* gid for transporting */ + #ifndef DISABLE_TLS const uschar *tlsver; /* version used for transport */ uschar *cipher; /* Cipher used for transport */ @@ -608,9 +611,9 @@ typedef struct address_item { int dsn_flags; /* DSN flags */ int dsn_aware; /* DSN aware flag */ - uid_t uid; /* uid for transporting */ - gid_t gid; /* gid for transporting */ - +#ifndef DISABLE_DKIM + const uschar * dkim_used; /* DKIM info, or NULL */ +#endif /* flags */ struct { BOOL af_allow_file:1; /* allow file in generated address */ commit 582f61444fa806694c2caae7c156830dbf8531d7 Author: Jeremy Harris Date: Fri Dec 29 15:29:27 2023 +0000 Tidying: defines for sync_responses() retcodes diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 4cf58436d..194671272 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -235,6 +235,17 @@ static BOOL pipelining_active; /* current transaction is in pipe mode */ static unsigned ehlo_response(uschar * buf, unsigned checks); +/* sync_responses() return codes */ + +#define RESP_BIT_HAD_5XX BIT(1) +#define RESP_BIT_HAD_2XX BIT(0) +#define RESP_HAD_2_AND_5 (RESP_BIT_HAD_2XX | RESP_BIT_HAD_5XX) +#define RESP_NOERROR 0 +#define RESP_RCPT_TIMEO -1 +#define RESP_RCPT_ERROR -2 +#define RESP_MAIL_OR_DATA_ERROR -3 +#define RESP_EPIPE_EHLO_ERR -4 +#define RESP_EHLO_ERR_TLS -5 /******************************************************************************/ @@ -1225,7 +1236,7 @@ int yield = 0; #ifndef DISABLE_PIPE_CONNECT int rc; if ((rc = smtp_reap_early_pipe(sx, &count)) != OK) - return rc == FAIL ? -4 : -5; + return rc == FAIL ? RESP_EPIPE_EHLO_ERR : RESP_EHLO_ERR_TLS; #endif /* Handle the response for a MAIL command. On error, reinstate the original @@ -1243,7 +1254,7 @@ 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; + return RESP_EHLO_ERR_TLS; if (errno == 0 && sx->buffer[0] != 0) { int save_errno = 0; @@ -1263,7 +1274,7 @@ if (sx->pending_MAIL) addr->host_used = sx->conn_args.host; addr = addr->next; } - return -3; + return RESP_MAIL_OR_DATA_ERROR; } } @@ -1277,7 +1288,7 @@ while (count-- > 0) { while (addr->transport_return != PENDING_DEFER) if (!(addr = addr->next)) - return -2; + return RESP_RCPT_ERROR; /* The address was accepted */ addr->host_used = sx->conn_args.host; @@ -1286,7 +1297,7 @@ while (count-- > 0) if (smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', ob->command_timeout)) { - yield |= 1; + yield |= RESP_BIT_HAD_2XX; addr->transport_return = PENDING_OK; /* If af_dr_retry_exists is set, there was a routing delay on this address; @@ -1305,7 +1316,7 @@ while (count-- > 0) /* Error on first TLS read */ else if (errno == ERRNO_TLSFAILURE) - return -5; + return RESP_EHLO_ERR_TLS; /* Timeout while reading the response */ @@ -1316,7 +1327,7 @@ while (count-- > 0) set_errno_nohost(sx->first_addr, ETIMEDOUT, message, DEFER, FALSE, &sx->delivery_start); retry_add_item(addr, addr->address_retry_key, 0); update_waiting = FALSE; - return -1; + return RESP_RCPT_TIMEO; } /* Handle other errors in obtaining an SMTP response by returning -1. This @@ -1334,7 +1345,7 @@ while (count-- > 0) g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "RCPT TO:<%s>", transport_rcpt_address(addr, sx->conn_args.tblock->rcpt_include_affixes)); string_from_gstring(g); - return -2; + return RESP_RCPT_ERROR; } /* Handle SMTP permanent and temporary response codes. */ @@ -1354,7 +1365,7 @@ while (count-- > 0) if (sx->buffer[0] == '5') { addr->transport_return = FAIL; - yield |= 2; + yield |= RESP_BIT_HAD_5XX; } /* The response was 4xx */ @@ -1374,7 +1385,7 @@ while (count-- > 0) /* If a 452 and we've had at least one 2xx or 5xx, set next_addr to the start point for another MAIL command. */ - if (addr->more_errno >> 8 == 52 && yield & 3) + if (addr->more_errno >> 8 == 52 && yield > 0) { if (!sx->RCPT_452) /* initialised at MAIL-ack above */ { @@ -1424,7 +1435,7 @@ while (count-- > 0) } } if (count && !(addr = addr->next)) - return -2; + return RESP_RCPT_ERROR; } /* Loop for next RCPT response */ /* Update where to start at for the next block of responses, unless we @@ -1446,16 +1457,16 @@ if (pending_DATA != 0) BOOL pass_message; if (errno == ERRNO_TLSFAILURE) /* Error on first TLS read */ - return -5; + return RESP_EHLO_ERR_TLS; - if (pending_DATA > 0 || (yield & 1) != 0) + if (pending_DATA > 0 || yield & RESP_BIT_HAD_2XX) { if (errno == 0 && sx->buffer[0] == '4') { errno = ERRNO_DATA4XX; sx->first_addr->more_errno |= ((sx->buffer[1] - '0')*10 + sx->buffer[2] - '0') << 8; } - return -3; + return RESP_MAIL_OR_DATA_ERROR; } (void)check_response(sx->conn_args.host, &errno, 0, sx->buffer, &code, &msg, &pass_message); DEBUG(D_transport) debug_printf("%s\nerror for DATA ignored: pipelining " @@ -2008,18 +2019,18 @@ if (flags & tc_reap_prev && prev_cmd_count > 0) switch(sync_responses(sx, prev_cmd_count, 0)) { - case 1: /* 2xx (only) => OK */ - case 3: sx->good_RCPT = TRUE; /* 2xx & 5xx => OK & progress made */ - case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */ - case 0: break; /* No 2xx or 5xx, but no probs */ + case RESP_BIT_HAD_2XX: /* OK */ + case RESP_HAD_2_AND_5: sx->good_RCPT = TRUE; /* OK & progress made */ + case RESP_BIT_HAD_5XX: sx->completed_addr = TRUE; /* progress made */ + case RESP_NOERROR: break; /* No 2xx or 5xx, but no probs */ - case -5: errno = ERRNO_TLSFAILURE; - return DEFER; + case RESP_EHLO_ERR_TLS:errno = ERRNO_TLSFAILURE; + return DEFER; #ifndef DISABLE_PIPE_CONNECT - case -4: /* non-2xx for pipelined banner or EHLO */ + case RESP_EPIPE_EHLO_ERR: /* non-2xx for pipelined banner or EHLO */ #endif - case -1: /* Timeout on RCPT */ - default: return ERROR; /* I/O error, or any MAIL/DATA error */ + case RESP_RCPT_TIMEO: /* Timeout on RCPT */ + default: return ERROR;/* I/O error, or any MAIL/DATA error */ } cmd_count = 1; if (!sx->pending_BDAT) @@ -2523,7 +2534,7 @@ goto SEND_QUIT; DEBUG(D_transport) debug_printf("may need to auth, so pipeline no further\n"); if (smtp_write_command(sx, SCMD_FLUSH, NULL) < 0) goto SEND_FAILED; - if (sync_responses(sx, 2, 0) != 0) + if (sync_responses(sx, 2, 0) != RESP_NOERROR) { HDEBUG(D_transport) debug_printf("failed reaping pipelined cmd responses\n"); @@ -2714,7 +2725,7 @@ if ( smtp_peer_options & OPTION_TLS if (sx->early_pipe_active) { - if (sync_responses(sx, 2, 0) != 0) + if (sync_responses(sx, 2, 0) != RESP_NOERROR) { HDEBUG(D_transport) debug_printf("failed reaping pipelined cmd responses\n"); @@ -3568,14 +3579,14 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; { switch(sync_responses(sx, cmds_sent, 0)) { - case 3: sx->ok = TRUE; /* 2xx & 5xx => OK & progress made */ - case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */ + case RESP_HAD_2_AND_5: sx->ok = TRUE; /* OK & progress made */ + case RESP_BIT_HAD_5XX: sx->completed_addr = TRUE; /* progress made */ break; - case 1: sx->ok = TRUE; /* 2xx (only) => OK, but if LMTP, */ + case RESP_BIT_HAD_2XX: sx->ok = TRUE; /* OK, but if LMTP, */ if (!sx->lmtp) /* can't tell about progress yet */ sx->completed_addr = TRUE; - case 0: /* No 2xx or 5xx, but no probs */ + case RESP_NOERROR: /* No 2xx or 5xx, but no probs */ /* If any RCPT got a 452 response then next_addr has been updated for restarting with a new MAIL on the same connection. Send no more RCPTs for this MAIL. */ @@ -3589,13 +3600,13 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; } break; - case -1: return -3; /* Timeout on RCPT */ - case -2: return -2; /* non-MAIL read i/o error */ - default: return -1; /* any MAIL error */ + case RESP_RCPT_TIMEO: return -3; /* Timeout on RCPT */ + case RESP_RCPT_ERROR: return -2; /* non-MAIL read i/o error */ + default: return -1; /* any MAIL error */ #ifndef DISABLE_PIPE_CONNECT - case -4: return -1; /* non-2xx for pipelined banner or EHLO */ - case -5: return -1; /* TLS first-read error */ + case RESP_EPIPE_EHLO_ERR: return -1; /* non-2xx for pipelined banner or EHLO */ + case RESP_EHLO_ERR_TLS: return -1; /* TLS first-read error */ #endif } } @@ -3956,17 +3967,19 @@ if ( !(smtp_peer_options & OPTION_CHUNKING) int count = smtp_write_command(sx, SCMD_FLUSH, "DATA\r\n"); if (count < 0) goto SEND_FAILED; + switch(sync_responses(sx, count, sx->ok ? +1 : -1)) { - case 3: sx->ok = TRUE; /* 2xx & 5xx => OK & progress made */ - case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */ - break; + case RESP_HAD_2_AND_5: sx->ok = TRUE; /* OK & progress made */ + case RESP_BIT_HAD_5XX: sx->completed_addr = TRUE; /* progress made */ + break; - 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 RESP_BIT_HAD_2XX: sx->ok = TRUE; /* OK, but if LMTP, */ + if (!sx->lmtp) /* can't tell about progress yet */ + sx->completed_addr = TRUE; + case RESP_NOERROR: break; /* No 2xx or 5xx, but no probs */ - case -1: goto END_OFF; /* Timeout on RCPT */ + case RESP_RCPT_TIMEO: goto END_OFF; #ifndef DISABLE_PIPE_CONNECT case -5: /* TLS first-read error */ @@ -4196,22 +4209,23 @@ else /* Reap any outstanding MAIL & RCPT commands, but not a DATA-go-ahead */ switch(sync_responses(sx, sx->cmd_count-1, 0)) { - case 3: sx->ok = TRUE; /* 2xx & 5xx => OK & progress made */ - case 2: sx->completed_addr = TRUE; /* 5xx (only) => progress made */ - break; + case RESP_HAD_2_AND_5: sx->ok = TRUE; /* OK & progress made */ + case RESP_BIT_HAD_5XX: sx->completed_addr = TRUE; /* progress made */ + break; - 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 RESP_BIT_HAD_2XX: sx->ok = TRUE; /* OK, but if LMTP, */ + if (!sx->lmtp) /* can't tell about progress yet */ + sx->completed_addr = TRUE; + case RESP_NOERROR: break; /* No 2xx or 5xx, but no probs */ - case -1: goto END_OFF; /* Timeout on RCPT */ + case RESP_RCPT_TIMEO: goto END_OFF; /* Timeout on RCPT */ #ifndef DISABLE_PIPE_CONNECT - case -5: /* TLS first-read error */ - case -4: HDEBUG(D_transport) + case RESP_EHLO_ERR_TLS: /* TLS first-read error */ + case RESP_EPIPE_EHLO_ERR: 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 f0ce0ecaa054ad9773a2078bc8f011a59518120a Author: Jeremy Harris Date: Fri Dec 29 22:12:58 2023 +0000 Tidying: enum for smtp_write_mail_and_rcpt_cmds() retcodes diff --git a/src/src/macros.h b/src/src/macros.h index e2c1d0f94..5279f70d0 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1175,4 +1175,14 @@ typedef unsigned mcs_flags; #define SR_FINAL TRUE #define SR_NOT_FINAL FALSE +/* Return codes for smtp_write_mail_and_rcpt_cmds() */ +typedef enum { + sw_mrc_ok, /* good, rcpt results in addr->transport_return (PENDING_OK, DEFER, FAIL) */ + sw_mrc_bad_mail, /* MAIL response error */ + sw_mrc_bad_read, /* any non-MAIL read i/o error */ + sw_mrc_nonmail_read_timeo, /* non-MAIL response timeout */ + sw_mrc_bad_internal, /* internal error; channel still usable */ + sw_mrc_tx_fail, /* transmit failed */ +} sw_mrc_t; + /* End of macros.h */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 194671272..817d729a7 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -3415,17 +3415,11 @@ if (sx->peer_offered & OPTION_DSN && !(addr->dsn_flags & rf_dsnlasthop)) -/* -Return: - 0 good, rcpt results in addr->transport_return (PENDING_OK, DEFER, FAIL) - -1 MAIL response error - -2 any non-MAIL read i/o error - -3 non-MAIL response timeout - -4 internal error; channel still usable - -5 transmit failed +/* Send MAIL FROM and RCPT TO commands. +See sw_mrc_t definition for return codes. */ -int +sw_mrc_t smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield) { address_item * addr; @@ -3438,7 +3432,7 @@ int rc; if (build_mailcmd_options(sx, sx->first_addr) != OK) { *yield = ERROR; - return -4; + return sw_mrc_bad_internal; } /* From here until we send the DATA command, we can make use of PIPELINING @@ -3466,7 +3460,7 @@ sx->pending_MAIL = TRUE; /* The block starts with MAIL */ { set_errno_nohost(sx->addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE, &sx->delivery_start); *yield = ERROR; - return -4; + return sw_mrc_bad_internal; } setflag(sx->addrlist, af_utf8_downcvt); } @@ -3481,7 +3475,7 @@ mail_command = string_copy(big_buffer); /* Save for later error message */ switch(rc) { case -1: /* Transmission error */ - return -5; + return sw_mrc_bad_mail; case +1: /* Cmd was sent */ if (!smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', @@ -3492,7 +3486,7 @@ switch(rc) errno = ERRNO_MAIL4XX; sx->addrlist->more_errno |= ((sx->buffer[1] - '0')*10 + sx->buffer[2] - '0') << 8; } - return -1; + return sw_mrc_bad_mail; } sx->pending_MAIL = FALSE; break; @@ -3567,14 +3561,14 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; { /*XXX could we use a per-address errstr here? Not fail the whole send? */ errno = ERRNO_EXPANDFAIL; - return -5; /*XXX too harsh? */ + return sw_mrc_tx_fail; /*XXX too harsh? */ } #endif cmds_sent = smtp_write_command(sx, no_flush ? SCMD_BUFFER : SCMD_FLUSH, "RCPT TO:<%s>%s%s\r\n", rcpt_addr, sx->igquotstr, sx->buffer); - if (cmds_sent < 0) return -5; + if (cmds_sent < 0) return sw_mrc_tx_fail; if (cmds_sent > 0) { switch(sync_responses(sx, cmds_sent, 0)) @@ -3596,17 +3590,17 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; DEBUG(D_transport) debug_printf("seen 452 too-many-rcpts\n"); sx->RCPT_452 = FALSE; /* sx->next_addr has been reset for fast_retry */ - return 0; + return sw_mrc_ok; } break; - case RESP_RCPT_TIMEO: return -3; /* Timeout on RCPT */ - case RESP_RCPT_ERROR: return -2; /* non-MAIL read i/o error */ - default: return -1; /* any MAIL error */ + case RESP_RCPT_TIMEO: return sw_mrc_nonmail_read_timeo; + case RESP_RCPT_ERROR: return sw_mrc_bad_read; + default: return sw_mrc_bad_mail; /* any MAIL error */ #ifndef DISABLE_PIPE_CONNECT - case RESP_EPIPE_EHLO_ERR: return -1; /* non-2xx for pipelined banner or EHLO */ - case RESP_EHLO_ERR_TLS: return -1; /* TLS first-read error */ + case RESP_EPIPE_EHLO_ERR: return sw_mrc_bad_mail; /* non-2xx for pipelined banner or EHLO */ + case RESP_EHLO_ERR_TLS: return sw_mrc_bad_mail; /* TLS first-read error */ #endif } } @@ -3617,7 +3611,7 @@ sx->next_addr = restart_addr ? restart_addr : addr; #else sx->next_addr = addr; #endif -return 0; +return sw_mrc_ok; } @@ -3925,11 +3919,12 @@ else switch(smtp_write_mail_and_rcpt_cmds(sx, &yield)) { - case 0: break; - case -1: case -2: goto RESPONSE_FAILED; - case -3: goto END_OFF; - case -4: goto SEND_QUIT; - default: goto SEND_FAILED; + case sw_mrc_ok: break; + case sw_mrc_bad_mail: goto RESPONSE_FAILED; + case sw_mrc_bad_read: goto RESPONSE_FAILED; + case sw_mrc_nonmail_read_timeo: goto END_OFF; + case sw_mrc_bad_internal: goto SEND_QUIT; + default: goto SEND_FAILED; } /* If we are an MUA wrapper, abort if any RCPTs were rejected, either diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index 1f888ee0b..ef9135838 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -225,7 +225,7 @@ typedef struct { } smtp_context; extern int smtp_setup_conn(smtp_context *, BOOL); -extern int smtp_write_mail_and_rcpt_cmds(smtp_context *, int *); +extern sw_mrc_t smtp_write_mail_and_rcpt_cmds(smtp_context *, int *); extern int smtp_reap_early_pipe(smtp_context *, int *); diff --git a/src/src/verify.c b/src/src/verify.c index 194e9a76a..bde660063 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -823,7 +823,7 @@ tls_retry_connection: /* Remember when we last did a random test */ new_domain_record.random_stamp = time(NULL); - if (smtp_write_mail_and_rcpt_cmds(sx, &yield) == 0) + if (smtp_write_mail_and_rcpt_cmds(sx, &yield) == sw_mrc_ok) switch(addr->transport_return) { case PENDING_OK: /* random was accepted, unfortunately */ @@ -891,33 +891,34 @@ tls_retry_connection: done = FALSE; switch(smtp_write_mail_and_rcpt_cmds(sx, &yield)) { - case 0: switch(addr->transport_return) /* ok so far */ - { - case PENDING_OK: done = TRUE; - new_address_record.result = ccache_accept; - break; - case FAIL: done = TRUE; - yield = FAIL; - *failure_ptr = US"recipient"; - new_address_record.result = ccache_reject; - break; - default: break; - } - break; + case sw_mrc_ok: + switch(addr->transport_return) /* ok so far */ + { + case PENDING_OK: done = TRUE; + new_address_record.result = ccache_accept; + break; + case FAIL: done = TRUE; + yield = FAIL; + *failure_ptr = US"recipient"; + new_address_record.result = ccache_reject; + break; + default: break; + } + break; - case -1: /* MAIL response error */ - *failure_ptr = US"mail"; - if (errno == 0 && sx->buffer[0] == '5') - { - setflag(addr, af_verify_nsfail); - if (from_address[0] == 0) - new_domain_record.result = ccache_reject_mfnull; - } - break; - /* non-MAIL read i/o error */ - /* non-MAIL response timeout */ - /* internal error; channel still usable */ - default: break; /* transmit failed */ + case sw_mrc_bad_mail: /* MAIL response error */ + *failure_ptr = US"mail"; + if (errno == 0 && sx->buffer[0] == '5') + { + setflag(addr, af_verify_nsfail); + if (from_address[0] == 0) + new_domain_record.result = ccache_reject_mfnull; + } + break; + /* non-MAIL read i/o error */ + /* non-MAIL response timeout */ + /* internal error; channel still usable */ + default: break; /* transmit failed */ } } @@ -955,7 +956,7 @@ tls_retry_connection: sx->completed_addr = FALSE; sx->avoid_option = OPTION_SIZE; - if( smtp_write_mail_and_rcpt_cmds(sx, &yield) == 0 + if( smtp_write_mail_and_rcpt_cmds(sx, &yield) == sw_mrc_ok && addr->transport_return == PENDING_OK ) done = TRUE; commit 690bc2ce8c7f0a76f01d03b5b158b0d64abbc86a Author: Jeremy Harris Date: Sat Oct 14 19:35:34 2023 +0100 fdatasync the spool data file diff --git a/src/src/exim.h b/src/src/exim.h index ccf14f0fd..699b39165 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -569,7 +569,7 @@ requires various things that are set therein. */ #endif #ifdef ENABLE_DISABLE_FSYNC -# define EXIMfsync(f) (disable_fsync? 0 : fsync(f)) +# define EXIMfsync(f) (disable_fsync ? 0 : fsync(f)) #else # define EXIMfsync(f) fsync(f) #endif diff --git a/src/src/receive.c b/src/src/receive.c index ae7045068..63aded09f 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -4052,7 +4052,15 @@ else receive_messagecount++; -if (fflush(spool_data_file)) +if ( fflush(spool_data_file) +#if _POSIX_C_SOURCE >= 199309L || _XOPEN_SOURCE >= 500 +# ifdef ENABLE_DISABLE_FSYNC + || !disable_fsync && fdatasync(data_fd) +# else + || fdatasync(data_fd) +# endif +#endif + ) { errmsg = string_sprintf("Spool write error: %s", strerror(errno)); log_write(0, LOG_MAIN, "%s\n", errmsg); commit 17648b558fc29a488d1e0bc12d2960f892d2838a Author: Jeremy Harris Date: Sun Dec 31 19:59:09 2023 +0000 Rewrites: avoid a split log line when rewiting hits a malformed address. Bug 3160 diff --git a/src/src/parse.c b/src/src/parse.c index 29f98e1e2..ecdbe9f8d 100644 --- a/src/src/parse.c +++ b/src/src/parse.c @@ -69,30 +69,31 @@ Returns: pointer past the end of the address */ uschar * -parse_find_address_end(const uschar *s, BOOL nl_ends) +parse_find_address_end(const uschar * s, BOOL nl_ends) { BOOL source_routing = *s == '@'; -int no_term = source_routing? 1 : 0; +int no_term = source_routing ? 1 : 0; -while (*s != 0 && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends)) +while (*s && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends)) { /* Skip single quoted characters. Strictly these should not occur outside quoted strings in RFC 822 addresses, but they can in RFC 821 addresses. Pity about the lack of consistency, isn't it? */ - if (*s == '\\' && s[1] != 0) s += 2; + if (*s == '\\' && s[1]) + s += 2; /* Skip quoted items that are not inside brackets. Note that quoted pairs are allowed inside quoted strings. */ else if (*s == '\"') - { - while (*(++s) != 0 && (*s != '\n' || !nl_ends)) + while (*++s && (*s != '\n' || !nl_ends)) { - if (*s == '\\' && s[1] != 0) s++; - else if (*s == '\"') { s++; break; } + if (*s == '\\' && s[1]) + s++; + else if (*s == '\"') + { s++; break; } } - } /* Skip comments, which may include nested brackets, but quotes are not recognized inside comments, though quoted pairs are. */ @@ -100,12 +101,13 @@ while (*s != 0 && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends)) else if (*s == '(') { int level = 1; - while (*(++s) != 0 && (*s != '\n' || !nl_ends)) - { - if (*s == '\\' && s[1] != 0) s++; - else if (*s == '(') level++; - else if (*s == ')' && --level <= 0) { s++; break; } - } + while (*++s && (*s != '\n' || !nl_ends)) + if (*s == '\\' && s[1]) + s++; + else if (*s == '(') + level++; + else if (*s == ')' && --level <= 0) + { s++; break; } } /* Non-special character; just advance. Passing the colon in a source @@ -117,10 +119,12 @@ while (*s != 0 && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends)) if (*s == '<') { source_routing = s[1] == '@'; - no_term = source_routing? 2 : 1; + no_term = source_routing ? 2 : 1; } - else if (*s == '>') no_term--; - else if (source_routing && *s == ':') no_term--; + else if (*s == '>') + no_term--; + else if (source_routing && *s == ':') + no_term--; s++; } } diff --git a/src/src/receive.c b/src/src/receive.c index 63aded09f..ae4203e7f 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -3069,7 +3069,7 @@ if ( from_header it has already been rewritten as part of verification for SMTP input. */ DEBUG(D_rewrite) - { debug_printf("global rewrite rules\n"); acl_level++; } + { debug_printf("rewrite rules on sender address\n"); acl_level++; } if (global_rewrite_rules && !sender_address_unrewritten && *sender_address) { /* deconst ok as src was not const */ @@ -3096,7 +3096,7 @@ documented as happening *after* recipient addresses are taken from the headers by the -t command line option. An added Sender: gets rewritten here. */ DEBUG(D_rewrite) - { debug_printf("rewrite headers\n"); acl_level++; } + { debug_printf("qualify and rewrite headers\n"); acl_level++; } for (header_line * h = header_list->next, * newh; h; h = h->next) if ((newh = rewrite_header(h, NULL, NULL, global_rewrite_rules, rewrite_existflags, TRUE))) @@ -3135,9 +3135,11 @@ new Received:) has not yet been set. */ DEBUG(D_receive) { debug_printf(">>Headers after rewriting and local additions:\n"); + acl_level++; for (header_line * h = header_list->next; h; h = h->next) - debug_printf("%c %s", h->type, h->text); + debug_printf_indent("%c %s", h->type, h->text); debug_printf("\n"); + acl_level--; } /* The headers are now complete in store. If we are running in filter diff --git a/src/src/rewrite.c b/src/src/rewrite.c index c0d173abf..318cda215 100644 --- a/src/src/rewrite.c +++ b/src/src/rewrite.c @@ -450,13 +450,13 @@ rewrite_one_header(header_line *h, int flag, rewrite_rule *rewrite_rules, int existflags, BOOL replace) { int lastnewline = 0; -header_line *newh = NULL; +header_line * newh = NULL; rmark function_reset_point = store_mark(); -uschar *s = Ustrchr(h->text, ':') + 1; +uschar * s = Ustrchr(h->text, ':') + 1; while (isspace(*s)) s++; -DEBUG(D_rewrite) +DEBUG(D_rewrite) /* The header text includes the trailing newline */ debug_printf_indent("rewrite_one_header: type=%c:\n %s", h->type, h->text); f.parse_allow_group = TRUE; /* Allow group syntax */ @@ -470,24 +470,31 @@ We want to avoid keeping store for any intermediate versions. */ while (*s) { - uschar *sprev; - uschar *ss = parse_find_address_end(s, FALSE); - uschar *recipient, *new; + uschar * sprev = s; + uschar * ss = parse_find_address_end(s, FALSE), * ss1 = ss; + uschar * recipient, * new; rmark loop_reset_point = store_mark(); - uschar *errmess = NULL; + uschar * errmess = NULL; BOOL changed = FALSE; - int terminator = *ss; + uschar terminator = *ss; int start, end, domain; + /* If we hit the end of the header, trim trailing newline and whitespace */ + + if (!terminator) + { + while (ss1 > s && isspace(ss1[-1])) ss1--; + terminator = *ss1; + } + /* Temporarily terminate the string at this point, and extract the operative address within. Then put back the terminator and prepare for the next address, saving the start of the old one. */ - *ss = 0; + *ss1 = '\0'; recipient = parse_extract_address(s, &errmess, &start, &end, &domain, FALSE); - *ss = terminator; - sprev = s; - s = ss + (terminator ? 1 : 0); + *ss1 = terminator; + s = ss + (*ss ? 1 : 0); while (isspace(*s)) s++; /* There isn't much we can do for syntactic disasters at this stage. @@ -587,7 +594,8 @@ while (*s) point, because we may have a rewritten line from a previous time round the loop. */ - if (!changed) loop_reset_point = store_reset(loop_reset_point); + if (!changed) + loop_reset_point = store_reset(loop_reset_point); /* If the address has changed, create a new header containing the rewritten address. We do not need to set the chain pointers at this commit 12fab4b0af476cf9d4bd389a2c4ebf7ff76e8252 Author: Jeremy Harris Date: Sun Dec 31 22:12:17 2023 +0000 Address qualification: ensure maformed addresses are logged. Bug 3061 diff --git a/src/src/rewrite.c b/src/src/rewrite.c index 318cda215..70bd79e26 100644 --- a/src/src/rewrite.c +++ b/src/src/rewrite.c @@ -510,8 +510,8 @@ while (*s) address, "To: undisclosed recpients:;" being the classic case. Ignore this one and carry on. */ - if ((rewrite_rules || routed_old) && Ustrcmp(errmess, "empty address") != 0) - log_write(0, LOG_MAIN, "rewrite: %s", errmess); + if (Ustrcmp(errmess, "empty address") != 0) + log_write(0, LOG_MAIN, "qualify/rewrite: %s", errmess); loop_reset_point = store_reset(loop_reset_point); continue; commit 4f1d6cb9b60f4d26c0654eba8889c04079d046d2 Author: Jeremy Harris Date: Thu Jan 4 22:29:59 2024 +0000 Report two-phase queue run in daemon startup log line diff --git a/src/src/daemon.c b/src/src/daemon.c index aff05120a..704ede24e 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -1654,7 +1654,7 @@ return 0; -const uschar * +static const uschar * describe_queue_runners(void) { gstring * g = NULL; @@ -1664,6 +1664,7 @@ if (!is_multiple_qrun()) return US"no queue runs"; for (qrunner * q = qrunners; q; q = q->next) { g = string_catn(g, US"-q", 2); + if (q->queue_2stage) g = string_catn(g, US"q", 1); if (q->name) g = string_append(g, 3, US"G", q->name, US"/"); g = string_cat(g, readconf_printtime(q->interval)); g = string_catn(g, US" ", 1); commit 77da14136b689daefe37608b4fd77417cb8c17b3 Author: Simon Arlott Date: Sun Jan 7 18:04:55 2024 +0000 DKIM: signing with t but no x timestamp. Bug 2851 diff --git a/src/src/dkim.c b/src/src/dkim.c index 59025608f..63b16af39 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -720,8 +720,12 @@ if (dkim_domain) if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps))) { errwhen = US"dkim_timestamps"; goto expand_bad; } else - xval = (tval = (unsigned long) time(NULL)) - + strtoul(CCS dkim_timestamps_expanded, NULL, 10); + { + tval = (unsigned long) time(NULL); + xval = strtoul(CCS dkim_timestamps_expanded, NULL, 10); + if (xval > 0) + xval += tval; + } if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain, dkim_signing_selector, commit 15851896ef1507c0901a4150fd869cbce6c17e3d Author: Jeremy Harris Date: Mon Jan 8 16:01:55 2024 +0000 Fix recipient (or source) selection in combination with periodic queue run. Bug 3064 Broken-by: 1e835086d159 diff --git a/src/src/exim.c b/src/src/exim.c index 4473373b3..c53b98186 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -3688,7 +3688,7 @@ on the second character (the one after '-'), to save some effort. */ in all cases provided there are no further characters in this argument. */ - alloc_onetime_qrunner(); + if (!qrunners) alloc_onetime_qrunner(); qrunners->queue_2stage = f.queue_2stage; if (*argrest) for (int i = 0; i < nelem(rsopts); i++) commit 4da37662868dcfd8ec23ad9d7f643ef014b1a42b Author: Heiko Schlichting Date: Fri Jan 12 21:43:54 2024 +0000 Eximon: handle new-format message IDs Broken-by: 46a36afae4 diff --git a/src/exim_monitor/em_hdr.h b/src/exim_monitor/em_hdr.h index feffa6bfc..f79686a80 100644 --- a/src/exim_monitor/em_hdr.h +++ b/src/exim_monitor/em_hdr.h @@ -190,7 +190,7 @@ typedef struct queue_item { int update_time; int size; uschar *sender; - uschar name[17]; + uschar name[MESSAGE_ID_LENGTH + 1]; uschar seen; uschar frozen; uschar dir_char; diff --git a/src/exim_monitor/em_log.c b/src/exim_monitor/em_log.c index 55925d786..fbcb6b1c0 100644 --- a/src/exim_monitor/em_log.c +++ b/src/exim_monitor/em_log.c @@ -108,7 +108,9 @@ length = Ustrlen(buffer); #ifdef ANONYMIZE { uschar *p = buffer + 9; - if (p[6] == '-' && p[13] == '-') p += 17; + if ( p[MESSAGE_ID_TIME_LEN] == '-' + && p[MESSAGE_ID_TIME_LEN + MESSAGE_ID_PID_LEN + 1] == '-') + p += MESSAGE_ID_LENGTH + 1; while (p < buffer + length) { commit 06b43f1b7f7319445d4a71b9a60e3f2f144cf7a2 Author: Jeremy Harris Date: Sat Jan 13 15:24:12 2024 +0000 Lookups: log warning for deprecated syntax. Bug 3068 diff --git a/src/src/lookups/lf_sqlperform.c b/src/src/lookups/lf_sqlperform.c index ecb0a3221..d5bb8d297 100644 --- a/src/src/lookups/lf_sqlperform.c +++ b/src/src/lookups/lf_sqlperform.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2022 */ +/* Copyright (c) The Exim Maintainers 2020 - 2024 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -56,6 +56,8 @@ if (Ustrncmp(query, "servers", 7) == 0) const uschar *qserverlist; uschar *qserver; + log_write(0, LOG_MAIN|LOG_CONFIG_IN, "WARNING: obslete syntax used for lookup\n"); + s = query + 7; skip_whitespace(&s); if (*s++ != '=') commit 17061038519b42b6919af1d3d82d346f2259a114 Author: Jeremy Harris Date: Mon Jan 15 12:54:41 2024 +0000 Exinext: handle new-format message IDs Broken-by: 46a36afae4 diff --git a/src/src/exinext.src b/src/src/exinext.src index 1a1d88f6b..882ad5f60 100644 --- a/src/src/exinext.src +++ b/src/src/exinext.src @@ -163,6 +163,7 @@ perl - $exim_path "$eximmacdef" $argone $spool_directory $qualify_domain $config if (scalar(@list) == 0) { + push(@list, $subject) if $subject =~ /^\w{6}-\w{11}-\w{4}$/; push(@list, $subject) if $subject =~ /^\w{6}-\w{6}-\w{2}$/; if ($subject !~ /\@/ && $subject !~ /\./) commit fe105877d57ac7e05a4333e0d072f232d212b9fe Author: Jeremy Harris Date: Sat Jan 20 12:38:15 2024 +0000 TLS: fix startup after forced-fail Broken-by: cf0c61644d7d, ce93c6d840d5, 520ef00f56ce diff --git a/src/src/expand.c b/src/src/expand.c index 9a88d38ca..f9813133d 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -8558,13 +8558,12 @@ Returns: the expanded string, or NULL if expansion failed; if failure was const uschar * expand_string_2(const uschar * string, BOOL * textonly_p) { +f.expand_string_forcedfail = f.search_find_defer = malformed_header = FALSE; if (Ustrpbrk(string, "$\\") != NULL) { int old_pool = store_pool; uschar * s; - f.search_find_defer = FALSE; - malformed_header = FALSE; store_pool = POOL_MAIN; s = expand_string_internal(string, ESI_HONOR_DOLLAR, NULL, NULL, textonly_p); store_pool = old_pool; diff --git a/src/src/tls.c b/src/src/tls.c index b6c5d70e1..e6203b768 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -105,7 +105,10 @@ expand_check(const uschar * s, const uschar * name, uschar ** result, uschar ** errstr) { if (!s) + { + f.expand_string_forcedfail = FALSE; *result = NULL; + } else if ( !(*result = expand_string(US s)) /* need to clean up const more */ && !f.expand_string_forcedfail ) commit b4e7527561f1c68b821d5cf25efe29ae63d1d434 Author: Jeremy Harris Date: Thu Jan 25 17:48:43 2024 +0000 Appendfile: release regex-match store every thousand files. Bug 3047 diff --git a/src/src/exim.c b/src/src/exim.c index c53b98186..e5b72f11a 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -49,6 +49,8 @@ optimize out the tail recursion and so not make them too expensive. */ static void * function_store_malloc(PCRE2_SIZE size, void * tag) { +if (size > INT_MAX) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "excessive memory alloc request"); return store_malloc((int)size); } @@ -63,12 +65,15 @@ if (block) store_free(block); static void * function_store_get(PCRE2_SIZE size, void * tag) { +if (size > INT_MAX) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "excessive memory alloc request"); return store_get((int)size, GET_UNTAINTED); /* loses track of taint */ } static void function_store_nullfree(void * block, void * tag) { +/* We cannot free memory allocated using store_get() */ } diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index ec41ca035..91b353079 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -153,6 +153,10 @@ static const char *mailbox_formats[] = { (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0)) +/* Free memory allocated by PCRE2 every so often, because a recent version +is now using 20kB for every match call */ + +#define RESET_STORE_FILECNT 1000 /************************************************* * Setup entry point * @@ -661,13 +665,14 @@ Returns: the sum of the sizes of the stattable files off_t check_dir_size(const uschar * dirname, int * countptr, const pcre2_code * re) { -DIR *dir; +DIR * dir; off_t sum = 0; -int count = *countptr; +int count = *countptr, lcount = RESET_STORE_FILECNT; +rmark reset_point = store_mark(); if (!(dir = exim_opendir(dirname))) return 0; -for (struct dirent *ent; ent = readdir(dir); ) +for (struct dirent * ent; ent = readdir(dir); ) { uschar * path, * name = US ent->d_name; struct stat statbuf; @@ -675,6 +680,11 @@ for (struct dirent *ent; ent = readdir(dir); ) if (Ustrcmp(name, ".") == 0 || Ustrcmp(name, "..") == 0) continue; count++; + if (--lcount == 0) + { + store_reset(reset_point); reset_point = store_mark(); + lcount = RESET_STORE_FILECNT; + } /* If there's a regex, try to find the size using it */ @@ -726,6 +736,7 @@ DEBUG(D_transport) debug_printf("check_dir_size: dir=%s sum=" OFF_T_FMT " count=%d\n", dirname, sum, count); +store_reset(reset_point); *countptr = count; return sum; } commit 35aacb69f5c839a4b77158464e401d86eb422ed6 Author: Jeremy Harris Date: Fri Jan 26 21:58:59 2024 +0000 ACL: in "regex" condition, release store every thousand lines. Bug 3047 diff --git a/src/src/acl.c b/src/src/acl.c index 9223fcec8..ecba07b25 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -3955,11 +3955,11 @@ for (; cb; cb = cb->next) CUSS &recipient_data); break; - #ifdef WITH_CONTENT_SCAN +#ifdef WITH_CONTENT_SCAN case ACLC_REGEX: rc = regex(&arg, textonly); break; - #endif +#endif case ACLC_REMOVE_HEADER: setup_remove_header(arg); diff --git a/src/src/macros.h b/src/src/macros.h index 5279f70d0..8aed335b5 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1185,4 +1185,9 @@ typedef enum { sw_mrc_tx_fail, /* transmit failed */ } sw_mrc_t; +/* Recent versions of PCRE2 are allocating 20kB per match, rather than the previous 112 B. +When doing en extended loop of matching, release store periodically. */ + +#define REGEX_LOOPCOUNT_STORE_RESET 1000 + /* End of macros.h */ diff --git a/src/src/regex.c b/src/src/regex.c index af425db2d..cda807716 100644 --- a/src/src/regex.c +++ b/src/src/regex.c @@ -31,12 +31,11 @@ extern uschar *mime_current_boundary; static pcre_list * -compile(const uschar * list, BOOL cacheable) +compile(const uschar * list, BOOL cacheable, int * cntp) { -int sep = 0; +int sep = 0, cnt = 0; uschar * regex_string; -pcre_list * re_list_head = NULL; -pcre_list * ri; +pcre_list * re_list_head = NULL, * ri; /* precompile our regexes */ while ((regex_string = string_nextinlist(&list, &sep, NULL, 0))) @@ -58,7 +57,9 @@ while ((regex_string = string_nextinlist(&list, &sep, NULL, 0))) ri->pcre_text = regex_string; ri->next = re_list_head; re_list_head = ri; + cnt++; } +if (cntp) *cntp = cnt; return re_list_head; } @@ -112,7 +113,8 @@ FILE * mbox_file; pcre_list * re_list_head; uschar * linebuffer; long f_pos = 0; -int ret = FAIL; +int ret = FAIL, cnt, lcount = REGEX_LOOPCOUNT_STORE_RESET; +rmark reset_point; regex_vars_clear(); @@ -136,26 +138,34 @@ else mbox_file = mime_stream; } -/* precompile our regexes */ -if (!(re_list_head = compile(*listptr, cacheable))) - return FAIL; /* no regexes -> nothing to do */ - -/* match each line against all regexes */ -linebuffer = store_get(32767, GET_TAINTED); -while (fgets(CS linebuffer, 32767, mbox_file)) +reset_point = store_mark(); { - if ( mime_stream && mime_current_boundary /* check boundary */ - && Ustrncmp(linebuffer, "--", 2) == 0 - && Ustrncmp((linebuffer+2), mime_current_boundary, - Ustrlen(mime_current_boundary)) == 0) - break; /* found boundary */ - - if ((ret = matcher(re_list_head, linebuffer, (int)Ustrlen(linebuffer))) == OK) - goto done; + /* precompile our regexes */ + if ((re_list_head = compile(*listptr, cacheable, &cnt))) + { + /* match each line against all regexes */ + linebuffer = store_get(32767, GET_TAINTED); + while (fgets(CS linebuffer, 32767, mbox_file)) + { + if ( mime_stream && mime_current_boundary /* check boundary */ + && Ustrncmp(linebuffer, "--", 2) == 0 + && Ustrncmp((linebuffer+2), mime_current_boundary, + Ustrlen(mime_current_boundary)) == 0) + break; /* found boundary */ + + if ((ret = matcher(re_list_head, linebuffer, (int)Ustrlen(linebuffer))) == OK) + break; + + if ((lcount -= cnt) <= 0) + { + store_reset(reset_point); reset_point = store_mark(); + lcount = REGEX_LOOPCOUNT_STORE_RESET; + } + } + } } -/* no matches ... */ +store_reset(reset_point); -done: if (!mime_stream) (void)fclose(mbox_file); else @@ -180,14 +190,11 @@ pcre_list * re_list_head = NULL; FILE * f; uschar * mime_subject = NULL; int mime_subject_len = 0; -int ret; +int ret = FAIL; +rmark reset_point; regex_vars_clear(); -/* precompile our regexes */ -if (!(re_list_head = compile(*listptr, cacheable))) - return FAIL; /* no regexes -> nothing to do */ - /* check if the file is already decoded */ if (!mime_decoded_filename) { /* no, decode it first */ @@ -210,12 +217,20 @@ if (!(f = fopen(CS mime_decoded_filename, "rb"))) return DEFER; } -/* get 32k memory, tainted */ -mime_subject = store_get(32767, GET_TAINTED); +reset_point = store_mark(); + { + /* precompile our regexes */ + if ((re_list_head = compile(*listptr, cacheable, NULL))) + { + /* get 32k memory, tainted */ + mime_subject = store_get(32767, GET_TAINTED); -mime_subject_len = fread(mime_subject, 1, 32766, f); + mime_subject_len = fread(mime_subject, 1, 32766, f); -ret = matcher(re_list_head, mime_subject, mime_subject_len); + ret = matcher(re_list_head, mime_subject, mime_subject_len); + } + } +store_reset(reset_point); (void)fclose(f); return ret; } diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 91b353079..ce52cc6ff 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -153,11 +153,6 @@ static const char *mailbox_formats[] = { (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0)) -/* Free memory allocated by PCRE2 every so often, because a recent version -is now using 20kB for every match call */ - -#define RESET_STORE_FILECNT 1000 - /************************************************* * Setup entry point * *************************************************/ @@ -667,7 +662,7 @@ check_dir_size(const uschar * dirname, int * countptr, const pcre2_code * re) { DIR * dir; off_t sum = 0; -int count = *countptr, lcount = RESET_STORE_FILECNT; +int count = *countptr, lcount = REGEX_LOOPCOUNT_STORE_RESET; rmark reset_point = store_mark(); if (!(dir = exim_opendir(dirname))) return 0; @@ -683,7 +678,7 @@ for (struct dirent * ent; ent = readdir(dir); ) if (--lcount == 0) { store_reset(reset_point); reset_point = store_mark(); - lcount = RESET_STORE_FILECNT; + lcount = REGEX_LOOPCOUNT_STORE_RESET; } /* If there's a regex, try to find the size using it */ commit d0e4bb183c038fe38ee249c1bd096f49120e908a Author: Jeremy Harris Date: Fri Jan 26 21:18:01 2024 +0000 Fix smtp transport response to close after all rcpt fates determined. Bug 3059 diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 817d729a7..c205145a7 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -4518,7 +4518,26 @@ if (!sx->ok) break; case ERRNO_SMTPCLOSED: - message_error = Ustrncmp(smtp_command,"end ",4) == 0; + /* If the peer closed the TCP connection after end-of-data, but before + we could send QUIT, do TLS close, etc - call it a message error. + Otherwise, if all the recipients have been dealt with, call a close no + error at all; each address_item should have a suitable result already + (2xx: PENDING_OK, 4xx: DEFER, 5xx: FAIL) */ + + if (!(message_error = Ustrncmp(smtp_command,"end ",4) == 0)) + { + address_item * addr; + for (addr = sx->addrlist; addr; addr = addr->next) + if (addr->transport_return == PENDING_DEFER) + break; + if (!addr) /* all rcpts fates determined */ + { + log_write(0, LOG_MAIN, "peer close after all rcpt responses;" + " converting i/o-error to no-error"); + sx->ok = TRUE; + goto happy; + } + } break; #ifndef DISABLE_DKIM @@ -4542,7 +4561,8 @@ if (!sx->ok) break; } - /* Handle the cases that are treated as message errors. These are: + /* Handle the cases that are treated as message errors (as opposed to + host-errors). These are: (a) negative response or timeout after MAIL (b) negative response after DATA @@ -4646,6 +4666,8 @@ connection to a new process. However, not all servers can handle this (Exim can), so we do not pass such a connection on if the host matches hosts_nopass_tls. */ +happy: + DEBUG(D_transport) debug_printf("ok=%d send_quit=%d send_rset=%d continue_more=%d " "yield=%d first_address is %sNULL\n", sx->ok, sx->send_quit, @@ -5063,16 +5085,16 @@ Returns: the first address for this delivery */ static address_item * -prepare_addresses(address_item *addrlist, host_item *host) +prepare_addresses(address_item * addrlist, host_item * host) { -address_item *first_addr = NULL; +address_item * first_addr = NULL; for (address_item * addr = addrlist; addr; addr = addr->next) if (addr->transport_return == DEFER) { if (!first_addr) first_addr = addr; addr->transport_return = PENDING_DEFER; addr->basic_errno = 0; - addr->more_errno = (host->mx >= 0)? 'M' : 'A'; + addr->more_errno = host->mx >= 0 ? 'M' : 'A'; addr->message = NULL; #ifndef DISABLE_TLS addr->cipher = NULL; @@ -5104,24 +5126,17 @@ FALSE. */ BOOL smtp_transport_entry( - transport_instance *tblock, /* data for this instantiation */ - address_item *addrlist) /* addresses we are working on */ + transport_instance * tblock, /* data for this instantiation */ + address_item * addrlist) /* addresses we are working on */ { int defport; -int hosts_defer = 0; -int hosts_fail = 0; -int hosts_looked_up = 0; -int hosts_retry = 0; -int hosts_serial = 0; -int hosts_total = 0; -int total_hosts_tried = 0; +int hosts_defer = 0, hosts_fail = 0, hosts_looked_up = 0; +int hosts_retry = 0, hosts_serial = 0, hosts_total = 0, total_hosts_tried = 0; BOOL expired = TRUE; -uschar *expanded_hosts = NULL; -uschar *pistring; -uschar *tid = string_sprintf("%s transport", tblock->name); -smtp_transport_options_block *ob = SOB tblock->options_block; -host_item *hostlist = addrlist->host_list; -host_item *host = NULL; +uschar * expanded_hosts = NULL, * pistring; +uschar * tid = string_sprintf("%s transport", tblock->name); +smtp_transport_options_block * ob = SOB tblock->options_block; +host_item * hostlist = addrlist->host_list, * host = NULL; DEBUG(D_transport) { @@ -5161,7 +5176,7 @@ database if the delivery fails temporarily or if we are running with queue_smtp or a 2-stage queue run. This gets unset for certain kinds of error, typically those that are specific to the message. */ -update_waiting = TRUE; +update_waiting = TRUE; /* If a host list is not defined for the addresses - they must all have the same one in order to be passed to a single transport - or if the transport has @@ -5349,16 +5364,12 @@ retry_non_continued: && total_hosts_tried < ob->hosts_max_try_hardlimit; host = nexthost) { - int rc; - int host_af; - BOOL host_is_expired = FALSE; - BOOL message_defer = FALSE; - BOOL some_deferred = FALSE; - address_item *first_addr = NULL; - uschar *interface = NULL; - uschar *retry_host_key = NULL; - uschar *retry_message_key = NULL; - uschar *serialize_key = NULL; + int rc, host_af; + BOOL host_is_expired = FALSE, message_defer = FALSE, some_deferred = FALSE; + address_item * first_addr = NULL; + uschar * interface = NULL; + uschar * retry_host_key = NULL, * retry_message_key = NULL; + uschar * serialize_key = NULL; /* Deal slightly better with a possible Linux kernel bug that results in intermittent TFO-conn fails deep into the TCP flow. Bug 2907 tracks. @@ -5665,7 +5676,14 @@ retry_non_continued: out the result of previous attempts, and finding the first address that is still to be delivered. */ - first_addr = prepare_addresses(addrlist, host); + if (!(first_addr = prepare_addresses(addrlist, host))) + { + /* Obscure situation; at least one case (bug 3059, fixed) where + a previous host try returned DEFER, but having moved all + recipients away from DEFER (the waiting-to-be-done state). */ + DEBUG(D_transport) debug_printf("no pending recipients\n"); + goto END_TRANSPORT; + } DEBUG(D_transport) debug_printf("delivering %s to %s [%s] (%s%s)\n", message_id, host->name, host->address, addrlist->address, @@ -5717,7 +5735,7 @@ retry_non_continued: { host_item * thost; /* Make a copy of the host if it is local to this invocation - of the transport. */ + of the transport. */ if (expanded_hosts) { @@ -5911,20 +5929,14 @@ retry_non_continued: if (rc == OK) for (address_item * addr = addrlist; addr; addr = addr->next) if (addr->transport_return == DEFER) - { - some_deferred = TRUE; - break; - } + { some_deferred = TRUE; break; } /* If no addresses deferred or the result was ERROR, return. We do this for ERROR because a failing filter set-up or add_headers expansion is likely to fail for any host we try. */ if (rc == ERROR || (rc == OK && !some_deferred)) - { - DEBUG(D_transport) debug_printf("Leaving %s transport\n", tblock->name); - return TRUE; /* Each address has its status */ - } + goto END_TRANSPORT; /* If the result was DEFER or some individual addresses deferred, let the loop run to try other hosts with the deferred addresses, except for the @@ -5944,7 +5956,7 @@ retry_non_continued: if ((rc == DEFER || some_deferred) && nexthost) { BOOL timedout; - retry_config *retry = retry_find_config(host->name, NULL, 0, 0); + retry_config * retry = retry_find_config(host->name, NULL, 0, 0); if (retry && retry->rules) { commit cd8cb71deb2d653228cc037cf91ecab980acdcd0 Author: Jeremy Harris Date: Sat Feb 10 16:44:54 2024 +0000 Move ESMPT LIMITS extension from experimental to mainline diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 28d4f13f7..c08f1874d 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -51,6 +51,7 @@ Do not put spaces between # and the 'define'. #define DISABLE_D_OPTION #define DISABLE_DNSSEC #define DISABLE_DKIM +#define DISABLE_ESMTP_LIMITS #define DISABLE_EVENT #define DISABLE_OCSP #define DISABLE_PIPE_CONNECT @@ -209,7 +210,6 @@ Do not put spaces between # and the 'define'. #define EXPERIMENTAL_BRIGHTMAIL #define EXPERIMENTAL_DCC #define EXPERIMENTAL_DSN_INFO -#define EXPERIMENTAL_ESMTP_LIMITS #define EXPERIMENTAL_QUEUEFILE #define EXPERIMENTAL_XCLIENT diff --git a/src/src/exim.c b/src/src/exim.c index e5b72f11a..1f76f8f14 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1105,6 +1105,9 @@ g = string_cat(g, US"Support for:"); #ifndef DISABLE_DNSSEC g = string_cat(g, US" DNSSEC"); #endif +#ifndef DISABLE_ESMTP_LIMITS + g = string_cat(g, US" ESMTP_Limits"); +#endif #ifndef DISABLE_EVENT g = string_cat(g, US" Event"); #endif @@ -1151,9 +1154,6 @@ g = string_cat(g, US"Support for:"); #ifdef EXPERIMENTAL_DSN_INFO g = string_cat(g, US" Experimental_DSN_info"); #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS - g = string_cat(g, US" Experimental_ESMTP_Limits"); -#endif #ifdef EXPERIMENTAL_QUEUEFILE g = string_cat(g, US" Experimental_QUEUEFILE"); #endif @@ -3019,7 +3019,7 @@ on the second character (the one after '-'), to save some effort. */ case 'K': smtp_peer_options |= OPTION_CHUNKING; break; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS /* -MCL: peer used LIMITS RCPTMAX and/or RCPTDOMAINMAX */ case 'L': if (++i < argc) continue_limit_mail = Uatoi(argv[i]); else badarg = TRUE; diff --git a/src/src/functions.h b/src/src/functions.h index ef84e3d7c..77323a5c1 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -632,7 +632,7 @@ extern void transport_do_pass_socket(const uschar *, const uschar *, const uschar *, uschar *, int); extern void transport_init(void); extern BOOL transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *, int -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS , unsigned, unsigned, unsigned #endif ); diff --git a/src/src/globals.c b/src/src/globals.c index c535ea121..c483ab182 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -706,7 +706,7 @@ unsigned chunking_data_left = 0; chunking_state_t chunking_state= CHUNKING_NOT_OFFERED; const pcre2_code *regex_CHUNKING = NULL; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS const pcre2_code *regex_LIMITS = NULL; #endif @@ -746,7 +746,7 @@ uschar *continue_hostname = NULL; uschar *continue_host_address = NULL; int continue_sequence = 1; uschar *continue_transport = NULL; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS unsigned continue_limit_mail = 0; unsigned continue_limit_rcpt = 0; unsigned continue_limit_rcptdom= 0; @@ -1029,7 +1029,7 @@ const uschar *letter_digit_hyphen_dot = US"abcdefghijklmnopqrstuvwxyz" ".-0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS uschar *limits_advertise_hosts = US"*"; #endif int load_average = -2; diff --git a/src/src/globals.h b/src/src/globals.h index ffc7150f2..b5c3a520e 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -449,7 +449,7 @@ extern uschar *continue_hostname; /* Host for continued delivery */ extern uschar *continue_host_address; /* IP address for ditto */ extern int continue_sequence; /* Sequence num for continued delivery */ extern uschar *continue_transport; /* Transport for continued delivery */ -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS extern unsigned continue_limit_mail; /* Peer advertised limit */ extern unsigned continue_limit_rcpt; extern unsigned continue_limit_rcptdom; @@ -688,7 +688,7 @@ extern int keep_malformed; /* Time to keep malformed messages */ extern uschar *eldap_dn; /* Where LDAP DNs are left */ extern const uschar *letter_digit_hyphen_dot; /* Legitimate DNS host name chars */ -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS extern uschar *limits_advertise_hosts; /* for banner/EHLO pipelining */ #endif extern int load_average; /* Most recently read load average */ @@ -902,7 +902,7 @@ extern const pcre2_code *regex_check_dns_names; /* For DNS name checking */ extern const pcre2_code *regex_From; /* For recognizing "From_" lines */ extern const pcre2_code *regex_CHUNKING; /* For recognizing CHUNKING (RFC 3030) */ extern const pcre2_code *regex_IGNOREQUOTA; /* For recognizing IGNOREQUOTA (LMTP) */ -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS extern const pcre2_code *regex_LIMITS; /* For recognizing LIMITS */ #endif extern const pcre2_code *regex_PIPELINING; /* For recognizing PIPELINING */ diff --git a/src/src/hintsdb_structs.h b/src/src/hintsdb_structs.h index 0e5853b2b..5da311c2b 100644 --- a/src/src/hintsdb_structs.h +++ b/src/src/hintsdb_structs.h @@ -163,7 +163,7 @@ typedef struct { unsigned short cleartext_auths; unsigned short crypted_auths; -# ifdef EXPERIMENTAL_ESMTP_LIMITS +# ifndef DISABLE_ESMTP_LIMITS unsigned int limit_mail; unsigned int limit_rcpt; unsigned int limit_rcptdom; diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c index bdc587502..9b354d345 100644 --- a/src/src/macro_predef.c +++ b/src/src/macro_predef.c @@ -160,6 +160,9 @@ due to conflicts with other common macros. */ #ifndef DISABLE_DNSSEC builtin_macro_create(US"_HAVE_DNSSEC"); #endif +#ifndef DISABLE_ESMTP_LIMITS + builtin_macro_create(US"_HAVE_ESMTP_LIMITS"); +#endif #ifndef DISABLE_EVENT builtin_macro_create(US"_HAVE_EVENT"); #endif @@ -309,9 +312,6 @@ exp_features(void) #ifdef EXPERIMENTAL_DSN_INFO builtin_macro_create(US"_EXP_DSNI"); #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS - builtin_macro_create(US"_EXP_LIMITS"); -#endif #ifdef EXPERIMENTAL_QUEUEFILE builtin_macro_create(US"_EXP_QUEUEFILE"); #endif diff --git a/src/src/readconf.c b/src/src/readconf.c index bbcca87f7..8ee6e9fe0 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -209,7 +209,7 @@ static optionlist optionlist_config[] = { { "ldap_start_tls", opt_bool, {&eldap_start_tls} }, { "ldap_version", opt_int, {&eldap_version} }, #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS { "limits_advertise_hosts", opt_stringptr, {&limits_advertise_hosts} }, #endif { "local_from_check", opt_bool, {&local_from_check} }, diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 541288301..a57c9821e 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -4054,7 +4054,7 @@ while (done <= 0) g = string_catn(g, US"-SIZE\r\n", 7); } -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS if ( (smtp_mailcmd_max > 0 || recipients_max) && verify_check_host(&limits_advertise_hosts) == OK) { diff --git a/src/src/transport.c b/src/src/transport.c index 79a69f941..5729f8e75 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -1941,7 +1941,7 @@ const uschar **argv; #ifndef DISABLE_TLS if (smtp_peer_options & OPTION_TLS) i += 6; #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS if (continue_limit_mail || continue_limit_rcpt || continue_limit_rcptdom) i += 4; #endif @@ -1983,7 +1983,7 @@ if (smtp_peer_options & OPTION_TLS) argv[i++] = US"-MCT"; #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS if (continue_limit_rcpt || continue_limit_rcptdom) { argv[i++] = US"-MCL"; @@ -2055,7 +2055,7 @@ Returns: FALSE if fork fails; TRUE otherwise BOOL transport_pass_socket(const uschar *transport_name, const uschar *hostname, const uschar *hostaddress, uschar *id, int socket_fd -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS , unsigned peer_limit_mail, unsigned peer_limit_rcpt, unsigned peer_limit_rcptdom #endif ) @@ -2065,7 +2065,7 @@ int status; DEBUG(D_transport) debug_printf("transport_pass_socket entered\n"); -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS continue_limit_mail = peer_limit_mail; continue_limit_rcpt = peer_limit_rcpt; continue_limit_rcptdom = peer_limit_rcptdom; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index c205145a7..596a328c3 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -277,7 +277,7 @@ struct list #ifndef DISABLE_PIPE_CONNECT { ®ex_EARLY_PIPE, US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)" }, #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS { ®ex_LIMITS, US"\\n250[\\s\\-]LIMITS\\s" }, #endif }; @@ -797,7 +797,7 @@ sx->conn_args.have_lbserver = TRUE; /******************************************************************************/ -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS /* If TLS, or TLS not offered, called with the EHLO response in the buffer. Check it for a LIMITS keyword and parse values into the smtp context structure. @@ -900,7 +900,7 @@ write_ehlo_cache_entry(smtp_context * sx) { open_db dbblock, * dbm_file; -# ifdef EXPERIMENTAL_ESMTP_LIMITS +# ifndef DISABLE_ESMTP_LIMITS sx->ehlo_resp.limit_mail = sx->peer_limit_mail; sx->ehlo_resp.limit_rcpt = sx->peer_limit_rcpt; sx->ehlo_resp.limit_rcptdom = sx->peer_limit_rcptdom; @@ -912,7 +912,7 @@ if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE))) dbdata_ehlo_resp er = { .data = sx->ehlo_resp }; HDEBUG(D_transport) -# ifdef EXPERIMENTAL_ESMTP_LIMITS +# ifndef DISABLE_ESMTP_LIMITS if (sx->ehlo_resp.limit_mail || sx->ehlo_resp.limit_rcpt || sx->ehlo_resp.limit_rcptdom) debug_printf("writing clr %04x/%04x cry %04x/%04x lim %05d/%05d/%05d\n", sx->ehlo_resp.cleartext_features, sx->ehlo_resp.cleartext_auths, @@ -979,7 +979,7 @@ else else { DEBUG(D_transport) -# ifdef EXPERIMENTAL_ESMTP_LIMITS +# ifndef DISABLE_ESMTP_LIMITS if (er->data.limit_mail || er->data.limit_rcpt || er->data.limit_rcptdom) debug_printf("EHLO response bits from cache:" " cleartext 0x%04x/0x%04x crypted 0x%04x/0x%04x lim %05d/%05d/%05d\n", @@ -994,7 +994,7 @@ else er->data.crypted_features, er->data.crypted_auths); sx->ehlo_resp = er->data; -# ifdef EXPERIMENTAL_ESMTP_LIMITS +# ifndef DISABLE_ESMTP_LIMITS ehlo_cache_limits_apply(sx); # endif dbfn_close(dbm_file); @@ -1120,7 +1120,7 @@ if (pending_EHLO) | OPTION_CHUNKING | OPTION_PRDR | OPTION_DSN | OPTION_PIPE | OPTION_SIZE | OPTION_UTF8 | OPTION_EARLY_PIPE ); -# ifdef EXPERIMENTAL_ESMTP_LIMITS +# ifndef DISABLE_ESMTP_LIMITS if (tls_out.active.sock >= 0 || !(peer_offered & OPTION_TLS)) ehlo_response_limits_read(sx); # endif @@ -1147,7 +1147,7 @@ if (pending_EHLO) return OK; /* just carry on */ } -# ifdef EXPERIMENTAL_ESMTP_LIMITS +# ifndef DISABLE_ESMTP_LIMITS /* If we are handling LIMITS, compare the actual EHLO LIMITS values with the cached values and invalidate cache if different. OK to carry on with connect since values are advisory. */ @@ -2305,7 +2305,7 @@ if (!continue_hostname) sx->cctx.tls_ctx = NULL; sx->inblock.cctx = sx->outblock.cctx = &sx->cctx; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS sx->peer_limit_mail = sx->peer_limit_rcpt = sx->peer_limit_rcptdom = #endif sx->avoid_option = sx->peer_offered = smtp_peer_options = 0; @@ -2607,7 +2607,7 @@ goto SEND_QUIT; ) #endif ); -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS if (tls_out.active.sock >= 0 || !(sx->peer_offered & OPTION_TLS)) { ehlo_response_limits_read(sx); @@ -2672,7 +2672,7 @@ else sx->inblock.cctx = sx->outblock.cctx = &sx->cctx; smtp_command = big_buffer; sx->peer_offered = smtp_peer_options; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS /* Limits passed by cmdline over exec. */ ehlo_limits_apply(sx, sx->peer_limit_mail = continue_limit_mail, @@ -3000,7 +3000,7 @@ if ( !continue_hostname sx->ehlo_resp.crypted_features = sx->peer_offered; #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS if (tls_out.active.sock >= 0 || !(sx->peer_offered & OPTION_TLS)) { ehlo_response_limits_read(sx); @@ -3423,7 +3423,7 @@ sw_mrc_t smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield) { address_item * addr; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS address_item * restart_addr = NULL; #endif int address_count, pipe_limit; @@ -3517,7 +3517,7 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; BOOL no_flush; const uschar * rcpt_addr; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS if ( sx->single_rcpt_domain /* restriction on domains */ && address_count > 0 /* not first being sent */ && Ustrcmp(addr->domain, sx->first_addr->domain) != 0 /* dom diff from first */ @@ -3606,7 +3606,7 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; } } /* Loop for next address */ -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS sx->next_addr = restart_addr ? restart_addr : addr; #else sx->next_addr = addr; @@ -3790,7 +3790,7 @@ uschar *message = NULL; uschar new_message_id[MESSAGE_ID_LENGTH + 1]; smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED); /* tainted, for the data buffers */ BOOL pass_message = FALSE; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS BOOL mail_limit = FALSE; #endif #ifdef SUPPORT_DANE @@ -4674,7 +4674,7 @@ DEBUG(D_transport) sx->send_rset, f.continue_more, yield, sx->first_addr ? "not " : ""); if (sx->completed_addr && sx->ok && sx->send_quit) -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS if (mail_limit = continue_sequence >= sx->max_mail) { DEBUG(D_transport) @@ -4735,7 +4735,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) if (sx->first_addr) /* More addresses still to be sent */ { /* for this message */ -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS /* Any that we marked as skipped, reset to do now */ for (address_item * a = sx->first_addr; a; a = a->next) if (a->transport_return == SKIP) @@ -4810,7 +4810,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) */ if (sx->ok && transport_pass_socket(tblock->name, host->name, host->address, new_message_id, socket_fd -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS , sx->peer_limit_mail, sx->peer_limit_rcpt, sx->peer_limit_rcptdom #endif )) @@ -4987,7 +4987,7 @@ if (dane_held) } #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS if (mail_limit && sx->first_addr) { /* Reset the sequence count since we closed the connection. This is flagged diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index ef9135838..fc8a6b126 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -176,7 +176,7 @@ typedef struct { BOOL pending_BDAT:1; BOOL RCPT_452:1; BOOL good_RCPT:1; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS BOOL single_rcpt_domain:1; #endif BOOL completed_addr:1; @@ -185,7 +185,7 @@ typedef struct { BOOL send_tlsclose:1; unsigned peer_offered; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS unsigned peer_limit_mail; unsigned peer_limit_rcpt; unsigned peer_limit_rcptdom; commit 84add256b3467cf6e0d4a2edf72cf5bf16cd9306 Author: Jeremy Harris Date: Sun Feb 11 13:57:18 2024 +0000 Use non-releaseable memory for regex match strings. Bug 3047 Broken-by: 35aacb69f5c8 diff --git a/src/src/regex.c b/src/src/regex.c index cda807716..bb34e5b23 100644 --- a/src/src/regex.c +++ b/src/src/regex.c @@ -63,6 +63,13 @@ if (cntp) *cntp = cnt; return re_list_head; } + +/* Check list of REs against buffer, returning OK for (first) match, +else FAIL. On match return allocated result strings in regex_vars[]. + +We use the perm-pool for that, so that our caller can release +other allocations. +*/ static int matcher(pcre_list * re_list_head, uschar * linebuffer, int len) { @@ -75,6 +82,9 @@ for (pcre_list * ri = re_list_head; ri; ri = ri->next) /* try matcher on the line */ if ((n = pcre2_match(ri->re, (PCRE2_SPTR)linebuffer, len, 0, 0, md, pcre_gen_mtc_ctx)) > 0) { + int save_pool = store_pool; + store_pool = POOL_PERM; + Ustrncpy(regex_match_string_buffer, ri->pcre_text, sizeof(regex_match_string_buffer)-1); regex_match_string = regex_match_string_buffer; @@ -87,6 +97,7 @@ for (pcre_list * ri = re_list_head; ri; ri = ri->next) regex_vars[nn-1] = string_copyn(linebuffer + ovec[off], len); } + store_pool = save_pool; return OK; } } commit 6fcb3173d64ef8a9d70f8adf19f134a0cd9cf6e8 Author: Jeremy Harris Date: Sun Feb 11 15:04:58 2024 +0000 use dynamic mem for regex_match_string diff --git a/src/src/regex.c b/src/src/regex.c index bb34e5b23..d5dc10258 100644 --- a/src/src/regex.c +++ b/src/src/regex.c @@ -24,8 +24,6 @@ typedef struct pcre_list { struct pcre_list * next; } pcre_list; -uschar regex_match_string_buffer[1024]; - extern FILE *mime_stream; extern uschar *mime_current_boundary; @@ -85,9 +83,7 @@ for (pcre_list * ri = re_list_head; ri; ri = ri->next) int save_pool = store_pool; store_pool = POOL_PERM; - Ustrncpy(regex_match_string_buffer, ri->pcre_text, - sizeof(regex_match_string_buffer)-1); - regex_match_string = regex_match_string_buffer; + regex_match_string = string_copy(ri->pcre_text); for (int nn = 1; nn < n; nn++) { commit a173a4376d168edbf3fe2494dff998c4060bf425 Author: Jeremy Harris Date: Tue Feb 13 17:34:19 2024 +0000 Use non-releasable memory for regex line-buffer Broken-by: 5aacb69f5c8 diff --git a/src/src/regex.c b/src/src/regex.c index d5dc10258..642b9cf93 100644 --- a/src/src/regex.c +++ b/src/src/regex.c @@ -118,7 +118,6 @@ regex(const uschar ** listptr, BOOL cacheable) unsigned long mbox_size; FILE * mbox_file; pcre_list * re_list_head; -uschar * linebuffer; long f_pos = 0; int ret = FAIL, cnt, lcount = REGEX_LOOPCOUNT_STORE_RESET; rmark reset_point; @@ -151,16 +150,15 @@ reset_point = store_mark(); if ((re_list_head = compile(*listptr, cacheable, &cnt))) { /* match each line against all regexes */ - linebuffer = store_get(32767, GET_TAINTED); - while (fgets(CS linebuffer, 32767, mbox_file)) + while (fgets(CS big_buffer, big_buffer_size, mbox_file)) { if ( mime_stream && mime_current_boundary /* check boundary */ - && Ustrncmp(linebuffer, "--", 2) == 0 - && Ustrncmp((linebuffer+2), mime_current_boundary, + && Ustrncmp(big_buffer, "--", 2) == 0 + && Ustrncmp((big_buffer+2), mime_current_boundary, Ustrlen(mime_current_boundary)) == 0) break; /* found boundary */ - if ((ret = matcher(re_list_head, linebuffer, (int)Ustrlen(linebuffer))) == OK) + if ((ret = matcher(re_list_head, big_buffer, (int)Ustrlen(big_buffer))) == OK) break; if ((lcount -= cnt) <= 0) commit cd19f9a79c20f9c0c9d650a8aa21d9cc54a66620 Author: Jeremy Harris Date: Sun Feb 11 23:32:34 2024 +0000 Expand recipients_max diff --git a/src/src/exim.c b/src/src/exim.c index 1f76f8f14..10fc98963 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -5339,6 +5339,7 @@ if (expansion_test) else if (expansion_test_message) { + uschar * rme = expand_string(recipients_max); int save_stdin = dup(0); int fd = Uopen(expansion_test_message, O_RDONLY, 0); if (fd < 0) @@ -5347,6 +5348,7 @@ if (expansion_test) (void) dup2(fd, 0); filter_test = FTEST_USER; /* Fudge to make it look like filter test */ message_ended = END_NOTENDED; + recipients_max_expanded = atoi(CCS rme); read_message_body(receive_msg(extract_recipients)); message_linecount += body_linecount; (void)dup2(save_stdin, 0); @@ -5753,8 +5755,8 @@ for (BOOL more = TRUE; more; ) int rc; if ((rc = smtp_setup_msg()) > 0) { - if (real_sender_address != NULL && - !receive_check_set_sender(sender_address)) + if ( real_sender_address + && !receive_check_set_sender(sender_address)) { sender_address = raw_sender = real_sender_address; sender_address_unrewritten = NULL; @@ -5801,10 +5803,12 @@ for (BOOL more = TRUE; more; ) else { - int rcount = 0; - int count = argc - recipients_arg; + uschar * rme = expand_string(recipients_max); + int rcount = 0, count = argc - recipients_arg; const uschar ** list = argv + recipients_arg; + recipients_max_expanded = atoi(CCS rme); + /* These options cannot be changed dynamically for non-SMTP messages */ f.active_local_sender_retain = local_sender_retain; @@ -5831,15 +5835,19 @@ for (BOOL more = TRUE; more; ) while (*s) { BOOL finished = FALSE; - uschar *recipient; - uschar *ss = parse_find_address_end(s, FALSE); + uschar * recipient; + uschar * ss = parse_find_address_end(s, FALSE); if (*ss == ',') *ss = 0; else finished = TRUE; /* Check max recipients - if -t was used, these aren't recipients */ - if (recipients_max > 0 && ++rcount > recipients_max && - !extract_recipients) + if ( recipients_max_expanded > 0 && ++rcount > recipients_max_expanded + && !extract_recipients) + { + DEBUG(D_all) debug_printf("excess reipients (max %d)\n", + recipients_max_expanded); + if (error_handling == ERRORS_STDERR) { fprintf(stderr, "exim: too many recipients\n"); @@ -5849,6 +5857,7 @@ for (BOOL more = TRUE; more; ) return moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)? errors_sender_rc : EXIT_FAILURE; + } #ifdef SUPPORT_I18N { @@ -5873,6 +5882,10 @@ for (BOOL more = TRUE; more; ) } if (!recipient) + { + DEBUG(D_all) debug_printf("bad recipient address \"%s\": %s\n", + string_printing(list[i]), errmess); + if (error_handling == ERRORS_STDERR) { fprintf(stderr, "exim: bad recipient address \"%s\": %s\n", @@ -5889,6 +5902,7 @@ for (BOOL more = TRUE; more; ) moan_to_sender(ERRMESS_BADARGADDRESS, &eblock, NULL, stdin, TRUE)? errors_sender_rc : EXIT_FAILURE; } + } receive_add_recipient(string_copy_taint(recipient, GET_TAINTED), -1); s = ss; diff --git a/src/src/globals.c b/src/src/globals.c index c483ab182..4af8668f0 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1322,7 +1322,8 @@ uschar *recipient_verify_failure = NULL; int recipients_count = 0; recipient_item *recipients_list = NULL; int recipients_list_max = 0; -int recipients_max = 50000; +uschar *recipients_max = US"50000"; +int recipients_max_expanded= 0; const pcre2_code *regex_AUTH = NULL; const pcre2_code *regex_check_dns_names = NULL; const pcre2_code *regex_From = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index b5c3a520e..427590050 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -895,7 +895,8 @@ extern uschar *recipient_data; /* lookup data for recipients */ extern uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */ extern uschar *recipient_verify_failure; /* What went wrong */ extern int recipients_list_max; /* Maximum number fitting in list */ -extern int recipients_max; /* Max permitted */ +extern uschar *recipients_max; /* Max permitted */ +extern int recipients_max_expanded; extern BOOL recipients_max_reject; /* If TRUE, reject whole message */ extern const pcre2_code *regex_AUTH; /* For recognizing AUTH settings */ extern const pcre2_code *regex_check_dns_names; /* For DNS name checking */ diff --git a/src/src/moan.c b/src/src/moan.c index c2e38d4f7..a3c8e0aba 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -561,7 +561,7 @@ switch(ident) case ERRMESS_TOOMANYRECIP: log_write(0, LOG_MAIN, "%s: too many recipients (max set to %d)", msg, - recipients_max); + recipients_max_expanded); break; case ERRMESS_LOCAL_SCAN: diff --git a/src/src/readconf.c b/src/src/readconf.c index 8ee6e9fe0..5b486d0b6 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -293,7 +293,7 @@ static optionlist optionlist_config[] = { { "received_header_text", opt_stringptr, {&received_header_text} }, { "received_headers_max", opt_int, {&received_headers_max} }, { "recipient_unqualified_hosts", opt_stringptr, {&recipient_unqualified_hosts} }, - { "recipients_max", opt_int, {&recipients_max} }, + { "recipients_max", opt_stringptr, {&recipients_max} }, { "recipients_max_reject", opt_bool, {&recipients_max_reject} }, #ifdef LOOKUP_REDIS { "redis_servers", opt_stringptr, {&redis_servers} }, diff --git a/src/src/receive.c b/src/src/receive.c index ae4203e7f..990b9c22e 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1204,6 +1204,8 @@ static void give_local_error(int errcode, uschar *text1, uschar *text2, int error_rc, FILE *f, header_line *hptr) { +DEBUG(D_all) debug_printf("%s%s\n", text2, text1); + if (error_handling == ERRORS_SENDER) { error_block eblock; @@ -2622,12 +2624,12 @@ if (extract_recip) if ((h->type == htype_to || h->type == htype_cc || h->type == htype_bcc) && (!contains_resent_headers || strncmpic(h->text, US"resent-", 7) == 0)) { - uschar *s = Ustrchr(h->text, ':') + 1; + uschar * s = Ustrchr(h->text, ':') + 1; while (isspace(*s)) s++; f.parse_allow_group = TRUE; /* Allow address group syntax */ - while (*s != 0) + while (*s) { uschar *ss = parse_find_address_end(s, FALSE); uschar *recipient, *errmess, *pp; @@ -2635,7 +2637,7 @@ if (extract_recip) /* Check on maximum */ - if (recipients_max > 0 && ++rcount > recipients_max) + if (recipients_max_expanded > 0 && ++rcount > recipients_max_expanded) give_local_error(ERRMESS_TOOMANYRECIP, US"too many recipients", US"message rejected: ", error_rc, stdin, NULL); /* Does not return */ diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index a57c9821e..1d4c232a5 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1879,7 +1879,7 @@ while (done <= 0) if (recipients_max > 0 && recipients_count + 1 > recipients_max) /* The function moan_smtp_batch() does not return. */ moan_smtp_batch(smtp_cmd_buffer, "%s too many recipients", - recipients_max_reject? "552": "452"); + recipients_max_reject ? "552": "452"); /* Apply SMTP rewrite, then extract address. Don't allow "<>" as a recipient address */ @@ -2540,6 +2540,11 @@ if (!f.sender_host_unknown) fl.helo_accept_junk = verify_check_host(&helo_accept_junk_hosts) == OK; } +/* Expand recipients_max, if needed */ + { + uschar * rme = expand_string(recipients_max); + recipients_max_expanded = atoi(CCS rme); + } /* For batch SMTP input we are now done. */ if (smtp_batched_input) return TRUE; @@ -4055,14 +4060,14 @@ while (done <= 0) } #ifndef DISABLE_ESMTP_LIMITS - if ( (smtp_mailcmd_max > 0 || recipients_max) + if ( (smtp_mailcmd_max > 0 || recipients_max_expanded > 0) && verify_check_host(&limits_advertise_hosts) == OK) { g = string_fmt_append(g, "%.3s-LIMITS", smtp_code); if (smtp_mailcmd_max > 0) g = string_fmt_append(g, " MAILMAX=%d", smtp_mailcmd_max); - if (recipients_max) - g = string_fmt_append(g, " RCPTMAX=%d", recipients_max); + if (recipients_max > 9) + g = string_fmt_append(g, " RCPTMAX=%d", recipients_max_expanded); g = string_catn(g, US"\r\n", 2); } #endif @@ -4900,7 +4905,8 @@ while (done <= 0) /* Check maximum allowed */ - if (rcpt_count+1 < 0 || rcpt_count > recipients_max && recipients_max > 0) + if ( rcpt_count+1 < 0 + || rcpt_count > recipients_max_expanded && recipients_max_expanded > 0) { if (recipients_max_reject) { commit 7502f0cbd3753de473a2279acaae15f9bbdfb5ee Author: Jeremy Harris Date: Wed Feb 14 11:25:52 2024 +0000 Expand recipients_max, smtp-batch input diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 1d4c232a5..2d977b975 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1876,7 +1876,8 @@ while (done <= 0) /* Check maximum number allowed */ - if (recipients_max > 0 && recipients_count + 1 > recipients_max) + if ( recipients_max_expanded > 0 + && recipients_count + 1 > recipients_max_expanded) /* The function moan_smtp_batch() does not return. */ moan_smtp_batch(smtp_cmd_buffer, "%s too many recipients", recipients_max_reject ? "552": "452"); @@ -4066,7 +4067,7 @@ while (done <= 0) g = string_fmt_append(g, "%.3s-LIMITS", smtp_code); if (smtp_mailcmd_max > 0) g = string_fmt_append(g, " MAILMAX=%d", smtp_mailcmd_max); - if (recipients_max > 9) + if (recipients_max_expanded > 0) g = string_fmt_append(g, " RCPTMAX=%d", recipients_max_expanded); g = string_catn(g, US"\r\n", 2); } commit 44b3172e369435c2c1baa4e9c837252f729d2905 Author: Jeremy Harris Date: Thu Feb 15 19:56:40 2024 +0000 regex: avoid releasing built RE midloop diff --git a/src/src/regex.c b/src/src/regex.c index 642b9cf93..285ab8dbd 100644 --- a/src/src/regex.c +++ b/src/src/regex.c @@ -120,7 +120,6 @@ FILE * mbox_file; pcre_list * re_list_head; long f_pos = 0; int ret = FAIL, cnt, lcount = REGEX_LOOPCOUNT_STORE_RESET; -rmark reset_point; regex_vars_clear(); @@ -144,11 +143,11 @@ else mbox_file = mime_stream; } -reset_point = store_mark(); - { /* precompile our regexes */ if ((re_list_head = compile(*listptr, cacheable, &cnt))) { + rmark reset_point = store_mark(); + /* match each line against all regexes */ while (fgets(CS big_buffer, big_buffer_size, mbox_file)) { @@ -167,9 +166,9 @@ reset_point = store_mark(); lcount = REGEX_LOOPCOUNT_STORE_RESET; } } + + store_reset(reset_point); } - } -store_reset(reset_point); if (!mime_stream) (void)fclose(mbox_file); commit 90bd3832bc0ff090ac5e37dfc66b30cabb9cfc1a Author: Jeremy Harris Date: Fri Feb 16 23:16:29 2024 +0000 Debug: option access for expansion diff --git a/src/src/daemon.c b/src/src/daemon.c index 704ede24e..3c63c6368 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -298,9 +298,10 @@ to provide host-specific limits according to $sender_host address, but because this is in the daemon mainline, only fast expansions (such as inline address checks) should be used. The documentation is full of warnings. */ +GET_OPTION("smtp_accept_max_per_host"); if (smtp_accept_max_per_host) { - uschar *expanded = expand_string(smtp_accept_max_per_host); + uschar * expanded = expand_string(smtp_accept_max_per_host); if (!expanded) { if (!f.expand_string_forcedfail) @@ -434,6 +435,7 @@ if (pid == 0) likely what it depends on.) */ smtp_active_hostname = primary_hostname; + GET_OPTION("smtp_active_hostname"); if (raw_active_hostname) { uschar * nah = expand_string(raw_active_hostname); @@ -1165,6 +1167,7 @@ return offsetof(struct sockaddr_un, sun_path) ssize_t daemon_notifier_sockname(struct sockaddr_un * sup) { +GET_OPTION("notifier_socket"); #ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS sup->sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */ return offsetof(struct sockaddr_un, sun_path) + 1 @@ -1709,12 +1712,13 @@ time_t last_connection_time = (time_t)0; int local_queue_run_max = 0; if (is_multiple_qrun()) - + { /* Nuber of runner-tracking structs needed: If the option queue_run_max has no expandable elements then it is the overall maximum; else we assume it depends on the queue name, and add them up to get the maximum. Evaluate both that and the individual limits. */ + GET_OPTION("queue_run_max"); if (Ustrchr(queue_run_max, '$') != NULL) { for (qrunner * q = qrunners; q; q = q->next) @@ -1731,6 +1735,7 @@ if (is_multiple_qrun()) for (qrunner * q = qrunners; q; q = q->next) q->run_max = local_queue_run_max; } + } process_purpose = US"daemon"; diff --git a/src/src/deliver.c b/src/src/deliver.c index 2cef3d731..70f44535f 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -1858,8 +1858,9 @@ if (tp->gid_set) } else if (tp->expand_gid) { + GET_OPTION("group"); if (!route_find_expanded_group(tp->expand_gid, tp->name, US"transport", gidp, - &(addr->message))) + &addr->message)) { common_error(FALSE, addr, ERRNO_GIDFAIL, NULL); return FALSE; @@ -1885,6 +1886,7 @@ it does not provide a passwd value from which a gid can be taken. */ else if (tp->expand_uid) { struct passwd *pw; + GET_OPTION("user"); if (!route_find_expanded_user(tp->expand_uid, tp->name, US"transport", &pw, uidp, &(addr->message))) { @@ -1988,6 +1990,7 @@ check_message_size(transport_instance *tp, address_item *addr) int rc = OK; int size_limit; +GET_OPTION("message_size_limit"); deliver_set_expansions(addr); size_limit = expand_string_integer(tp->message_size_limit, TRUE); deliver_set_expansions(NULL); @@ -2150,6 +2153,7 @@ if(addr->prop.errors_address) else return_path = sender_address; +GET_OPTION("return_path"); if (tp->return_path) { uschar * new_return_path = expand_string(tp->return_path); @@ -2179,6 +2183,7 @@ if (!findugid(addr, tp, &uid, &gid, &use_initgroups)) return; home directory set in the address may already be expanded; a flag is set to indicate that. In other cases we must expand it. */ +GET_OPTION("home_directory"); if ( (deliver_home = tp->home_dir) /* Set in transport, or */ || ( (deliver_home = addr->home_dir) /* Set in address and */ && !testflag(addr, af_home_expanded) /* not expanded */ @@ -2208,6 +2213,7 @@ all users have access. It is necessary to be in a visible directory for some operating systems when running pipes, as some commands (e.g. "rm" under Solaris 2.5) require this. */ +GET_OPTION("current_directory"); working_directory = tp->current_dir ? tp->current_dir : addr->current_dir; if (working_directory) { @@ -2605,36 +2611,40 @@ if ((status & 0xffff) != 0) /* If SPECIAL_WARN is set in the top address, send a warning message. */ -if (addr->special_action == SPECIAL_WARN && addr->transport->warn_message) +if (addr->special_action == SPECIAL_WARN) { - int fd; - uschar *warn_message; - pid_t pid; + uschar * warn_message = addr->transport->warn_message; + GET_OPTION("quota_warn_message"); + if (warn_message) + { + int fd; + pid_t pid; - DEBUG(D_deliver) debug_printf("Warning message requested by transport\n"); + DEBUG(D_deliver) debug_printf("Warning message requested by transport\n"); - if (!(warn_message = expand_string(addr->transport->warn_message))) - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand \"%s\" (warning " - "message for %s transport): %s", addr->transport->warn_message, - addr->transport->name, expand_string_message); + if (!(warn_message = expand_string(warn_message))) + log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand \"%s\" (warning " + "message for %s transport): %s", addr->transport->warn_message, + addr->transport->name, expand_string_message); - else if ((pid = child_open_exim(&fd, US"tpt-warning-message")) > 0) - { - FILE *f = fdopen(fd, "wb"); - if (errors_reply_to && !contains_header(US"Reply-To", warn_message)) - fprintf(f, "Reply-To: %s\n", errors_reply_to); - fprintf(f, "Auto-Submitted: auto-replied\n"); - if (!contains_header(US"From", warn_message)) - moan_write_from(f); - fprintf(f, "%s", CS warn_message); + else if ((pid = child_open_exim(&fd, US"tpt-warning-message")) > 0) + { + FILE * f = fdopen(fd, "wb"); + if (errors_reply_to && !contains_header(US"Reply-To", warn_message)) + fprintf(f, "Reply-To: %s\n", errors_reply_to); + fprintf(f, "Auto-Submitted: auto-replied\n"); + if (!contains_header(US"From", warn_message)) + moan_write_from(f); + fprintf(f, "%s", CS warn_message); - /* Close and wait for child process to complete, without a timeout. */ + /* Close and wait for child process to complete, without a timeout. */ - (void)fclose(f); - (void)child_close(pid, 0); - } + (void)fclose(f); + (void)child_close(pid, 0); + } - addr->special_action = SPECIAL_NONE; + addr->special_action = SPECIAL_NONE; + } } } @@ -2650,6 +2660,7 @@ tpt_parallel_check(transport_instance * tp, address_item * addr, uschar ** key) { unsigned max_parallel; +GET_OPTION("max_parallel"); if (!tp->max_parallel) return FALSE; max_parallel = (unsigned) expand_string_integer(tp->max_parallel, TRUE); @@ -2773,6 +2784,7 @@ while (addr_local) /* Expand the batch_id string for comparison with other addresses. Expansion failure suppresses batching. */ + GET_OPTION("batch_id"); if (tp->batch_id) { deliver_set_expansions(addr); @@ -2827,11 +2839,12 @@ while (addr_local) if (ok && batch_id) { - uschar *bid; - address_item *save_nextnext = next->next; + uschar * bid; + address_item * save_nextnext = next->next; next->next = NULL; /* Expansion for a single address */ deliver_set_expansions(next); next->next = save_nextnext; + GET_OPTION("batch_id"); bid = expand_string(tp->batch_id); deliver_set_expansions(NULL); if (!bid) @@ -4454,9 +4467,10 @@ nonmatch domains else return_path = sender_address; + GET_OPTION("return_path"); if (tp->return_path) { - uschar *new_return_path = expand_string(tp->return_path); + uschar * new_return_path = expand_string(tp->return_path); if (new_return_path) return_path = new_return_path; else if (!f.expand_string_forcedfail) @@ -5557,18 +5571,18 @@ return actual_time; static FILE * expand_open(const uschar * filename, - const uschar * varname, const uschar * reason) + const uschar * optname, const uschar * reason) { const uschar * s = expand_cstring(filename); FILE * fp = NULL; if (!s || !*s) log_write(0, LOG_MAIN|LOG_PANIC, - "Failed to expand %s: '%s'\n", varname, filename); + "Failed to expand %s: '%s'\n", optname, filename); else if (*s != '/' || is_tainted(s)) log_write(0, LOG_MAIN|LOG_PANIC, "%s is not %s after expansion: '%s'\n", - varname, *s == '/' ? "untainted" : "absolute", s); + optname, *s == '/' ? "untainted" : "absolute", s); else if (!(fp = Ufopen(s, "rb"))) log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for %s " "message texts: %s", s, reason, strerror(errno)); @@ -5699,6 +5713,7 @@ else /* Open a template file if one is provided. Log failure to open, but carry on - default texts will be used. */ + GET_OPTION("bounce_message_file"); if (bounce_message_file) emf = expand_open(bounce_message_file, US"bounce_message_file", US"error"); @@ -6058,6 +6073,7 @@ transport_ctx tctx = {{0}}; if (pid <= 0) return FALSE; +GET_OPTION("warn_message_file"); if (warn_message_file) wmf = expand_open(warn_message_file, US"warn_message_file", US"warning"); @@ -6757,6 +6773,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) /* Any error in the filter file causes a delivery to be abandoned. */ + GET_OPTION("system_filter"); redirect.string = system_filter; redirect.isfile = TRUE; redirect.check_owner = redirect.check_group = FALSE; @@ -6936,12 +6953,14 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) if (p->address[0] == '|') { type = US"pipe"; + GET_OPTION("system_filter_pipe_transport"); tpname = system_filter_pipe_transport; address_pipe = p->address; } else if (p->address[0] == '>') { type = US"reply"; + GET_OPTION("system_filter_reply_transport"); tpname = system_filter_reply_transport; } else @@ -6949,11 +6968,13 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) if (p->address[Ustrlen(p->address)-1] == '/') { type = US"directory"; + GET_OPTION("system_filter_directory_transport"); tpname = system_filter_directory_transport; } else { type = US"file"; + GET_OPTION("system_filter_file_transport"); tpname = system_filter_file_transport; } address_file = p->address; @@ -8437,54 +8458,57 @@ else if (addr_defer != (address_item *)(+1)) || addr_defer->dsn_flags & rf_notify_delay ) && delay_warning[1] > 0 - && sender_address[0] != 0 - && ( !delay_warning_condition - || expand_check_condition(delay_warning_condition, - US"delay_warning", US"option") - ) - ) + && sender_address[0] != 0) { - int count; - int show_time; - int queue_time = time(NULL) - received_time.tv_sec; - - queue_time = test_harness_fudged_queue_time(queue_time); - - /* See how many warnings we should have sent by now */ + GET_OPTION("delay_warning_condition"); + if ( ( !delay_warning_condition + || expand_check_condition(delay_warning_condition, + US"delay_warning", US"option") + ) + ) + { + int count; + int show_time; + int queue_time = time(NULL) - received_time.tv_sec; - for (count = 0; count < delay_warning[1]; count++) - if (queue_time < delay_warning[count+2]) break; + queue_time = test_harness_fudged_queue_time(queue_time); - show_time = delay_warning[count+1]; + /* See how many warnings we should have sent by now */ - if (count >= delay_warning[1]) - { - int extra; - int last_gap = show_time; - if (count > 1) last_gap -= delay_warning[count]; - extra = (queue_time - delay_warning[count+1])/last_gap; - show_time += last_gap * extra; - count += extra; - } + for (count = 0; count < delay_warning[1]; count++) + if (queue_time < delay_warning[count+2]) break; - DEBUG(D_deliver) - { - debug_printf("time on queue = %s id %s addr %s\n", - readconf_printtime(queue_time), message_id, addr_defer->address); - debug_printf("warning counts: required %d done %d\n", count, - warning_count); - } + show_time = delay_warning[count+1]; - /* We have computed the number of warnings there should have been by now. - If there haven't been enough, send one, and up the count to what it should - have been. */ + if (count >= delay_warning[1]) + { + int extra; + int last_gap = show_time; + if (count > 1) last_gap -= delay_warning[count]; + extra = (queue_time - delay_warning[count+1])/last_gap; + show_time += last_gap * extra; + count += extra; + } - if (warning_count < count) - if (send_warning_message(recipients, queue_time, show_time)) + DEBUG(D_deliver) { - warning_count = count; - update_spool = TRUE; /* Ensure spool rewritten */ + debug_printf("time on queue = %s id %s addr %s\n", + readconf_printtime(queue_time), message_id, addr_defer->address); + debug_printf("warning counts: required %d done %d\n", count, + warning_count); } + + /* We have computed the number of warnings there should have been by now. + If there haven't been enough, send one, and up the count to what it should + have been. */ + + if (warning_count < count) + if (send_warning_message(recipients, queue_time, show_time)) + { + warning_count = count; + update_spool = TRUE; /* Ensure spool rewritten */ + } + } } /* Clear deliver_domain */ diff --git a/src/src/dkim.c b/src/src/dkim.c index 63b16af39..9e76c51a0 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -624,6 +624,7 @@ if (dkim->dot_stuffed) store_pool = POOL_MAIN; +GET_OPTION("dkim_domain"); if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s))) /* expansion error, do not send message. */ { errwhen = US"dkim_domain"; goto expand_bad; } @@ -652,6 +653,7 @@ if (dkim_domain) /* Set $dkim_selector expansion variable to each selector in list, for this domain. */ + GET_OPTION("dkim_selector"); if (!(dkim_sel = expand_string(dkim->dkim_selector))) { errwhen = US"dkim_selector"; goto expand_bad; } @@ -669,6 +671,7 @@ if (dkim_domain) /* Get canonicalization to use */ + GET_OPTION("dkim_canon"); dkim_canon_expanded = dkim->dkim_canon ? expand_string(dkim->dkim_canon) : US"relaxed"; if (!dkim_canon_expanded) /* expansion error, do not send message. */ @@ -686,6 +689,7 @@ if (dkim_domain) pdkim_canon = PDKIM_CANON_RELAXED; } + GET_OPTION("dkim_sign_headers"); if ( dkim->dkim_sign_headers && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers))) { errwhen = US"dkim_sign_header"; goto expand_bad; } @@ -693,6 +697,7 @@ if (dkim_domain) /* Get private key to use. */ + GET_OPTION("dkim_private_key"); if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key))) { errwhen = US"dkim_private_key"; goto expand_bad; } @@ -707,15 +712,18 @@ if (dkim_domain) expand_file_big_buffer(dkim_private_key_expanded))) goto bad; + GET_OPTION("dkim_hash"); if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash))) { errwhen = US"dkim_hash"; goto expand_bad; } + GET_OPTION("dkim_identity"); if (dkim->dkim_identity) if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity))) { errwhen = US"dkim_identity"; goto expand_bad; } else if (!*dkim_identity_expanded) dkim_identity_expanded = NULL; + GET_OPTION("dkim_timestamps"); if (dkim->dkim_timestamps) if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps))) { errwhen = US"dkim_timestamps"; goto expand_bad; } diff --git a/src/src/dkim_transport.c b/src/src/dkim_transport.c index 38f849af6..8c8d9b41a 100644 --- a/src/src/dkim_transport.c +++ b/src/src/dkim_transport.c @@ -18,6 +18,7 @@ static BOOL dkt_sign_fail(struct ob_dkim * dkim, int * errp) { +GET_OPTION("dkim_strict"); if (dkim->dkim_strict) { uschar * dkim_strict_result = expand_string(dkim->dkim_strict); diff --git a/src/src/exim.c b/src/src/exim.c index 10fc98963..c591ee60c 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -5063,6 +5063,8 @@ for (i = 0;;) /* If a pattern for matching the gecos field was supplied, apply it and then expand the name string. */ + GET_OPTION("gecos_pattern"); + GET_OPTION("gecos_name"); if (gecos_pattern && gecos_name) { const pcre2_code *re; @@ -5108,6 +5110,7 @@ any setting of unknown_login overrides the actual name. */ if (!originator_login || f.running_in_test_harness) { + GET_OPTION("unknown_login"); if (unknown_login) { originator_login = expand_string(unknown_login); @@ -5407,17 +5410,18 @@ for hosts that want to play several parts at once. We need to ensure that it is set for host checking, and for receiving messages. */ smtp_active_hostname = primary_hostname; -if (raw_active_hostname != NULL) +GET_OPTION("smtp_active_hostname"); +if (raw_active_hostname) { - uschar *nah = expand_string(raw_active_hostname); - if (nah == NULL) + uschar * nah = expand_string(raw_active_hostname); + if (!nah) { if (!f.expand_string_forcedfail) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand \"%s\" " "(smtp_active_hostname): %s", raw_active_hostname, expand_string_message); } - else if (nah[0] != 0) smtp_active_hostname = nah; + else if (nah[0]) smtp_active_hostname = nah; } /* Handle host checking: this facility mocks up an incoming SMTP call from a @@ -5675,6 +5679,7 @@ if (smtp_input) else { + GET_OPTION("message_size_limit"); thismessage_size_limit = expand_string_integer(message_size_limit, TRUE); if (expand_string_message) if (thismessage_size_limit == -1) @@ -5767,14 +5772,18 @@ for (BOOL more = TRUE; more; ) the very end. The result of the ACL is ignored (as for other non-SMTP messages). It is run for its potential side effects. */ - if (smtp_batched_input && acl_not_smtp_start != NULL) - { - uschar *user_msg, *log_msg; - f.enable_dollar_recipients = TRUE; - (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start, - &user_msg, &log_msg); - f.enable_dollar_recipients = FALSE; - } + if (smtp_batched_input) + { + GET_OPTION("acl_not_smtp_start"); + if (acl_not_smtp_start) + { + uschar * user_msg, * log_msg; + f.enable_dollar_recipients = TRUE; + (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start, + &user_msg, &log_msg); + f.enable_dollar_recipients = FALSE; + } + } /* Now get the data for the message */ @@ -5928,9 +5937,10 @@ for (BOOL more = TRUE; more; ) ignored; rejecting here would just add complication, and it can just as well be done later. Allow $recipients to be visible in the ACL. */ + GET_OPTION("acl_not_smtp_start"); if (acl_not_smtp_start) { - uschar *user_msg, *log_msg; + uschar * user_msg, * log_msg; f.enable_dollar_recipients = TRUE; (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start, &user_msg, &log_msg); diff --git a/src/src/expand.c b/src/src/expand.c index f9813133d..6be5cca0e 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -8737,12 +8737,14 @@ Returns: OK value placed in rvalue */ int -exp_bool(address_item *addr, - uschar *mtype, uschar *mname, unsigned dbg_opt, - uschar *oname, BOOL bvalue, - uschar *svalue, BOOL *rvalue) +exp_bool(address_item * addr, + uschar * mtype, uschar * mname, unsigned dbg_opt, + uschar * oname, BOOL bvalue, + uschar * svalue, BOOL * rvalue) { -uschar *expanded; +uschar * expanded; + +DEBUG(D_expand) debug_printf("try option %s\n", oname); if (!svalue) { *rvalue = bvalue; return OK; } if (!(expanded = expand_string(svalue))) diff --git a/src/src/macros.h b/src/src/macros.h index 8aed335b5..902cdd165 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1190,4 +1190,8 @@ When doing en extended loop of matching, release store periodically. */ #define REGEX_LOOPCOUNT_STORE_RESET 1000 +/* Debug an option access. Use for non-list ones about to be expanded. */ +#define GET_OPTION(name) \ + DEBUG(D_expand) debug_printf("try option " name "\n"); + /* End of macros.h */ diff --git a/src/src/moan.c b/src/src/moan.c index a3c8e0aba..6fe82b29c 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -30,8 +30,9 @@ Returns: nothing void moan_write_from(FILE *f) { -uschar * s = expand_string(dsn_from); -if (!s) +uschar * s; +GET_OPTION("dsn_from"); +if (!(s = expand_string(dsn_from))) { log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand dsn_from (using default): %s", expand_string_message); @@ -175,6 +176,7 @@ uschar * s, * s2; /* For DMARC if there is a specific sender set, expand the variable for the header From: and grab the address from that for the envelope FROM. */ +GET_OPTION("dmarc_forensic_sender"); if ( ident == ERRMESS_DMARC_FORENSIC && dmarc_forensic_sender && (s = expand_string(dmarc_forensic_sender)) @@ -513,9 +515,12 @@ if (check_sender && message_file && f.trusted_caller && { uschar *new_sender = NULL; if (regex_match_and_setup(regex_From, big_buffer, 0, -1)) + { + GET_OPTION("uucp_from_sender"); new_sender = expand_string(uucp_from_sender); + } if (new_sender) sender_address = new_sender; - else firstline = big_buffer; + else firstline = big_buffer; } /* If viable sender address, send a message */ diff --git a/src/src/receive.c b/src/src/receive.c index 990b9c22e..abac05c56 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1574,6 +1574,7 @@ uschar * timestamp = expand_string(US"${tod_full}"); header_line * received_header= header_list; if (recipients_count == 1) received_for = recipients_list[0].address; +GET_OPTION("received_header_text"); received = expand_string(received_header_text); received_for = NULL; @@ -2201,8 +2202,9 @@ OVERSIZE: { if (!f.sender_address_forced) { - uschar *uucp_sender = expand_string(uucp_from_sender); - if (!uucp_sender) + uschar * uucp_sender; + GET_OPTION("uucp_from_sender"); + if (!(uucp_sender = expand_string(uucp_from_sender))) log_write(0, LOG_MAIN|LOG_PANIC, "expansion of \"%s\" failed after matching " "\"From \" line: %s", uucp_from_sender, expand_string_message); @@ -2821,6 +2823,7 @@ if ( !msgid_header /* Permit only letters, digits, dots, and hyphens in the domain */ + GET_OPTION("message_id_header_domain"); if (message_id_domain) { uschar *new_id_domain = expand_string(message_id_domain); @@ -2842,6 +2845,7 @@ if ( !msgid_header /* Permit all characters except controls and RFC 2822 specials in the additional text part. */ + GET_OPTION("message_id_header_text"); if (message_id_text) { uschar *new_id_text = expand_string(message_id_text); @@ -3517,6 +3521,7 @@ else dkim_exim_verify_finish(); /* Check if we must run the DKIM ACL */ + GET_OPTION("acl_smtp_dkim"); if (acl_smtp_dkim && dkim_verify_signers && *dkim_verify_signers) { uschar * dkim_verify_signers_expanded = @@ -3606,11 +3611,14 @@ else #endif /* DISABLE_DKIM */ #ifdef WITH_CONTENT_SCAN - if ( recipients_count > 0 - && acl_smtp_mime - && !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by) - ) - goto TIDYUP; + if (recipients_count > 0) + { + GET_OPTION("acl_smtp_mime"); + if (acl_smtp_mime + && !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by) + ) + goto TIDYUP; + } #endif /* WITH_CONTENT_SCAN */ #ifdef SUPPORT_DMARC @@ -3618,67 +3626,73 @@ else #endif #ifndef DISABLE_PRDR - if (prdr_requested && recipients_count > 1 && acl_smtp_data_prdr) + if (prdr_requested && recipients_count > 1) { - int all_pass = OK; - int all_fail = FAIL; + GET_OPTION("acl_smtp_data_prdr"); + if (acl_smtp_data_prdr) + { + int all_pass = OK; + int all_fail = FAIL; - smtp_printf("353 PRDR content analysis beginning\r\n", SP_MORE); - /* Loop through recipients, responses must be in same order received */ - for (unsigned int c = 0; recipients_count > c; c++) - { - const uschar * addr = recipients_list[c].address; - uschar * msg= US"PRDR R=<%s> %s"; - uschar * code; - DEBUG(D_receive) - debug_printf("PRDR processing recipient %s (%d of %d)\n", - addr, c+1, recipients_count); - rc = acl_check(ACL_WHERE_PRDR, addr, - acl_smtp_data_prdr, &user_msg, &log_msg); - - /* If any recipient rejected content, indicate it in final message */ - all_pass |= rc; - /* If all recipients rejected, indicate in final message */ - all_fail &= rc; - - switch (rc) - { - case OK: case DISCARD: code = US"250"; break; - case DEFER: code = US"450"; break; - default: code = US"550"; break; - } - if (user_msg != NULL) - smtp_user_msg(code, user_msg); - else + smtp_printf("353 PRDR content analysis beginning\r\n", SP_MORE); + /* Loop through recipients, responses must be in same order received */ + for (unsigned int c = 0; recipients_count > c; c++) { + const uschar * addr = recipients_list[c].address; + uschar * msg= US"PRDR R=<%s> %s"; + uschar * code; + DEBUG(D_receive) + debug_printf("PRDR processing recipient %s (%d of %d)\n", + addr, c+1, recipients_count); + rc = acl_check(ACL_WHERE_PRDR, addr, + acl_smtp_data_prdr, &user_msg, &log_msg); + + /* If any recipient rejected content, indicate it in final message */ + all_pass |= rc; + /* If all recipients rejected, indicate in final message */ + all_fail &= rc; + switch (rc) - { - case OK: case DISCARD: - msg = string_sprintf(CS msg, addr, "acceptance"); break; - case DEFER: - msg = string_sprintf(CS msg, addr, "temporary refusal"); break; - default: - msg = string_sprintf(CS msg, addr, "refusal"); break; - } - smtp_user_msg(code, msg); - } - if (log_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, log_msg); - else if (user_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, user_msg); - else log_write(0, LOG_MAIN, "%s", CS msg); + { + case OK: case DISCARD: code = US"250"; break; + case DEFER: code = US"450"; break; + default: code = US"550"; break; + } + if (user_msg != NULL) + smtp_user_msg(code, user_msg); + else + { + switch (rc) + { + case OK: case DISCARD: + msg = string_sprintf(CS msg, addr, "acceptance"); break; + case DEFER: + msg = string_sprintf(CS msg, addr, "temporary refusal"); break; + default: + msg = string_sprintf(CS msg, addr, "refusal"); break; + } + smtp_user_msg(code, msg); + } + if (log_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, log_msg); + else if (user_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, user_msg); + else log_write(0, LOG_MAIN, "%s", CS msg); - if (rc != OK) { receive_remove_recipient(addr); c--; } - } - /* Set up final message, used if data acl gives OK */ - smtp_reply = string_sprintf("%s id=%s message %s", - all_fail == FAIL ? US"550" : US"250", - message_id, - all_fail == FAIL - ? US"rejected for all recipients" - : all_pass == OK - ? US"accepted" - : US"accepted for some recipients"); - if (recipients_count == 0) - goto NOT_ACCEPTED; + if (rc != OK) { receive_remove_recipient(addr); c--; } + } + /* Set up final message, used if data acl gives OK */ + smtp_reply = string_sprintf("%s id=%s message %s", + all_fail == FAIL ? US"550" : US"250", + message_id, + all_fail == FAIL + ? US"rejected for all recipients" + : all_pass == OK + ? US"accepted" + : US"accepted for some recipients"); + if (recipients_count == 0) + goto NOT_ACCEPTED; + } + else + prdr_requested = FALSE; } else prdr_requested = FALSE; @@ -3687,6 +3701,7 @@ else /* Check the recipients count again, as the MIME ACL might have changed them. */ + GET_OPTION("acl_smtp_data"); if (acl_smtp_data && recipients_count > 0) { rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg); @@ -3724,6 +3739,7 @@ else { #ifdef WITH_CONTENT_SCAN + GET_OPTION("acl_not_smtp_mime"); if ( acl_not_smtp_mime && !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by) @@ -3731,9 +3747,10 @@ else goto TIDYUP; #endif /* WITH_CONTENT_SCAN */ + GET_OPTION("acl_not_smtp"); if (acl_not_smtp) { - uschar *user_msg, *log_msg; + uschar * user_msg, * log_msg; f.authentication_local = TRUE; rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg); if (rc == DISCARD) diff --git a/src/src/route.c b/src/src/route.c index 3401f15b4..0fdcdf2ed 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -616,7 +616,7 @@ uschar *check; if (!s) return OK; -DEBUG(D_route) debug_printf("checking require_files\n"); +DEBUG(D_route|D_expand) debug_printf("checking require_files\n"); listptr = s; while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) @@ -637,7 +637,7 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) /* Empty items are just skipped */ - if (*ss == 0) continue; + if (!*ss) continue; /* If there are no slashes in the string, we have a user name or uid, with optional group/gid. */ @@ -651,9 +651,9 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) /* If there's a comma, temporarily terminate the user name/number at that point. Then set the uid. */ - if (comma != NULL) *comma = 0; + if (comma) *comma = 0; ok = route_finduser(ss, &pw, &uid); - if (comma != NULL) *comma = ','; + if (comma) *comma = ','; if (!ok) { @@ -663,24 +663,22 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) /* If there was no comma, the gid is that associated with the user. */ - if (comma == NULL) - { - if (pw != NULL) gid = pw->pw_gid; else + if (!comma) + if (pw) + gid = pw->pw_gid; + else { *perror = string_sprintf("group missing after numerical uid %d for " "require_files", (int)uid); goto RETURN_DEFER; } - } else - { if (!route_findgroup(comma + 1, &gid)) { *perror = string_sprintf("group \"%s\" for require_files not found\n", comma + 1); goto RETURN_DEFER; } - } /* Note that we have values set, and proceed to next item */ @@ -974,6 +972,7 @@ check_local_user before any subsequent expansions are done. Otherwise, $home could mean different things for different options, which would be extremely confusing. */ +GET_OPTION("router_home_directory"); if (r->router_home_directory) { uschar * router_home = expand_string(r->router_home_directory); @@ -1018,7 +1017,8 @@ if ((rc = check_files(r->require_files, perror)) != OK) if (r->condition) { - DEBUG(D_route) debug_printf("checking \"condition\" \"%.80s\"...\n", r->condition); + DEBUG(D_route|D_expand) + debug_printf("checking \"condition\" \"%.80s\"...\n", r->condition); if (!expand_check_condition(r->condition, r->name, US"router")) { if (f.search_find_defer) @@ -1440,6 +1440,7 @@ const uschar * varlist = r->set; tree_node ** root = (tree_node **) &addr->prop.variables; int sep = ';'; +GET_OPTION("set"); if (!varlist) return OK; /* Walk the varlist, creating variables */ @@ -1474,6 +1475,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); ) /* Expand "more" if necessary; DEFER => an expansion failed */ + GET_OPTION("more"); yield = exp_bool(addr, US"router", r->name, D_route, US"more", r->more, r->expand_more, &more); if (yield != OK) return yield; @@ -1754,7 +1756,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) if (r->address_data) { - DEBUG(D_route) debug_printf("processing address_data\n"); + DEBUG(D_route|D_expand) debug_printf("processing address_data\n"); if (!(deliver_address_data = expand_string(r->address_data))) { if (f.expand_string_forcedfail) @@ -1764,6 +1766,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) /* Expand "more" if necessary; DEFER => an expansion failed */ + GET_OPTION("more"); yield = exp_bool(addr, US"router", r->name, D_route, US"more", r->more, r->expand_more, &more); if (yield != OK) goto ROUTE_EXIT; @@ -1872,6 +1875,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) { /* Expand "more" if necessary */ + GET_OPTION("more"); yield = exp_bool(addr, US"router", r->name, D_route, US"more", r->more, r->expand_more, &more); if (yield != OK) goto ROUTE_EXIT; @@ -1897,18 +1901,21 @@ if (!r) HDEBUG(D_route) debug_printf("no more routers\n"); if (!addr->message) { - uschar *message = US"Unrouteable address"; - if (addr->router && addr->router->cannot_route_message) + uschar * message = US"Unrouteable address"; + if (addr->router) { - uschar *expmessage = expand_string(addr->router->cannot_route_message); - if (!expmessage) - { - if (!f.expand_string_forcedfail) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand " - "cannot_route_message in %s router: %s", addr->router->name, - expand_string_message); - } - else message = expmessage; + uschar * s = addr->router->cannot_route_message; + GET_OPTION("cannot_route_message"); + if (s) + { + if ((s = expand_string(s))) + message = s; + else + if (!f.expand_string_forcedfail) + log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand " + "cannot_route_message in %s router: %s", addr->router->name, + expand_string_message); + } } addr->user_message = addr->message = message; } @@ -1950,6 +1957,7 @@ networking, so it is included in the binary only if requested. */ #ifdef SUPPORT_TRANSLATE_IP_ADDRESS +GET_OPTION("translate_ip_address"); if (r->translate_ip_address) { int rc; @@ -2008,6 +2016,7 @@ if (r->translate_ip_address) /* See if this is an unseen routing; first expand the option if necessary. DEFER can be given if the expansion fails */ +GET_OPTION("unseen"); yield = exp_bool(addr, US"router", r->name, D_route, US"unseen", r->unseen, r->expand_unseen, &unseen); if (yield != OK) goto ROUTE_EXIT; diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c index d27757c7e..671e8c93f 100644 --- a/src/src/routers/dnslookup.c +++ b/src/src/routers/dnslookup.c @@ -151,14 +151,11 @@ host_item h; int rc; int widen_sep = 0; int whichrrs = HOST_FIND_BY_MX | HOST_FIND_BY_A | HOST_FIND_BY_AAAA; -dnslookup_router_options_block *ob = +dnslookup_router_options_block * ob = (dnslookup_router_options_block *)(rblock->options_block); -uschar *srv_service = NULL; -uschar *widen = NULL; -const uschar *pre_widen = addr->domain; -const uschar *post_widen = NULL; -const uschar *fully_qualified_name; -const uschar *listptr; +uschar * srv_service = NULL, * widen = NULL; +const uschar * pre_widen = addr->domain, * post_widen = NULL; +const uschar * fully_qualified_name, * listptr; uschar widen_buffer[256]; DEBUG(D_route) @@ -167,8 +164,8 @@ DEBUG(D_route) /* If an SRV check is required, expand the service name */ +GET_OPTION("check_srv"); if (ob->check_srv) - { if ( !(srv_service = expand_string(ob->check_srv)) && !f.expand_string_forcedfail) { @@ -176,8 +173,8 @@ if (ob->check_srv) rblock->name, ob->check_srv, expand_string_message); return DEFER; } - else whichrrs |= HOST_FIND_BY_SRV; - } + else + whichrrs |= HOST_FIND_BY_SRV; /* Set up the first of any widening domains. The code further down copes with either pre- or post-widening, but at present there is no way to turn on diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c index a6dc0fc87..f9966bcc0 100644 --- a/src/src/routers/iplookup.c +++ b/src/src/routers/iplookup.c @@ -178,19 +178,17 @@ reply = store_get(256, GET_TAINTED); /* Build the query string to send. If not explicitly given, a default of "user@domain user@domain" is used. */ -if (ob->query == NULL) +GET_OPTION("query"); +if (!ob->query) query = string_sprintf("%s@%s %s@%s", addr->local_part, addr->domain, addr->local_part, addr->domain); else - { - query = expand_string(ob->query); - if (query == NULL) + if (!(query = expand_string(ob->query))) { addr->message = string_sprintf("%s router: failed to expand %s: %s", rblock->name, ob->query, expand_string_message); return DEFER; } - } query_len = Ustrlen(query); DEBUG(D_route) debug_printf("%s router query is \"%s\"\n", rblock->name, @@ -362,23 +360,24 @@ else /* If an explicit rerouting string is specified, expand it. Otherwise, use what was sent back verbatim. */ -if (ob->reroute != NULL) +GET_OPTION("reroute"); +if (ob->reroute) { reroute = expand_string(ob->reroute); expand_nmax = -1; - if (reroute == NULL) + if (!reroute) { addr->message = string_sprintf("%s router: failed to expand %s: %s", rblock->name, ob->reroute, expand_string_message); return DEFER; } } -else reroute = reply; +else + reroute = reply; /* We should now have a new address in the form user@domain. */ -domain = Ustrchr(reroute, '@'); -if (domain == NULL) +if (!(domain = Ustrchr(reroute, '@'))) { log_write(0, LOG_MAIN, "%s router: reroute string %s is not of the form " "user@domain", rblock->name, reroute); diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c index 160c866b9..200e0206e 100644 --- a/src/src/routers/manualroute.c +++ b/src/src/routers/manualroute.c @@ -118,8 +118,8 @@ if (ob->hai_code < 0) /* One of route_list or route_data must be specified */ -if ((ob->route_list == NULL && ob->route_data == NULL) || - (ob->route_list != NULL && ob->route_data != NULL)) +if ( !ob->route_list && !ob->route_data + || ob->route_list && ob->route_data) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n " "route_list or route_data (but not both) must be specified", rblock->name); @@ -291,6 +291,7 @@ string, decline. */ else { + GET_OPTION("route_data"); if (!(route_item = rf_expand_data(addr, ob->route_data, &rc))) return rc; (void) parse_route_item(route_item, NULL, &hostlist, &options); diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index 2a6a73eb6..dd5e24b93 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -287,6 +287,7 @@ if (curr_uid != root_uid && (uid != curr_uid || gid != curr_gid)) /* Set up the command to run */ +GET_OPTION("command"); if (!transport_set_up_command(&argvptr, /* anchor for arg list */ ob->command, /* raw command */ TSUC_EXPAND_ARGS, /* arguments expanded but must not be tainted */ diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 4c8e30563..6b27c82b0 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -370,12 +370,11 @@ while (generated) in \N...\N to avoid expansion later. In Cygwin, home directories can contain $ characters. */ - if (rblock->home_directory != NULL) + if (rblock->home_directory) next->home_dir = rblock->home_directory; else if (rblock->check_local_user) next->home_dir = string_sprintf("\\N%s\\N", pw->pw_dir); - else if (rblock->router_home_directory != NULL && - testflag(addr, af_home_expanded)) + else if (rblock->router_home_directory && testflag(addr, af_home_expanded)) { next->home_dir = deliver_home; setflag(next, af_home_expanded); @@ -395,6 +394,7 @@ while (generated) if (next->address[0] == '|') { address_pipe = next->address; + GET_OPTION("pipe_transport"); if (rf_get_transport(ob->pipe_transport_name, &ob->pipe_transport, next, rblock->name, US"pipe_transport")) next->transport = ob->pipe_transport; @@ -402,6 +402,7 @@ while (generated) } else if (next->address[0] == '>') { + GET_OPTION("reply_transport"); if (rf_get_transport(ob->reply_transport_name, &ob->reply_transport, next, rblock->name, US"reply_transport")) next->transport = ob->reply_transport; @@ -412,15 +413,19 @@ while (generated) address_file = next->address; if (next->address[len-1] == '/') { + GET_OPTION("directory_transport"); if (rf_get_transport(ob->directory_transport_name, &(ob->directory_transport), next, rblock->name, US"directory_transport")) next->transport = ob->directory_transport; } else + { + GET_OPTION("file_transport"); if (rf_get_transport(ob->file_transport_name, &ob->file_transport, next, rblock->name, US"file_transport")) next->transport = ob->file_transport; + } address_file = NULL; } @@ -566,11 +571,15 @@ address. Otherwise, if a local qualify_domain is provided, set that up. */ if (ob->qualify_preserve_domain) qualify_domain_recipient = addr->domain; -else if (ob->qualify_domain) +else { - uschar *new_qdr = rf_expand_data(addr, ob->qualify_domain, &xrc); - if (!new_qdr) return xrc; - qualify_domain_recipient = new_qdr; + GET_OPTION("qualify_domain"); + if (ob->qualify_domain) + { + uschar *new_qdr = rf_expand_data(addr, ob->qualify_domain, &xrc); + if (!new_qdr) return xrc; + qualify_domain_recipient = new_qdr; + } } redirect.owners = ob->owners; diff --git a/src/src/routers/rf_expand_data.c b/src/src/routers/rf_expand_data.c index 9892567f0..6ba613215 100644 --- a/src/src/routers/rf_expand_data.c +++ b/src/src/routers/rf_expand_data.c @@ -31,7 +31,7 @@ uschar * rf_expand_data(address_item *addr, uschar *s, int *prc) { uschar *yield = expand_string(s); -if (yield != NULL) return yield; +if (yield) return yield; if (f.expand_string_forcedfail) { DEBUG(D_route) debug_printf("forced failure for expansion of \"%s\"\n", s); diff --git a/src/src/routers/rf_get_errors_address.c b/src/src/routers/rf_get_errors_address.c index 222d157d8..792b9b5f3 100644 --- a/src/src/routers/rf_get_errors_address.c +++ b/src/src/routers/rf_get_errors_address.c @@ -38,14 +38,13 @@ int rf_get_errors_address(address_item * addr, router_instance * rblock, int verify, const uschar ** errors_to) { -uschar *s; +uschar * s; *errors_to = addr->prop.errors_address; if (!rblock->errors_to) return OK; -s = expand_string(rblock->errors_to); - -if (s == NULL) +GET_OPTION("errors_to"); +if (!(s = expand_string(rblock->errors_to))) { if (f.expand_string_forcedfail) { @@ -60,7 +59,7 @@ if (s == NULL) /* If the errors_to address is empty, it means "ignore errors" */ -if (*s == 0) +if (!*s) { addr->prop.ignore_error = TRUE; /* For locally detected errors */ *errors_to = US""; /* Return path for SMTP */ diff --git a/src/src/routers/rf_get_transport.c b/src/src/routers/rf_get_transport.c index d54e3c296..d37966865 100644 --- a/src/src/routers/rf_get_transport.c +++ b/src/src/routers/rf_get_transport.c @@ -47,6 +47,7 @@ rf_get_transport(uschar *tpname, transport_instance **tpptr, address_item *addr, uschar *ss; BOOL expandable; +GET_OPTION("transport"); if (!tpname) { if (!require_name) return TRUE; diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 2d977b975..ff768e94c 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -2172,6 +2172,7 @@ lwr_receive_ungetc = NULL; /* Set up the message size limit; this may be host-specific */ +GET_OPTION("message_size_limit"); thismessage_size_limit = expand_string_integer(message_size_limit, TRUE); if (expand_string_message) { @@ -2569,6 +2570,7 @@ if (proxy_protocol_host()) /* Run the connect ACL if it exists */ user_msg = NULL; +GET_OPTION("acl_smtp_connect"); if (acl_smtp_connect) { int rc; @@ -2615,16 +2617,20 @@ if (user_msg) esclen = codelen - 4; } } -else if (!(s = expand_string(smtp_banner))) +else { - log_write(0, f.expand_string_forcedfail ? LOG_MAIN : LOG_MAIN|LOG_PANIC_DIE, - "Expansion of \"%s\" (smtp_banner) failed: %s", - smtp_banner, expand_string_message); - /* for force-fail */ -#ifndef DISABLE_TLS - if (tls_in.on_connect) tls_close(NULL, TLS_SHUTDOWN_WAIT); -#endif - return FALSE; + GET_OPTION("smtp_banner"); + if (!(s = expand_string(smtp_banner))) + { + log_write(0, f.expand_string_forcedfail ? LOG_MAIN : LOG_MAIN|LOG_PANIC_DIE, + "Expansion of \"%s\" (smtp_banner) failed: %s", + smtp_banner, expand_string_message); + /* for force-fail */ + #ifndef DISABLE_TLS + if (tls_in.on_connect) tls_close(NULL, TLS_SHUTDOWN_WAIT); + #endif + return FALSE; + } } /* Remove any terminating newlines; might as well remove trailing space too */ @@ -3185,6 +3191,7 @@ fl.smtp_exit_function_called = TRUE; /* Call the not-QUIT ACL, if there is one, unless no reason is given. */ +GET_OPTION("acl_smtp_notquit"); if (acl_smtp_notquit && reason) { smtp_notquit_reason = reason; @@ -3521,6 +3528,7 @@ smtp_quit_handler(uschar ** user_msgp, uschar ** log_msgp) HAD(SCH_QUIT); f.smtp_in_quit = TRUE; incomplete_transaction_log(US"QUIT"); +GET_OPTION("acl_smtp_quit"); if ( acl_smtp_quit && acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp) == ERROR) @@ -3694,6 +3702,7 @@ while (done <= 0) for (auth_instance * au = auths; au; au = au->next) if (strcmpic(US"tls", au->driver_name) == 0) { + GET_OPTION("acl_smtp_auth"); if ( acl_smtp_auth && (rc = acl_check(ACL_WHERE_AUTH, NULL, acl_smtp_auth, &user_msg, &log_msg)) != OK @@ -3772,6 +3781,7 @@ while (done <= 0) /* Check the ACL */ + GET_OPTION("acl_smtp_auth"); if ( acl_smtp_auth && (rc = acl_check(ACL_WHERE_AUTH, NULL, acl_smtp_auth, &user_msg, &log_msg)) != OK @@ -3966,6 +3976,7 @@ while (done <= 0) /* Apply an ACL check if one is defined; afterwards, recheck synchronization in case the client started sending in a delay. */ + GET_OPTION("acl_smtp_helo"); if (acl_smtp_helo) if ((rc = acl_check(ACL_WHERE_HELO, NULL, acl_smtp_helo, &user_msg, &log_msg)) != OK) @@ -4097,16 +4108,19 @@ while (done <= 0) /* Advertise ETRN/VRFY/EXPN if there's are ACL checking whether a host is permitted to issue them; a check is made when any host actually tries. */ + GET_OPTION("acl_smtp_etrn"); if (acl_smtp_etrn) { g = string_catn(g, smtp_code, 3); g = string_catn(g, US"-ETRN\r\n", 7); } + GET_OPTION("acl_smtp_vrfy"); if (acl_smtp_vrfy) { g = string_catn(g, smtp_code, 3); g = string_catn(g, US"-VRFY\r\n", 7); } + GET_OPTION("acl_smtp_expn"); if (acl_smtp_expn) { g = string_catn(g, smtp_code, 3); @@ -4502,6 +4516,7 @@ while (done <= 0) US"invalid data for AUTH"); goto COMMAND_LOOP; } + GET_OPTION("acl_smtp_mailauth"); if (!acl_smtp_mailauth) { ignore_msg = US"client not authenticated"; @@ -4698,6 +4713,7 @@ while (done <= 0) when pipelining is not advertised, do another sync check in case the ACL delayed and the client started sending in the meantime. */ + GET_OPTION("acl_smtp_mail"); if (acl_smtp_mail) { rc = acl_check(ACL_WHERE_MAIL, NULL, acl_smtp_mail, &user_msg, &log_msg); @@ -4953,10 +4969,13 @@ while (done <= 0) if (f.recipients_discarded) rc = DISCARD; else + { + GET_OPTION("acl_smtp_rcpt"); if ( (rc = acl_check(ACL_WHERE_RCPT, recipient, acl_smtp_rcpt, &user_msg, &log_msg)) == OK && !f.smtp_in_pipelining_advertised && !check_sync()) goto SYNC_FAILURE; + } /* The ACL was happy */ @@ -5119,6 +5138,7 @@ while (done <= 0) since the ACL may have delayed. To handle cutthrough delivery enforce a dummy call to get the DATA command sent. */ + GET_OPTION("acl_smtp_predata"); if (!acl_smtp_predata && cutthrough.cctx.sock < 0) rc = OK; else @@ -5177,6 +5197,7 @@ while (done <= 0) US"verify"))) break; + GET_OPTION("acl_smtp_vrfy"); if ((rc = acl_check(ACL_WHERE_VRFY, address, acl_smtp_vrfy, &user_msg, &log_msg)) != OK) done = smtp_handle_acl_fail(ACL_WHERE_VRFY, rc, user_msg, log_msg); @@ -5215,6 +5236,7 @@ while (done <= 0) case EXPN_CMD: HAD(SCH_EXPN); + GET_OPTION("acl_smtp_expn"); rc = acl_check(ACL_WHERE_EXPN, NULL, acl_smtp_expn, &user_msg, &log_msg); if (rc != OK) done = smtp_handle_acl_fail(ACL_WHERE_EXPN, rc, user_msg, log_msg); @@ -5244,6 +5266,7 @@ while (done <= 0) /* Apply an ACL check if one is defined */ + GET_OPTION("acl_smtp_starttls"); if ( acl_smtp_starttls && (rc = acl_check(ACL_WHERE_STARTTLS, NULL, acl_smtp_starttls, &user_msg, &log_msg)) != OK @@ -5362,6 +5385,7 @@ while (done <= 0) case QUIT_CMD: f.smtp_in_quit = TRUE; user_msg = NULL; + GET_OPTION("acl_smtp_quit"); if ( acl_smtp_quit && ((rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg, &log_msg)) == ERROR)) @@ -5481,6 +5505,7 @@ while (done <= 0) log_write(L_etrn, LOG_MAIN, "ETRN %s received from %s", smtp_cmd_argument, host_and_ident(FALSE)); + GET_OPTION("acl_smtp_etrn"); if ((rc = acl_check(ACL_WHERE_ETRN, NULL, acl_smtp_etrn, &user_msg, &log_msg)) != OK) { @@ -5497,6 +5522,7 @@ while (done <= 0) since that is strictly the only kind of ETRN that can be implemented according to the RFC. */ + GET_OPTION("smtp_etrn_command"); if (smtp_etrn_command) { uschar *error; diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 62557072e..895b594fc 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -278,6 +278,7 @@ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on))) /* Set DSCP value, if we can. For now, if we fail to set the value, we don't bomb out, just log it and continue in default traffic class. */ +GET_OPTION("dscp"); if (dscp && dscp_lookup(dscp, sc->host_af, &dscp_level, &dscp_option, &dscp_value)) { HDEBUG(D_transport|D_acl|D_v) diff --git a/src/src/spf.c b/src/src/spf.c index 2e3f861eb..cc36463e4 100644 --- a/src/src/spf.c +++ b/src/src/spf.c @@ -253,10 +253,13 @@ if (!(spf_server = SPF_server_new_dns(dc, debug))) DEBUG(D_receive) debug_printf("spf: SPF_server_new() failed.\n"); return FALSE; } - /* Override the outdated explanation URL. - See https://www.mail-archive.com/mailop@mailop.org/msg08019.html - Used to work as "Please%_see%_http://www.open-spf.org/Why?id=%{S}&ip=%{C}&receiver=%{R}", - but is broken now (May 18th, 2020) */ + +/* Override the outdated explanation URL. +See https://www.mail-archive.com/mailop@mailop.org/msg08019.html +Used to work as "Please%_see%_http://www.open-spf.org/Why?id=%{S}&ip=%{C}&receiver=%{R}", +but is broken now (May 18th, 2020) */ + +GET_OPTION("spf_smtp_comment_template"); if (!(s = expand_string(spf_smtp_comment_template))) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "expansion of spf_smtp_comment_template failed"); diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index ce52cc6ff..72c96f0d0 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -178,18 +178,24 @@ static int appendfile_transport_setup(transport_instance *tblock, address_item *addrlist, transport_feedback *dummy, uid_t uid, gid_t gid, uschar **errmsg) { -appendfile_transport_options_block *ob = +appendfile_transport_options_block * ob = (appendfile_transport_options_block *)(tblock->options_block); -uschar *q = ob->quota; +uschar * q; double default_value = 0.0; if (ob->expand_maildir_use_size_file) - ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, + { + GET_OPTION("maildir_use_size_file"); + ob->maildir_use_size_file = + expand_check_condition(ob->expand_maildir_use_size_file, US"`maildir_use_size_file` in transport", tblock->name); + } /* Loop for quota, quota_filecount, quota_warn_threshold, mailbox_size, mailbox_filecount */ +GET_OPTION("quota"); +q = ob->quota; for (int i = 0; i < 5; i++) { double d = default_value; @@ -258,6 +264,7 @@ for (int i = 0; i < 5; i++) which = US"quota"; ob->quota_value = (off_t)d; ob->quota_no_check = no_check; + GET_OPTION("quota_filecount"); q = ob->quota_filecount; break; @@ -266,6 +273,7 @@ for (int i = 0; i < 5; i++) which = US"quota_filecount"; ob->quota_filecount_value = (int)d; ob->quota_filecount_no_check = no_check; + GET_OPTION("quota_warn_threshold"); q = ob->quota_warn_threshold; break; @@ -273,6 +281,7 @@ for (int i = 0; i < 5; i++) if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4) which = US"quota_warn_threshold"; ob->quota_warn_threshold_value = (off_t)d; + GET_OPTION("mailbox_size"); q = ob->mailbox_size_string; default_value = -1.0; break; @@ -281,6 +290,7 @@ for (int i = 0; i < 5; i++) if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4) which = US"mailbox_size";; ob->mailbox_size_value = (off_t)d; + GET_OPTION("mailbox_filecount"); q = ob->mailbox_filecount_string; break; @@ -399,10 +409,10 @@ if (ob->dirname) if (ob->maildir_format && ob->mailstore_format) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " "only one of maildir and mailstore may be specified", tblock->name); - if (ob->quota_filecount != NULL && ob->quota == NULL) + if (ob->quota_filecount != NULL && !ob->quota) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " "quota must be set if quota_filecount is set", tblock->name); - if (ob->quota_directory != NULL && ob->quota == NULL) + if (ob->quota_directory != NULL && !ob->quota) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s transport:\n " "quota must be set if quota_directory is set", tblock->name); } @@ -1221,6 +1231,7 @@ if (!fdname) { if (!(fdname = ob->filename)) { + GET_OPTION("directory"); fdname = ob->dirname; isdirectory = TRUE; } @@ -2234,6 +2245,7 @@ else /* Use an explicitly configured directory if set */ + GET_OPTION("quota_directory"); if (ob->quota_directory) { if (!(check_path = expand_string(ob->quota_directory))) @@ -2431,6 +2443,7 @@ else DEBUG(D_transport) debug_printf("delivering in maildir format in %s\n", path); + GET_OPTION("maildir_tag"); nametag = ob->maildir_tag; /* Check that nametag expands successfully; a hard failure causes a panic @@ -2567,9 +2580,10 @@ else /* Write the envelope file, then close it. */ + GET_OPTION("mailstore_prefix"); if (ob->mailstore_prefix) { - uschar *s = expand_string(ob->mailstore_prefix); + uschar * s = expand_string(ob->mailstore_prefix); if (!s) { if (!f.expand_string_forcedfail) @@ -2595,9 +2609,10 @@ else for (address_item * taddr = addr; taddr; taddr = taddr->next) fprintf(env_file, "%s@%s\n", taddr->local_part, taddr->domain); + GET_OPTION("mailstore_suffix"); if (ob->mailstore_suffix) { - uschar *s = expand_string(ob->mailstore_suffix); + uschar * s = expand_string(ob->mailstore_suffix); if (!s) { if (!f.expand_string_forcedfail) @@ -2757,18 +2772,21 @@ transport_newlines = 0; /* Write any configured prefix text first */ -if (yield == OK && ob->message_prefix && *ob->message_prefix) +if (yield == OK) { - uschar *prefix = expand_string(ob->message_prefix); - if (!prefix) - { - errno = ERRNO_EXPANDFAIL; - addr->transport_return = PANIC; - addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s " - "transport) failed", ob->message_prefix, tblock->name); - yield = DEFER; - } - else if (!transport_write_string(fd, "%s", prefix)) yield = DEFER; + uschar * prefix = ob->message_prefix; + GET_OPTION("message_prefix"); + if (prefix && *prefix) + if (!(prefix = expand_string(prefix))) + { + errno = ERRNO_EXPANDFAIL; + addr->transport_return = PANIC; + addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s " + "transport) failed", ob->message_prefix, tblock->name); + yield = DEFER; + } + else if (!transport_write_string(fd, "%s", prefix)) + yield = DEFER; } /* If the use_bsmtp option is on, we need to write SMTP prefix information. The @@ -2820,18 +2838,21 @@ if (yield == OK) /* Now a configured suffix. */ -if (yield == OK && ob->message_suffix && *ob->message_suffix) +if (yield == OK) { - uschar *suffix = expand_string(ob->message_suffix); - if (!suffix) - { - errno = ERRNO_EXPANDFAIL; - addr->transport_return = PANIC; - addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s " - "transport) failed", ob->message_suffix, tblock->name); - yield = DEFER; - } - else if (!transport_write_string(fd, "%s", suffix)) yield = DEFER; + uschar * suffix = ob->message_suffix; + GET_OPTION("message_suffix"); + if (suffix && *suffix) + if (!(suffix = expand_string(suffix))) + { + errno = ERRNO_EXPANDFAIL; + addr->transport_return = PANIC; + addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s " + "transport) failed", ob->message_suffix, tblock->name); + yield = DEFER; + } + else if (!transport_write_string(fd, "%s", suffix)) + yield = DEFER; } /* If batch smtp, write the terminating dot. */ diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index fa884cec4..3755ba284 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -314,20 +314,21 @@ if (addr->reply) } else { - uschar *oncerepeat = ob->once_repeat; + uschar * oncerepeat; DEBUG(D_transport) debug_printf("taking data from transport\n"); - from = ob->from; - reply_to = ob->reply_to; - to = ob->to; - cc = ob->cc; - bcc = ob->bcc; - subject = ob->subject; - headers = ob->headers; - text = ob->text; - file = ob->file; - logfile = ob->logfile; - oncelog = ob->oncelog; + GET_OPTION("once_repeat"); oncerepeat = ob->once_repeat; + GET_OPTION("from"); from = ob->from; + GET_OPTION("reply_to"); reply_to = ob->reply_to; + GET_OPTION("to"); to = ob->to; + GET_OPTION("cc"); cc = ob->cc; + GET_OPTION("bcc"); bcc = ob->bcc; + GET_OPTION("subject"); subject = ob->subject; + GET_OPTION("headers"); headers = ob->headers; + GET_OPTION("text"); text = ob->text; + GET_OPTION("file"); file = ob->file; + GET_OPTION("log"); logfile = ob->logfile; + GET_OPTION("once"); oncelog = ob->oncelog; file_expand = ob->file_expand; return_message = ob->return_message; diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index 64c70e719..157d2368f 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -315,6 +315,7 @@ argv = *argvptr; /* If allow_commands is set, see if the command is in the permitted list. */ +GET_OPTION("allow_commands"); if (ob->allow_commands) { int sep = 0; @@ -368,10 +369,11 @@ for it. */ if (argv[0][0] != '/') { int sep = 0; - uschar *p; - const uschar *listptr = expand_string(ob->path); + uschar * p; - while ((p = string_nextinlist(&listptr, &sep, NULL, 0))) + GET_OPTION("path"); + for (const uschar * listptr = expand_string(ob->path); + p = string_nextinlist(&listptr, &sep, NULL, 0); ) { struct stat statbuf; sprintf(CS big_buffer, "%.256s/%.256s", p, argv[0]); @@ -550,6 +552,7 @@ if (testflag(addr, af_pfr) && addr->local_part[0] == '|') { /* Enables expansion of $address_pipe into separate arguments */ setflag(addr, af_force_command); + GET_OPTION("commsnd"); cmd = ob->cmd; expand_arguments = TRUE; expand_fail = PANIC; @@ -563,6 +566,7 @@ if (testflag(addr, af_pfr) && addr->local_part[0] == '|') } else { + GET_OPTION("commsnd"); cmd = ob->cmd; expand_arguments = TRUE; expand_fail = PANIC; @@ -650,6 +654,7 @@ else if (timezone_string && timezone_string[0]) /* Add any requested items */ +GET_OPTION("environment"); if (envlist) if (!(envlist = expand_cstring(envlist))) { @@ -796,9 +801,10 @@ transport_count = 0; /* First write any configured prefix information */ +GET_OPTION("message_prefix"); if (ob->message_prefix) { - uschar *prefix = expand_string(ob->message_prefix); + uschar * prefix = expand_string(ob->message_prefix); if (!prefix) { addr->transport_return = f.search_find_defer? DEFER : PANIC; @@ -838,9 +844,10 @@ if (!transport_write_message(&tctx, 0)) /* Now any configured suffix */ +GET_OPTION("message_suffix"); if (ob->message_suffix) { - uschar *suffix = expand_string(ob->message_suffix); + uschar * suffix = expand_string(ob->message_suffix); if (!suffix) { addr->transport_return = f.search_find_defer? DEFER : PANIC; diff --git a/src/src/transports/queuefile.c b/src/src/transports/queuefile.c index b6511133c..21c98eeef 100644 --- a/src/src/transports/queuefile.c +++ b/src/src/transports/queuefile.c @@ -195,6 +195,7 @@ DEBUG(D_transport) # define O_NOFOLLOW 0 #endif +GET_OPTION("directory"); if (!(dstdir = expand_string(ob->dirname))) { addr->message = string_sprintf("%s transport: failed to expand dirname option", diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 596a328c3..736592352 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -1088,6 +1088,7 @@ if (pending_BANNER) /*XXX EXPERIMENTAL_ESMTP_LIMITS ? */ # ifndef DISABLE_TLS_RESUME + GET_OPTION("host_name_extract"); s = ((smtp_transport_options_block *)sx->conn_args.ob)->host_name_extract; if (!s) s = HNE_DEFAULT; ehlo_response_lbserver(sx, s); @@ -1769,6 +1770,7 @@ uschar * local_authenticated_sender = authenticated_sender; authenticated_sender, ob->authenticated_sender, f.smtp_authenticated?"Y":"N"); #endif +GET_OPTION("authenticated_sender"); if (ob->authenticated_sender) { uschar * new = expand_string(ob->authenticated_sender); @@ -2374,6 +2376,7 @@ PIPE_CONNECT_RETRY: For early-pipe, we are ok if binding to a local interface; otherwise (if $sending_ip_address is seen in helo_data) we disabled early-pipe above. */ + GET_OPTION("helo_data"); if (sx->helo_data) if (!(sx->helo_data = expand_string(sx->helo_data))) if (sx->verify) @@ -2501,6 +2504,7 @@ goto SEND_QUIT; an LB. Call this anyway, so that a dummy host_name_extract option value can force resumption attempts. */ + GET_OPTION("host_name_extract"); if (!(s = ob->host_name_extract)) s = US"never-LB"; ehlo_response_lbserver(sx, s); # endif @@ -2629,6 +2633,7 @@ goto SEND_QUIT; } #endif #ifndef DISABLE_TLS_RESUME + GET_OPTION("host_name_extract"); if (!(s = ob->host_name_extract)) s = HNE_DEFAULT; ehlo_response_lbserver(sx, s); #endif @@ -2837,13 +2842,17 @@ if (tls_out.active.sock >= 0) { uschar * greeting_cmd; - if (!sx->helo_data && !(sx->helo_data = expand_string(ob->helo_data))) + if (!sx->helo_data) { - uschar *message = string_sprintf("failed to expand helo_data: %s", - expand_string_message); - set_errno_nohost(sx->addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, &sx->delivery_start); - yield = DEFER; - goto SEND_QUIT; + GET_OPTION("helo_data"); + if (!(sx->helo_data = expand_string(ob->helo_data))) + { + uschar *message = string_sprintf("failed to expand helo_data: %s", + expand_string_message); + set_errno_nohost(sx->addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, &sx->delivery_start); + yield = DEFER; + goto SEND_QUIT; + } } #ifndef DISABLE_PIPE_CONNECT @@ -3094,6 +3103,7 @@ if (sx->addrlist->prop.utf8_msg) /* If the transport sets a downconversion mode it overrides any set by ACL for the message. */ + GET_OPTION("utf8_downconvert"); if ((s = ob->utf8_downconvert)) { if (!(s = expand_string(s))) @@ -5565,8 +5575,9 @@ retry_non_continued: host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET; { - uschar * s = ob->interface; - if (s && *s) + uschar * s; + GET_OPTION("interface"); + if ((s = ob->interface) && *s) { if (!smtp_get_interface(s, host_af, addrlist, &interface, tid)) return FALSE; diff --git a/src/src/transports/smtp_socks.c b/src/src/transports/smtp_socks.c index 22ee74bd8..ac8d0f2da 100644 --- a/src/src/transports/smtp_socks.c +++ b/src/src/transports/smtp_socks.c @@ -229,6 +229,7 @@ blob early_data; if (!timeout) timeout = 24*60*60; /* use 1 day for "indefinite" */ tmo = time(NULL) + timeout; +GET_OPTION("socks_proxy"); if (!(proxy_list = expand_string(ob->socks_proxy))) { log_write(0, LOG_MAIN|LOG_PANIC, "Bad expansion for socks_proxy in %s", diff --git a/src/src/verify.c b/src/src/verify.c index bde660063..78923651c 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -368,6 +368,7 @@ if (addr->transport == cutthrough.addr.transport) host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET; + GET_OPTION("interface"); if ( !smtp_get_interface(tf->interface, host_af, addr, &interface, US"callout") || !smtp_get_port(tf->port, addr, &port, US"callout") @@ -579,10 +580,14 @@ else with a random local part, ensure that such a local part is available. If not, log the fact, but carry on without randomising. */ - if (options & vopt_callout_random && callout_random_local_part) - if (!(random_local_part = expand_string(callout_random_local_part))) + if (options & vopt_callout_random) + { + GET_OPTION("callout_random_local_part"); + if ( callout_random_local_part + && !(random_local_part = expand_string(callout_random_local_part))) log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand " "callout_random_local_part: %s", expand_string_message); + } /* Compile regex' used by client-side smtp */ @@ -660,6 +665,7 @@ coding means skipping this whole loop and doing the append separately. */ deliver_domain = addr->domain; transport_name = addr->transport->name; + GET_OPTION("interface"); if ( !smtp_get_interface(tf->interface, host_af, addr, &interface, US"callout") || !smtp_get_port(tf->port, addr, &port, US"callout") commit 38965d80d70cacd0c944d32f7107549a3a272b35 Author: Jeremy Harris Date: Thu Sep 28 11:10:13 2023 +0100 Build: avoid compiling code for unused transports, routers, authenticators The smtp transport is not covered here; there are dependencies in other bits of the exim body. diff --git a/src/src/auths/cram_md5.c b/src/src/auths/cram_md5.c index 0761b7c6a..8f00ee498 100644 --- a/src/src/auths/cram_md5.c +++ b/src/src/auths/cram_md5.c @@ -13,15 +13,17 @@ in the MD5 computation functions, without their own stand-alone main program. */ #ifdef STAND_ALONE -#define CRAM_STAND_ALONE -#include "md5.c" +# define CRAM_STAND_ALONE +# include "md5.c" /* This is the normal, non-stand-alone case */ #else -#include "../exim.h" -#include "cram_md5.h" +# include "../exim.h" + +# ifdef AUTH_CRAM_MD5 +# include "cram_md5.h" /* Options specific to the cram_md5 authentication mechanism. */ @@ -49,7 +51,7 @@ auth_cram_md5_options_block auth_cram_md5_option_defaults = { }; -#ifdef MACRO_PREDEF +# ifdef MACRO_PREDEF /* Dummy values */ void auth_cram_md5_init(auth_instance *ablock) {} @@ -57,7 +59,7 @@ int auth_cram_md5_server(auth_instance *ablock, uschar *data) {return 0;} int auth_cram_md5_client(auth_instance *ablock, void *sx, int timeout, uschar *buffer, int buffsize) {return 0;} -#else /*!MACRO_PREDEF*/ +# else /*!MACRO_PREDEF*/ /************************************************* @@ -81,8 +83,9 @@ if (ob->client_secret != NULL) } } -#endif /*!MACRO_PREDEF*/ -#endif /* STAND_ALONE */ +# endif /*!MACRO_PREDEF*/ +# endif /*AUTH_CRAM_MD5*/ +#endif /*!STAND_ALONE*/ @@ -154,7 +157,8 @@ md5_end(&base, md5secret, 16, digestptr); } -#ifndef STAND_ALONE +# ifndef STAND_ALONE +# ifdef AUTH_CRAM_MD5 /************************************************* * Server entry point * @@ -329,7 +333,8 @@ if (smtp_write_command(sx, SCMD_FLUSH, "%s\r\n", b64encode(CUS big_buffer, return smtp_read_response(sx, US buffer, buffsize, '2', timeout) ? OK : FAIL; } -#endif /* STAND_ALONE */ +# endif /*AUTH_CRAM_MD5*/ +# endif /*!STAND_ALONE*/ /************************************************* @@ -338,7 +343,7 @@ return smtp_read_response(sx, US buffer, buffsize, '2', timeout) ************************************************** *************************************************/ -#ifdef STAND_ALONE +# ifdef STAND_ALONE int main(int argc, char **argv) { @@ -355,7 +360,7 @@ printf("\n"); return 0; } -#endif +# endif /*STAND_ALONE*/ #endif /*!MACRO_PREDEF*/ /* End of cram_md5.c */ diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c index 377c09205..7f437fa0d 100644 --- a/src/src/auths/dovecot.c +++ b/src/src/auths/dovecot.c @@ -23,6 +23,8 @@ because using C buffered I/O gives problems on some operating systems. PH */ */ #include "../exim.h" + +#ifdef AUTH_DOVECOT /* Remainder of file */ #include "dovecot.h" #define VERSION_MAJOR 1 @@ -533,4 +535,6 @@ return ret; } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*AUTH_DOVECOT*/ +/* end of auths/dovecot.c */ diff --git a/src/src/auths/external.c b/src/src/auths/external.c index a89a50486..6ae5833af 100644 --- a/src/src/auths/external.c +++ b/src/src/auths/external.c @@ -14,6 +14,8 @@ method defined in RFC 4422 Appendix A. #include "../exim.h" + +#ifdef AUTH_EXTERNAL /* Remainder of file */ #include "external.h" /* Options specific to the external authentication mechanism. */ @@ -153,5 +155,6 @@ return OK; -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*AUTH_EXTERNAL*/ /* End of external.c */ diff --git a/src/src/auths/plaintext.c b/src/src/auths/plaintext.c index 391e629f9..814896047 100644 --- a/src/src/auths/plaintext.c +++ b/src/src/auths/plaintext.c @@ -8,6 +8,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "../exim.h" + +#ifdef AUTH_PLAINTEXT /* Remainder of file */ #include "plaintext.h" @@ -176,5 +178,6 @@ while ((s = string_nextinlist(&text, &sep, NULL, 0))) return FAIL; } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*AUTH_PLAINTEST*/ /* End of plaintext.c */ diff --git a/src/src/auths/spa.c b/src/src/auths/spa.c index 0d4262ec5..51418c4ed 100644 --- a/src/src/auths/spa.c +++ b/src/src/auths/spa.c @@ -34,6 +34,8 @@ References: #include "../exim.h" + +#ifdef AUTH_SPA /* Remainder of file */ #include "spa.h" /* #define DEBUG_SPA */ @@ -372,5 +374,6 @@ if (errno != 0 || buffer[0] != '3') return FAIL; } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*AUTH_SPA*/ /* End of spa.c */ diff --git a/src/src/auths/tls.c b/src/src/auths/tls.c index 72ad56c4e..005032f57 100644 --- a/src/src/auths/tls.c +++ b/src/src/auths/tls.c @@ -12,6 +12,8 @@ a server to verify a client SSL certificate #include "../exim.h" + +#ifdef AUTH_TLS /* Remainder of file */ #include "tls.h" /* Options specific to the tls authentication mechanism. */ @@ -91,5 +93,6 @@ return auth_check_serv_cond(ablock); } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*AUTH_TLS*/ /* End of tls.c */ diff --git a/src/src/routers/accept.c b/src/src/routers/accept.c index 8b72bfac1..9766e5e10 100644 --- a/src/src/routers/accept.c +++ b/src/src/routers/accept.c @@ -9,6 +9,8 @@ #include "../exim.h" + +#ifdef ROUTER_ACCEPT /* Remainder of file */ #include "rf_functions.h" #include "accept.h" @@ -137,4 +139,5 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)? OK : DEFER; } #endif /*!MACRO_PREDEF*/ +#endif /*ROUTER_ACCEPT*/ /* End of routers/accept.c */ diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c index 671e8c93f..33382671f 100644 --- a/src/src/routers/dnslookup.c +++ b/src/src/routers/dnslookup.c @@ -8,6 +8,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "../exim.h" + +#ifdef ROUTER_DNSLOOKUP /* Remainder of file */ #include "rf_functions.h" #include "dnslookup.h" @@ -469,7 +471,8 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)? OK : DEFER; } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*ROUTER_DNSLOOKUP /* End of routers/dnslookup.c */ /* vi: aw ai sw=2 */ diff --git a/src/src/routers/ipliteral.c b/src/src/routers/ipliteral.c index 1297b97f2..16e096b40 100644 --- a/src/src/routers/ipliteral.c +++ b/src/src/routers/ipliteral.c @@ -9,6 +9,8 @@ #include "../exim.h" + +#ifdef ROUTER_IPLITERAL /* Remainder of file */ #include "rf_functions.h" #include "ipliteral.h" @@ -199,5 +201,6 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)? OK : DEFER; } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*ROUTER_IPLITERAL*/ /* End of routers/ipliteral.c */ diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c index f9966bcc0..b88212e5c 100644 --- a/src/src/routers/iplookup.c +++ b/src/src/routers/iplookup.c @@ -9,6 +9,8 @@ #include "../exim.h" + +#ifdef ROUTER_IPLOOKUP /* Remainder of file */ #include "rf_functions.h" #include "iplookup.h" @@ -414,5 +416,6 @@ if (rc != OK) return rc; return OK; } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*ROUTER_IPLOOKUP*/ /* End of routers/iplookup.c */ diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c index 200e0206e..45378ce3d 100644 --- a/src/src/routers/manualroute.c +++ b/src/src/routers/manualroute.c @@ -9,6 +9,8 @@ #include "../exim.h" + +#ifdef ROUTER_MANUALROUTE #include "rf_functions.h" #include "manualroute.h" @@ -488,5 +490,6 @@ addr->transport = transport; return OK; } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*ROUTER_MANUALROUTE*/ /* End of routers/manualroute.c */ diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index dd5e24b93..b1d736f94 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -8,6 +8,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "../exim.h" + +#ifdef ROUTER_QUERYPROGRAM /* Remainder of file */ #include "rf_functions.h" #include "queryprogram.h" @@ -535,5 +537,6 @@ addr->prop = addr_prop; return rf_queue_add(addr, addr_local, addr_remote, rblock, pw) ? OK : DEFER; } -#endif /*!MACRO_PREDEF*/ +#endif /*!MACRO_PREDEF*/ +#endif /*ROUTER_QUERYPROGRAM*/ /* End of routers/queryprogram.c */ diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 6b27c82b0..37b5f5e24 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -9,6 +9,8 @@ #include "../exim.h" + +#ifdef ROUTER_REDIRECT /* Remainder of file */ #include "rf_functions.h" #include "redirect.h" @@ -807,4 +809,5 @@ return yield; } #endif /*!MACRO_PREDEF*/ +#endif /*ROUTER_REDIRECT*/ /* End of routers/redirect.c */ diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 72c96f0d0..0279659f2 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -9,6 +9,8 @@ #include "../exim.h" + +#ifdef TRANSPORT_APPENDFILE /* Remainder of file */ #include "appendfile.h" #ifdef SUPPORT_MAILDIR @@ -3326,4 +3328,5 @@ ret_panic: } #endif /*!MACRO_PREDEF*/ +#endif /*TRANSPORT_APPENDFILE*/ /* End of transport/appendfile.c */ diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index 3755ba284..2f2fe1e16 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -9,6 +9,8 @@ #include "../exim.h" + +#ifdef TRANSPORT_AUTOREPLY /* Remainder of file */ #include "autoreply.h" @@ -820,4 +822,5 @@ return FALSE; } #endif /*!MACRO_PREDEF*/ +#endif /*TRANSPORT_AUTOREPOL*/ /* End of transport/autoreply.c */ diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c index f3f908836..eff0dc79d 100644 --- a/src/src/transports/lmtp.c +++ b/src/src/transports/lmtp.c @@ -9,6 +9,8 @@ #include "../exim.h" +#ifdef TRANSPORT_LMTP /* Remainder of file */ + #include "lmtp.h" #define PENDING_OK 256 @@ -807,4 +809,5 @@ MINUS_N: } #endif /*!MACRO_PREDEF*/ +#endif /*TRANSPORT_LMTP*/ /* End of transport/lmtp.c */ diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index 157d2368f..60a20c8fe 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -9,6 +9,8 @@ #include "../exim.h" + +#ifdef TRANSPORT_PIPE /* Remainder of file */ #include "pipe.h" #ifdef HAVE_SETCLASSRESOURCES @@ -1131,4 +1133,5 @@ return FALSE; } #endif /*!MACRO_PREDEF*/ +#endif /*TRASPORT_PIPE*/ /* End of transport/pipe.c */ commit 46ad960434683b3e15eb17edf3b2d748c191fbc4 Author: Jeremy Harris Date: Sat Dec 23 17:44:31 2023 +0000 tidying diff --git a/src/src/daemon.c b/src/src/daemon.c index 3c63c6368..88114d648 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -1493,7 +1493,7 @@ if (is_multiple_qrun()) /* we are managing periodic runs */ } else #endif - /* Normal periodic runL in order of run priority, find the first queue + /* Normal periodic run: in order of run priority, find the first queue for which we can start a runner */ for (q = qrunners; q; q = q->next) commit f2738aab2d72569b6d47b788099f6ebab701b2b2 Author: Jeremy Harris Date: Wed Feb 28 13:46:56 2024 +0000 Lookups: avoid leaking user/passwd from server spec to log. Bug 3066 diff --git a/src/src/acl.c b/src/src/acl.c index ecba07b25..f4d65464e 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1146,9 +1146,9 @@ Returns: nothing */ static void -acl_warn(int where, uschar *user_message, uschar *log_message) +acl_warn(int where, uschar * user_message, uschar * log_message) { -if (log_message != NULL && log_message != user_message) +if (log_message && log_message != user_message) { uschar *text; string_item *logged; @@ -1159,9 +1159,9 @@ if (log_message != NULL && log_message != user_message) /* If a sender verification has failed, and the log message is "sender verify failed", add the failure message. */ - if (sender_verified_failed != NULL && - sender_verified_failed->message != NULL && - strcmpic(log_message, US"sender verify failed") == 0) + if ( sender_verified_failed + && sender_verified_failed->message + && strcmpic(log_message, US"sender verify failed") == 0) text = string_sprintf("%s: %s", text, sender_verified_failed->message); /* Search previously logged warnings. They are kept in malloc diff --git a/src/src/lookups/lf_sqlperform.c b/src/src/lookups/lf_sqlperform.c index d5bb8d297..0f3984ba7 100644 --- a/src/src/lookups/lf_sqlperform.c +++ b/src/src/lookups/lf_sqlperform.c @@ -13,6 +13,15 @@ +static int +server_len_for_logging(const uschar * server) +{ +const uschar * s = Ustrchr(server, '/'); +if (!s) return 64; +if (!(s = Ustrchr(s+1, '/'))) return 64; +return (int) (s - server); +} + /************************************************* * Call SQL server(s) to run an actual query * *************************************************/ @@ -30,6 +39,7 @@ Arguments: result where to pass back the result errmsg where to pass back an error message do_cache to be set zero if data is changed + opts options (which suffixed the lookup name, minus cache-control ones) or NULL func the lookup function to call Returns: the return from the lookup function, or DEFER @@ -42,21 +52,19 @@ lf_sqlperform(const uschar *name, const uschar *optionname, int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *, const uschar *)) { int rc; -uschar *server; +uschar * server; BOOL defer_break = FALSE; DEBUG(D_lookup) debug_printf_indent("%s query: \"%s\" opts '%s'\n", name, query, opts); -/* Handle queries that do have server information at the start. */ +/* Handle queries that do have server information at the start (old style). */ if (Ustrncmp(query, "servers", 7) == 0) { int qsep = 0; - const uschar *s, *ss; - const uschar *qserverlist; - uschar *qserver; + const uschar * s, * ss, * qserverlist; - log_write(0, LOG_MAIN|LOG_CONFIG_IN, "WARNING: obslete syntax used for lookup\n"); + log_write(0, LOG_MAIN|LOG_CONFIG_IN, "WARNING: obsolete syntax used for lookup"); s = query + 7; skip_whitespace(&s); @@ -83,35 +91,37 @@ if (Ustrncmp(query, "servers", 7) == 0) } qserverlist = string_sprintf("%.*s", (int)(ss - s), s); + query = ss + 1; - while ((qserver = string_nextinlist(&qserverlist, &qsep, NULL, 0))) + for (uschar * qsrv; qsrv = string_nextinlist(&qserverlist, &qsep, NULL, 0); ) { - if (Ustrchr(qserver, '/')) - server = qserver; + if (Ustrchr(qsrv, '/')) + server = qsrv; /* full server spec */ else - { - int len = Ustrlen(qserver); + { /* only name; search in option list */ + int len = Ustrlen(qsrv); const uschar * serverlist = optserverlist; for (int sep = 0; server = string_nextinlist(&serverlist, &sep, NULL, 0);) - if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/') + if (Ustrncmp(server, qsrv, len) == 0 && server[len] == '/') break; if (!server) { - *errmsg = string_sprintf("%s server \"%s\" not found in %s", name, - qserver, optionname); + *errmsg = string_sprintf("%s server \"%.*s\" not found in %s", + name, server_len_for_logging(qsrv), qsrv, optionname); return DEFER; } } if (is_tainted(server)) { - *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server); + *errmsg = string_sprintf("%s server \"%.*s\" is tainted", + name, server_len_for_logging(server), server); return DEFER; } - rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts); + rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts); if (rc != DEFER || defer_break) return rc; } } @@ -139,7 +149,7 @@ else *errmsg = string_sprintf("no %s servers defined (%s option)", name, optionname); else - for (int d = 0; (server = string_nextinlist(&serverlist, &d, NULL, 0)); ) + for (int d = 0; server = string_nextinlist(&serverlist, &d, NULL, 0); ) { /* If not a full spec assume from options; scan main list for matching hostname */ @@ -163,7 +173,8 @@ else if (is_tainted(server)) { - *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server); + *errmsg = string_sprintf("%s server \"%.*s\" is tainted", + name, server_len_for_logging(server), server); return DEFER; } @@ -176,3 +187,5 @@ return DEFER; } /* End of lf_sqlperform.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/receive.c b/src/src/receive.c index abac05c56..a56ff473e 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -290,12 +290,11 @@ Returns: FALSE if there isn't enough space, or if the information cannot BOOL receive_check_fs(int msg_size) { -int_eximarith_t space; int inodes; if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0) { - space = receive_statvfs(TRUE, &inodes); + int_eximarith_t space = receive_statvfs(TRUE, &inodes); DEBUG(D_receive) debug_printf("spool directory space = " PR_EXIM_ARITH "K inodes = %d " @@ -313,7 +312,7 @@ if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0) if (check_log_space > 0 || check_log_inodes > 0) { - space = receive_statvfs(FALSE, &inodes); + int_eximarith_t space = receive_statvfs(FALSE, &inodes); DEBUG(D_receive) debug_printf("log directory space = " PR_EXIM_ARITH "K inodes = %d " diff --git a/src/src/search.c b/src/src/search.c index 52dcab2b7..62416da76 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -590,35 +590,48 @@ else is either untainted or properly quoted for the lookup type. XXX Should we this move into lf_sqlperform() ? The server-taint check is there. + Also it already knows about looking for a "servers" spec in the query string. + Passing search_type down that far is an issue. */ if ( !filename && lookup_list[search_type]->quote && is_tainted(keystring) && !is_quoted_like(keystring, search_type)) { - uschar * s = acl_current_verb(); - if (!s) s = authenticator_current_name(); /* must be before transport */ - if (!s) s = transport_current_name(); /* must be before router */ - if (!s) s = router_current_name(); /* GCC ?: would be good, but not in clang */ - if (!s) s = US""; + const uschar * ks = keystring; + uschar * loc = acl_current_verb(); + if (!loc) loc = authenticator_current_name(); /* must be before transport */ + if (!loc) loc = transport_current_name(); /* must be before router */ + if (!loc) loc = router_current_name(); /* GCC ?: would be good, but not in clang */ + if (!loc) loc = US""; + + if (Ustrncmp(ks, "servers", 7) == 0) /* Avoid logging server/password */ + if ((ks = Ustrchr(keystring, ';'))) + while (isspace(*++ks)) + ; + else + ks = US""; + #ifdef enforce_quote_protection_notyet search_error_message = string_sprintf( "tainted search query is not properly quoted%s: %s%s", - s, keystring); + loc, ks); f.search_find_defer = TRUE; + goto out; #else - { - int q = quoter_for_address(keystring); - /* If we're called from a transport, no privs to open the paniclog; - the logging punts to using stderr - and that seems to stop the debug - stream. */ - log_write(0, - transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC, - "tainted search query is not properly quoted%s: %s", s, keystring); - - DEBUG(D_lookup) debug_printf_indent("search_type %d (%s) quoting %d (%s)\n", + /* If we're called from a transport, no privs to open the paniclog; + the logging punts to using stderr - and that seems to stop the debug + stream. */ + log_write(0, + transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC, + "tainted search query is not properly quoted%s: %s", loc, ks); + + DEBUG(D_lookup) + { + int q = quoter_for_address(ks); + debug_printf_indent("search_type %d (%s) quoting %d (%s)\n", search_type, lookup_list[search_type]->name, q, is_real_quoter(q) ? lookup_list[q]->name : US"none"); - } + } #endif } @@ -669,6 +682,7 @@ pointer to NULL here, because we cannot release the store at this stage. */ } } +out: DEBUG(D_lookup) { if (data) commit 443245384239776d29f5386050f56247c7404c1e Author: Fabrice Fontaine Date: Thu Feb 29 19:01:49 2024 +0000 LibreSSL: fix build for 3.5.0+ Bug 3074 diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 237303ba9..e6a1c6fa4 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -97,6 +97,9 @@ change this guard and punt the issue for a while longer. */ #if LIBRESSL_VERSION_NUMBER >= 0x3040000fL # define EXIM_HAVE_OPENSSL_CIPHER_GET_ID #endif +#if LIBRESSL_VERSION_NUMBER >= 0x3050000fL +# define EXIM_HAVE_OPENSSL_OCSP_RESP_GET0_CERTS +#endif #if !defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x030000000L) # define EXIM_HAVE_EXPORT_CHNL_BNGNG commit f9609304cd7ffe553e3da325287973a0b2a4446c Author: Heiko Schlichting Date: Thu Feb 29 19:26:48 2024 +0000 Fix crash on empty -oMt argument. Bug 3070 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index ff768e94c..f62d6fbf2 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1352,7 +1352,7 @@ if (host_checking) g = string_cat(g, hostname); else if (f.sender_host_unknown || f.sender_host_notsocket) - g = string_cat(g, sender_ident); + g = string_cat(g, sender_ident ? sender_ident : US"NULL"); else if (f.is_inetd) g = string_append(g, 2, hostname, US" (via inetd)"); commit d945e180cbe2b26392fb21f7ae4dd2ccc603a81b Author: Jeremy Harris Date: Fri Mar 8 01:59:34 2024 +0000 Debug: expansions: refactor ascii-art/UTF8; mark up space & nl diff --git a/src/src/expand.c b/src/src/expand.c index 6be5cca0e..a916eee64 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -4496,30 +4496,17 @@ return yield; /************************************************/ static void debug_expansion_interim(const uschar * what, const uschar * value, int nchar, - BOOL skipping) + esi_flags flags) { -DEBUG(D_noutf8) - debug_printf_indent("|"); -else - debug_printf_indent(UTF8_VERT_RIGHT); +debug_printf_indent("%V", "K"); for (int fill = 11 - Ustrlen(what); fill > 0; fill--) - DEBUG(D_noutf8) - debug_printf("-"); - else - debug_printf(UTF8_HORIZ); + debug_printf("%V", "-"); -debug_printf("%s: %.*s\n", what, nchar, value); +debug_printf("%s: %.*W\n", what, nchar, value); if (is_tainted(value)) - { - DEBUG(D_noutf8) - debug_printf_indent("%s \\__", skipping ? "| " : " "); - else - debug_printf_indent("%s", - skipping - ? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ); - debug_printf("(tainted)\n"); - } + debug_printf_indent("%V %V(tainted)\n", + flags & ESI_SKIPPING ? "|" : " ", "\\__"); } @@ -4618,17 +4605,10 @@ while (*s) DEBUG(D_expand) { - DEBUG(D_noutf8) - debug_printf_indent("%c%s: %s\n", - first ? '/' : '|', - flags & ESI_SKIPPING ? "---scanning" : "considering", s); - else - debug_printf_indent("%s%s: %s\n", - first ? UTF8_DOWN_RIGHT : UTF8_VERT_RIGHT, - flags & ESI_SKIPPING - ? UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ "scanning" - : "considering", - s); + debug_printf_indent("%V%V%s: %W\n", + first ? "/" : "K", + flags & ESI_SKIPPING ? "---" : "", + flags & ESI_SKIPPING ? "scanning" : "considering", s); first = FALSE; } @@ -4651,21 +4631,20 @@ while (*s) for (s = t; *s ; s++) if (*s == '\\' && s[1] == 'N') break; DEBUG(D_expand) - debug_expansion_interim(US"protected", t, (int)(s - t), !!(flags & ESI_SKIPPING)); - yield = string_catn(yield, t, s - t); + debug_expansion_interim(US"protected", t, (int)(s - t), flags); + if (!(flags & ESI_SKIPPING)) + yield = string_catn(yield, t, s - t); if (*s) s += 2; } else { uschar ch[1]; DEBUG(D_expand) - DEBUG(D_noutf8) - debug_printf_indent("|backslashed: '\\%c'\n", s[1]); - else - debug_printf_indent(UTF8_VERT_RIGHT "backslashed: '\\%c'\n", s[1]); + debug_printf_indent("%Vbackslashed: '\\%c'\n", "K", s[1]); ch[0] = string_interpret_escape(&s); + if (!(flags & ESI_SKIPPING)) + yield = string_catn(yield, ch, 1); s++; - yield = string_catn(yield, ch, 1); } continue; } @@ -4682,9 +4661,10 @@ while (*s) for (const uschar * t = s+1; *t && *t != '$' && *t != '}' && *t != '\\'; t++) i++; - DEBUG(D_expand) debug_expansion_interim(US"text", s, i, !!(flags & ESI_SKIPPING)); + DEBUG(D_expand) debug_expansion_interim(US"text", s, i, flags); - yield = string_catn(yield, s, i); + if (!(flags & ESI_SKIPPING)) + yield = string_catn(yield, s, i); s += i; continue; } @@ -4710,15 +4690,16 @@ while (*s) /* If this is the first thing to be expanded, release the pre-allocated buffer. */ - if (!yield) - g = store_get(sizeof(gstring), GET_UNTAINTED); - else if (yield->ptr == 0) - { - if (resetok) reset_point = store_reset(reset_point); - yield = NULL; - reset_point = store_mark(); - g = store_get(sizeof(gstring), GET_UNTAINTED); /* alloc _before_ calling find_variable() */ - } + if (!(flags & ESI_SKIPPING)) + if (!yield) + g = store_get(sizeof(gstring), GET_UNTAINTED); + else if (yield->ptr == 0) + { + if (resetok) reset_point = store_reset(reset_point); + yield = NULL; + reset_point = store_mark(); + g = store_get(sizeof(gstring), GET_UNTAINTED); /* alloc _before_ calling find_variable() */ + } /* Header */ @@ -4767,16 +4748,17 @@ while (*s) reset in the middle of the buffer will make it inaccessible. */ len = Ustrlen(value); - DEBUG(D_expand) debug_expansion_interim(US"value", value, len, !!(flags & ESI_SKIPPING)); - if (!yield && newsize != 0) - { - yield = g; - yield->size = newsize; - yield->ptr = len; - yield->s = US value; /* known to be in new store i.e. a copy, so deconst safe */ - } - else - yield = string_catn(yield, value, len); + DEBUG(D_expand) debug_expansion_interim(US"value", value, len, flags); + if (!(flags & ESI_SKIPPING)) + if (!yield && newsize != 0) + { + yield = g; + yield->size = newsize; + yield->ptr = len; + yield->s = US value; /* known to be in new store i.e. a copy, so deconst safe */ + } + else + yield = string_catn(yield, value, len); continue; } @@ -4787,8 +4769,9 @@ while (*s) s = read_cnumber(&n, s); if (n >= 0 && n <= expand_nmax) { - DEBUG(D_expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], !!(flags & ESI_SKIPPING)); - yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); + DEBUG(D_expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], flags); + if (!(flags & ESI_SKIPPING)) + yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); } continue; } @@ -4815,8 +4798,9 @@ while (*s) } if (n >= 0 && n <= expand_nmax) { - DEBUG(D_expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], !!(flags & ESI_SKIPPING)); - yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); + DEBUG(D_expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], flags); + if (!(flags & ESI_SKIPPING)) + yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); } continue; } @@ -4941,9 +4925,9 @@ while (*s) DEBUG(D_expand) { - debug_expansion_interim(US"condition", s, (int)(next_s - s), !!(flags & ESI_SKIPPING)); + debug_expansion_interim(US"condition", s, (int)(next_s - s), flags); debug_expansion_interim(US"result", - cond ? US"true" : US"false", cond ? 4 : 5, !!(flags & ESI_SKIPPING)); + cond ? US"true" : US"false", cond ? 4 : 5, flags); } s = next_s; @@ -7162,7 +7146,7 @@ while (*s) if (yield && (expansion_start > 0 || *s)) debug_expansion_interim(US"item-res", yield->s + expansion_start, yield->ptr - expansion_start, - !!(flags & ESI_SKIPPING)); + flags); continue; NOT_ITEM: ; @@ -8347,27 +8331,13 @@ NOT_ITEM: ; int i = gstring_length(yield) - expansion_start; BOOL tainted = is_tainted(s); - DEBUG(D_noutf8) - { - debug_printf_indent("|-----op-res: %.*s\n", i, s); - if (tainted) - { - debug_printf_indent("%s \\__", flags & ESI_SKIPPING ? "| " : " "); - debug_print_taint(res); - } - } - else + debug_printf_indent("%Vop-res: %.*s\n", "K-----", i, s); + if (tainted) { - debug_printf_indent(UTF8_VERT_RIGHT - UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ - "op-res: %.*s\n", i, s); - if (tainted) - { - debug_printf_indent("%s", - flags & ESI_SKIPPING - ? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ); - debug_print_taint(res); - } + debug_printf_indent("%V %V", + flags & ESI_SKIPPING ? "|" : " ", + "\\__"); + debug_print_taint(res); } } continue; @@ -8459,39 +8429,25 @@ left != NULL, return a pointer to the terminator. */ DEBUG(D_expand) { BOOL tainted = is_tainted(res); - DEBUG(D_noutf8) - { - debug_printf_indent("|--expanding: %.*s\n", (int)(s - string), string); - debug_printf_indent("%sresult: %s\n", - flags & ESI_SKIPPING ? "|-----" : "\\_____", res); - if (tainted) - { - debug_printf_indent("%s \\__", flags & ESI_SKIPPING ? "| " : " "); - debug_print_taint(res); - } - if (flags & ESI_SKIPPING) - debug_printf_indent("\\___skipping: result is not used\n"); - } + debug_printf_indent("%Vexpanded: %.*W\n", + "K---", + (int)(s - string), string); + debug_printf_indent("%Vresult: ", + flags & ESI_SKIPPING ? "K-----" : "\\_____"); + if (*res || !(flags & ESI_SKIPPING)) + debug_printf("%W\n", res); else + debug_printf(" %Vskipped%V\n", "<", ">"); + if (tainted) { - debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ - "expanding: %.*s\n", - (int)(s - string), string); - debug_printf_indent("%s" UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ - "result: %s\n", - flags & ESI_SKIPPING ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT, - res); - if (tainted) - { - debug_printf_indent("%s", - flags & ESI_SKIPPING - ? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ); - debug_print_taint(res); - } - if (flags & ESI_SKIPPING) - debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ - "skipping: result is not used\n"); + debug_printf_indent("%V %V", + flags & ESI_SKIPPING ? "|" : " ", + "\\__" + ); + debug_print_taint(res); } + if (flags & ESI_SKIPPING) + debug_printf_indent("%Vskipping: result is not used\n", "\\___"); } if (textonly_p) *textonly_p = textonly; expand_level--; @@ -8517,25 +8473,11 @@ EXPAND_FAILED: if (left) *left = s; DEBUG(D_expand) { - DEBUG(D_noutf8) - { - debug_printf_indent("|failed to expand: %s\n", string); - debug_printf_indent("%serror message: %s\n", - f.expand_string_forcedfail ? "|---" : "\\___", expand_string_message); - if (f.expand_string_forcedfail) - debug_printf_indent("\\failure was forced\n"); - } - else - { - debug_printf_indent(UTF8_VERT_RIGHT "failed to expand: %s\n", - string); - debug_printf_indent("%s" UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ - "error message: %s\n", - f.expand_string_forcedfail ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT, - expand_string_message); - if (f.expand_string_forcedfail) - debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n"); - } + debug_printf_indent("%Vfailed to expand: %s\n", "K", string); + debug_printf_indent("%Verror message: %s\n", + f.expand_string_forcedfail ? "K---" : "\\___", expand_string_message); + if (f.expand_string_forcedfail) + debug_printf_indent("%Vfailure was forced\n", "\\"); } if (resetok_p && !resetok) *resetok_p = FALSE; expand_level--; diff --git a/src/src/macros.h b/src/src/macros.h index 902cdd165..3341f5f41 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -107,8 +107,9 @@ don't make the file descriptors two-way. */ /* Debugging control */ #define LOG_NAME_SIZE 256 -#define DEBUG(x) if (debug_selector & (x)) -#define HDEBUG(x) if (host_checking || debug_selector & (x)) +#define IS_DEBUG(x) (debug_selector & (x)) +#define DEBUG(x) if (IS_DEBUG(x)) +#define HDEBUG(x) if (host_checking || IS_DEBUG(x)) /* The default From: text for DSNs */ @@ -1057,6 +1058,10 @@ enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE }; #define UTF8_VERT_RIGHT "\xE2\x94\x9C" #define UTF8_UP_RIGHT "\xE2\x95\xB0" #define UTF8_VERT_2DASH "\xE2\x95\x8E" +#define UTF8_LEFT_TRIANGLE "\xE2\x97\x80" +#define UTF8_RIGHT_TRIANGLE "\xE2\x96\xB6" +#define UTF8_LIGHT_SHADE "\xE2\x96\x91" +#define UTF8_L_ARROW_HOOK "\xE2\x86\xA9" /* Options on tls_close */ diff --git a/src/src/os.c b/src/src/os.c index c6d1e06c2..3b49e4b9e 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -12,7 +12,8 @@ # include # include #else -# define DEBUG(x) if (debug_selector & (x)) +# define IS_DEBUG(x) (debug_selector & (x)) +# define DEBUG(x) if (IS_DEBUG(x)) #endif #ifndef CS diff --git a/src/src/string.c b/src/src/string.c index 3bf2f1df7..af187c199 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1348,7 +1348,7 @@ The return value can be NULL to signify overflow. Field width: decimal digits, or * Precision: dot, followed by decimal digits or * Length modifiers: h L l ll z -Conversion specifiers: n d o u x X p f e E g G % c s S T Y D M +Conversion specifiers: n d o u x X p f e E g G % c s S T W V Y D M Returns the possibly-new (if copy for growth or taint-handling was needed) string, not nul-terminated. @@ -1597,11 +1597,77 @@ while (*fp) case 'Y': /* gstring pointer */ { gstring * zg = va_arg(ap, gstring *); - if (zg) { s = CS zg->s; slen = zg->ptr; } + if (zg) { s = CS zg->s; slen = gstring_length(zg); } else { s = null; slen = Ustrlen(s); } goto INSERT_GSTRING; } +#ifndef COMPILE_UTILITY + case 'V': /* Maybe convert ascii-art to UTF-8 chars */ + { + gstring * zg = NULL; + s = va_arg(ap, char *); + if (IS_DEBUG(D_noutf8)) + for ( ; *s; s++) + zg = string_catn(zg, CUS (*s == 'K' ? "|" : s), 1); + else + for ( ; *s; s++) switch (*s) + { + case '\\': zg = string_catn(zg, US UTF8_UP_RIGHT, 3); break; + case '/': zg = string_catn(zg, US UTF8_DOWN_RIGHT, 3); break; + case '-': + case '_': zg = string_catn(zg, US UTF8_HORIZ, 3); break; + case '|': zg = string_catn(zg, US UTF8_VERT, 3); break; + case 'K': zg = string_catn(zg, US UTF8_VERT_RIGHT, 3); break; + case '<': zg = string_catn(zg, US UTF8_LEFT_TRIANGLE, 3); break; + case '>': zg = string_catn(zg, US UTF8_RIGHT_TRIANGLE, 3); break; + default: zg = string_catn(zg, CUS s, 1); break; + } + if (!zg) + break; + s = CS zg->s; + slen = gstring_length(zg); + goto INSERT_GSTRING; + } + + case 'W': /* Maybe mark up spaces & newlines */ + s = va_arg(ap, char *); + if (Ustrpbrk(s, " \n") && !IS_DEBUG(D_noutf8)) + { + gstring * zg = NULL; + int p = precision; + for ( ; *s; s++) + { + /* Take a given precision as applying to the input; expand + it for the transformed result */ + + if (p >= 0 && --p < 0) break; + switch (*s) + { + case ' ': + zg = string_catn(zg, CUS UTF8_LIGHT_SHADE, 3); + if (precision >= 0) precision += 2; + break; + case '\n': + zg = string_catn(zg, CUS UTF8_L_ARROW_HOOK "\n", 4); + if (precision >= 0) precision += 3; + break; + default: + zg = string_catn(zg, CUS s, 1); + break; + } + } + if (zg) { s = CS zg->s; slen = gstring_length(zg); } + else { s = null; slen = Ustrlen(s); } + } + else + { + if (!s) s = null; + slen = Ustrlen(s); + } + goto INSERT_GSTRING; + +#endif case 's': case 'S': /* Forces *lower* case */ case 'T': /* Forces *upper* case */ @@ -1610,7 +1676,7 @@ while (*fp) if (!s) s = null; slen = Ustrlen(s); - INSERT_GSTRING: /* Coome to from %Y above */ + INSERT_GSTRING: /* Come to from %Y above */ if (!(flags & SVFMT_TAINT_NOCHK) && is_incompatible(g->s, s)) if (flags & SVFMT_REBUFFER) @@ -1909,3 +1975,5 @@ return 0; #endif /* End of string.c */ +/* vi: aw ai sw=2 +*/ commit d4ff6d2a25234f7558baa99a54ca138c3f004b06 Author: Andrew Aitchison Date: Fri Mar 8 11:52:10 2024 +0000 Silence some compiler warnings. Bug 3076 diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c index 33382671f..80b12cba2 100644 --- a/src/src/routers/dnslookup.c +++ b/src/src/routers/dnslookup.c @@ -472,7 +472,7 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)? } #endif /*!MACRO_PREDEF*/ -#endif /*ROUTER_DNSLOOKUP +#endif /*ROUTER_DNSLOOKUP*/ /* End of routers/dnslookup.c */ /* vi: aw ai sw=2 */ diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 56ea93935..3e8ec6d84 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -1185,6 +1185,8 @@ tls_server_servercerts_cb(gnutls_session_t session, unsigned int htype, # ifdef notdef_crashes /*XXX crashes */ return gnutls_ext_raw_parse(NULL, tls_server_servercerts_ext, msg, 0); +# else +return GNUTLS_E_SUCCESS; # endif } #endif /*SUPPORT_GNUTLS_EXT_RAW_PARSE*/ @@ -1233,7 +1235,7 @@ switch (htype) return tls_server_ticket_cb(sess, htype, when, incoming, msg); # endif default: - return 0; + return GNUTLS_E_SUCCESS; } } #endif commit 35e7f5dc54c333d744a6b73d5668abddc085e0da Author: Peter Benie Date: Thu Mar 14 15:56:07 2024 +0000 Debug: fix transport-wait DB message. Bug 3082 diff --git a/src/src/transport.c b/src/src/transport.c index 5729f8e75..3609b78bb 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -1506,7 +1506,7 @@ open_db *dbm_file; if (!is_new_message_id(message_id)) { DEBUG(D_transport) debug_printf("message_id %s is not new format; " - "skipping wait-%s database update\n", tpname); + "skipping wait-%s database update\n", message_id, tpname); return; } commit c71f869820b45b911cc8edbd0de88bbc9621fd5f Author: Peter Benie Date: Thu Mar 14 16:11:14 2024 +0000 Rewrites: fix delivery crash from constant errors_to. Bug 3081 Broken-by: 753739fdef6d diff --git a/src/src/rewrite.c b/src/src/rewrite.c index 70bd79e26..9ee5a6794 100644 --- a/src/src/rewrite.c +++ b/src/src/rewrite.c @@ -104,7 +104,7 @@ rewrite_one(const uschar *s, int flag, BOOL *whole, BOOL add_header, uschar *nam { const uschar *yield = s; const uschar *subject = s; -uschar *domain = NULL; +const uschar *domain = NULL; BOOL done = FALSE; int rule_number = 1; int yield_start = 0, yield_end = 0; @@ -158,7 +158,7 @@ for (rewrite_rule * rule = rewrite_rules; else { - if (!domain) domain = Ustrrchr(subject, '@') + 1; + if (!domain) domain = CUstrrchr(subject, '@') + 1; /* Use the general function for matching an address against a list (here just one item, so use the "impossible value" separator UCHAR_MAX+1). */ @@ -182,16 +182,14 @@ for (rewrite_rule * rule = rewrite_rules; save_domain = deliver_domain; /* We have subject pointing to "localpart@domain" and domain pointing to - the domain. Temporarily terminate the local part so that it can be - set up as an expansion variable */ + the domain. Split into local part and domain so that it can be set up as + an expansion variable */ - domain[-1] = 0; - deliver_localpart = US subject; + deliver_localpart = US string_copyn(subject, domain-subject-1); deliver_domain = domain; new = expand_string(rule->replacement); - domain[-1] = '@'; deliver_localpart = save_localpart; deliver_domain = save_domain; } commit a7e6ad0ba38cf088e841c321042f81966d846b4b Author: Jeremy Harris Date: Sat Mar 16 13:50:45 2024 +0000 Lookups: fix dbmnz crash on zero-length datum. Bug 3079 Broken-by: 6d2c02560e5c diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 3c51162a4..460fd8bb7 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -239,12 +239,13 @@ Returns: a pointer to the retrieved record, or */ void * -dbfn_read_with_length(open_db *dbblock, const uschar *key, int *length) +dbfn_read_with_length(open_db * dbblock, const uschar * key, int * length) { -void *yield; +void * yield; EXIM_DATUM key_datum, result_datum; int klen = Ustrlen(key) + 1; uschar * key_copy = store_get(klen, key); +unsigned dlen; memcpy(key_copy, key, klen); @@ -260,9 +261,10 @@ if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL; /* Assume the data store could have been tainted. Properly, we should store the taint status with the data. */ -yield = store_get(exim_datum_size_get(&result_datum), GET_TAINTED); -memcpy(yield, exim_datum_data_get(&result_datum), exim_datum_size_get(&result_datum)); -if (length) *length = exim_datum_size_get(&result_datum); +dlen = exim_datum_size_get(&result_datum); +yield = store_get(dlen, GET_TAINTED); +memcpy(yield, exim_datum_data_get(&result_datum), dlen); +if (length) *length = dlen; exim_datum_free(&result_datum); /* Some DBM libs require freeing */ return yield; diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 3f70c2fd5..4d213773b 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -407,12 +407,13 @@ Returns: a pointer to the retrieved record, or */ void * -dbfn_read_with_length(open_db *dbblock, const uschar *key, int *length) +dbfn_read_with_length(open_db * dbblock, const uschar * key, int * length) { -void *yield; +void * yield; EXIM_DATUM key_datum, result_datum; int klen = Ustrlen(key) + 1; uschar * key_copy = store_get(klen, key); +unsigned dlen; memcpy(key_copy, key, klen); @@ -426,9 +427,10 @@ if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL; /* Assume for now that anything stored could have been tainted. Properly we should store the taint status along with the data. */ -yield = store_get(exim_datum_size_get(&result_datum), GET_TAINTED); -memcpy(yield, exim_datum_data_get(&result_datum), exim_datum_size_get(&result_datum)); -if (length) *length = exim_datum_size_get(&result_datum); +dlen = exim_datum_size_get(&result_datum); +yield = store_get(dlen, GET_TAINTED); +memcpy(yield, exim_datum_data_get(&result_datum), dlen); +if (length) *length = dlen; exim_datum_free(&result_datum); /* Some DBM libs require freeing */ return yield; diff --git a/src/src/lookups/dbmdb.c b/src/src/lookups/dbmdb.c index aa930e654..96665b6e4 100644 --- a/src/src/lookups/dbmdb.c +++ b/src/src/lookups/dbmdb.c @@ -102,7 +102,8 @@ exim_datum_size_set(&key, length); if (exim_dbget(d, &key, &data)) { - *result = string_copyn(exim_datum_data_get(&data), exim_datum_size_get(&data)); + unsigned len = exim_datum_size_get(&data); + *result = len > 0 ? string_copyn(exim_datum_data_get(&data), len) : US""; exim_datum_free(&data); /* Some DBM libraries need a free() call */ return OK; } @@ -283,3 +284,5 @@ static lookup_info *_lookup_list[] = { &dbm_lookup_info, &dbmz_lookup_info, &dbm lookup_module_info dbmdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 3 }; /* End of lookups/dbmdb.c */ +/* vi: aw ai sw=2 +*/ commit 481eeb93961ef9998901c522b498253d75124fb4 Author: Jeremy Harris Date: Sat Mar 16 13:54:42 2024 +0000 Autoreply: Remove Exim version 3 campatibility code diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index 2f2fe1e16..690ec4a92 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -496,19 +496,7 @@ if (oncelog && *oncelog && to) exim_datum_size_set(&key_datum, Ustrlen(to) + 1); if (exim_dbget(dbm_file, &key_datum, &result_datum)) - { - /* If the datum size is that of a binary time, we are in the new world - where messages are sent periodically. Otherwise the file is an old one, - where the datum was filled with a tod_log time, which is assumed to be - different in size. For that, only one message is ever sent. This change - introduced at Exim 3.00. In a couple of years' time the test on the size - can be abolished. */ - - if (exim_datum_size_get(&result_datum) == sizeof(time_t)) - memcpy(&then, exim_datum_data_get(&result_datum), sizeof(time_t)); - else - then = now; - } + memcpy(&then, exim_datum_data_get(&result_datum), sizeof(time_t)); } /* Either "then" is set zero, if no message has yet been sent, or it commit a1caa6da6f72e8c5b8b24678e32c4953a26a2b48 Author: Jeremy Harris Date: Thu Mar 21 23:48:32 2024 +0000 Option for taint when setting variable under -be diff --git a/src/src/acl.c b/src/src/acl.c index f4d65464e..29441dfc1 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -800,7 +800,7 @@ return TRUE; static BOOL acl_data_to_cond(const uschar * s, acl_condition_block * cond, - const uschar * name, uschar ** error) + const uschar * name, BOOL taint, uschar ** error) { if (*s++ != '=') { @@ -809,7 +809,7 @@ if (*s++ != '=') return FALSE;; } Uskip_whitespace(&s); -cond->arg = string_copy(s); +cond->arg = taint ? string_copy_taint(s, GET_TAINTED) : string_copy(s); return TRUE; } @@ -959,7 +959,7 @@ while ((s = (*func)())) "endpass" has no data */ if (c != ACLC_ENDPASS) - if (!acl_data_to_cond(s, cond, name, error)) return NULL; + if (!acl_data_to_cond(s, cond, name, FALSE, error)) return NULL; } return yield; @@ -4941,7 +4941,7 @@ fprintf(f, "acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value); uschar * -acl_standalone_setvar(const uschar * s) +acl_standalone_setvar(const uschar * s, BOOL taint) { acl_condition_block * cond = store_get(sizeof(acl_condition_block), GET_UNTAINTED); uschar * errstr = NULL, * log_msg = NULL; @@ -4951,7 +4951,7 @@ int e; cond->next = NULL; cond->type = ACLC_SET; if (!acl_varname_to_cond(&s, cond, &errstr)) return errstr; -if (!acl_data_to_cond(s, cond, US"'-be'", &errstr)) return errstr; +if (!acl_data_to_cond(s, cond, US"'-be'", taint, &errstr)) return errstr; if (acl_check_condition(ACL_WARN, cond, ACL_WHERE_UNKNOWN, NULL, 0, &endpass_seen, &errstr, &log_msg, &e) != OK) diff --git a/src/src/exim.c b/src/src/exim.c index c591ee60c..3170bef98 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1704,8 +1704,10 @@ if (isupper(big_buffer[0])) if (macro_read_assignment(big_buffer)) printf("Defined macro '%s'\n", mlast->name); } +else if (Ustrncmp(big_buffer, "set,t ", 6) == 0) + printf("%s\n", acl_standalone_setvar(big_buffer+6, TRUE)); else if (Ustrncmp(big_buffer, "set ", 4) == 0) - printf("%s\n", acl_standalone_setvar(big_buffer+4)); + printf("%s\n", acl_standalone_setvar(big_buffer+4, FALSE)); else if ((s = expand_string(big_buffer))) printf("%s\n", CS s); else printf("Failed: %s\n", expand_string_message); diff --git a/src/src/functions.h b/src/src/functions.h index 77323a5c1..0e657d7c4 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -103,7 +103,7 @@ extern acl_block *acl_read(uschar *(*)(void), uschar **); extern int acl_check(int, const uschar *, uschar *, uschar **, uschar **); extern uschar *acl_current_verb(void); extern int acl_eval(int, uschar *, uschar **, uschar **); -extern uschar *acl_standalone_setvar(const uschar *); +extern uschar *acl_standalone_setvar(const uschar *, BOOL); extern tree_node *acl_var_create(uschar *); extern void acl_var_write(uschar *, uschar *, void *); commit cea451c53287e51175c9bbe1a4fd607d1db7a02a Author: Jeremy Harris Date: Fri Mar 22 21:11:25 2024 +0000 Debug: more clarity on a ret=key lookup diff --git a/src/src/search.c b/src/src/search.c index 62416da76..27c686a5d 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -980,9 +980,15 @@ than the result. Return a de-tainted version of the key on the grounds that it have been validated by the lookup. */ if (yield && ret_key) + { yield = string_copy_taint(keystring, GET_UNTAINTED); + DEBUG(D_lookup) + debug_printf_indent("lookup yield replace by key: %s\n", yield); + } return yield; } /* End of search.c */ +/* vi: aw ai sw=2 +*/ commit 64226a31616e631b9e10f7897d603cdf9847a458 Author: Jeremy Harris Date: Fri Mar 22 23:05:02 2024 +0000 Debug: mark up space/nl in lookup results diff --git a/src/src/search.c b/src/src/search.c index 27c686a5d..168c25e6a 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -686,7 +686,7 @@ out: DEBUG(D_lookup) { if (data) - debug_printf_indent("lookup yielded: %s\n", data); + debug_printf_indent("lookup yielded: %W\n", data); else if (f.search_find_defer) debug_printf_indent("lookup deferred: %s\n", search_error_message); else debug_printf_indent("lookup failed\n"); commit c90c2288e88f66ae1d8af198cfa56c401e573ce4 Author: Jeremy Harris Date: Mon Mar 25 12:13:09 2024 +0000 specified-initializers diff --git a/src/src/globals.c b/src/src/globals.c index 4af8668f0..e23188b34 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -467,6 +467,9 @@ uschar *acl_smtp_quit = NULL; uschar *acl_smtp_rcpt = NULL; uschar *acl_smtp_starttls = NULL; uschar *acl_smtp_vrfy = NULL; +#ifdef EXPERIMENTAL_WELLKNOWN +uschar *acl_smtp_wellknown = NULL; +#endif tree_node *acl_var_c = NULL; tree_node *acl_var_m = NULL; @@ -474,56 +477,49 @@ uschar *acl_verify_message = NULL; string_item *acl_warn_logged = NULL; /* Names of SMTP places for use in ACL error messages, and corresponding SMTP -error codes - keep in step with definitions of ACL_WHERE_xxxx in macros.h. */ - -uschar *acl_wherenames[] = { US"RCPT", - US"MAIL", - US"PREDATA", - US"MIME", - US"DKIM", - US"DATA", +error codes (only those used) */ + +uschar *acl_wherenames[] = { [ACL_WHERE_RCPT] = US"RCPT", + [ACL_WHERE_MAIL] = US"MAIL", + [ACL_WHERE_PREDATA] = US"PREDATA", + [ACL_WHERE_MIME] = US"MIME", + [ACL_WHERE_DKIM] = US"DKIM", + [ACL_WHERE_DATA] = US"DATA", #ifndef DISABLE_PRDR - US"PRDR", -#endif - US"non-SMTP", - US"AUTH", - US"connection", - US"ETRN", - US"EXPN", - US"EHLO or HELO", - US"MAILAUTH", - US"non-SMTP-start", - US"NOTQUIT", - US"QUIT", - US"STARTTLS", - US"VRFY", - US"delivery", - US"unknown" + [ACL_WHERE_PRDR] = US"PRDR", +#endif + [ACL_WHERE_NOTSMTP] = US"non-SMTP", + [ACL_WHERE_AUTH] = US"AUTH", + [ACL_WHERE_CONNECT] = US"connection", + [ACL_WHERE_ETRN] = US"ETRN", + [ACL_WHERE_EXPN] = US"EXPN", + [ACL_WHERE_HELO] = US"EHLO or HELO", + [ACL_WHERE_MAILAUTH] = US"MAILAUTH", + [ACL_WHERE_NOTSMTP_START] = US"non-SMTP-start", + [ACL_WHERE_NOTQUIT] = US"NOTQUIT", + [ACL_WHERE_QUIT] = US"QUIT", + [ACL_WHERE_STARTTLS] = US"STARTTLS", + [ACL_WHERE_VRFY] = US"VRFY", + [ACL_WHERE_DELIVERY] = US"delivery", + [ACL_WHERE_UNKNOWN] = US"unknown" }; -uschar *acl_wherecodes[] = { US"550", /* RCPT */ - US"550", /* MAIL */ - US"550", /* PREDATA */ - US"550", /* MIME */ - US"550", /* DKIM */ - US"550", /* DATA */ +uschar *acl_wherecodes[] = { [ACL_WHERE_RCPT] = US"550", + [ACL_WHERE_MAIL] = US"550", + [ACL_WHERE_PREDATA] = US"550", + [ACL_WHERE_MIME] = US"550", + [ACL_WHERE_DKIM] = US"550", + [ACL_WHERE_DATA] = US"550", #ifndef DISABLE_PRDR - US"550", /* RCPT PRDR */ -#endif - US"0", /* not SMTP; not relevant */ - US"503", /* AUTH */ - US"550", /* connect */ - US"458", /* ETRN */ - US"550", /* EXPN */ - US"550", /* HELO/EHLO */ - US"0", /* MAILAUTH; not relevant */ - US"0", /* not SMTP; not relevant */ - US"0", /* NOTQUIT; not relevant */ - US"0", /* QUIT; not relevant */ - US"550", /* STARTTLS */ - US"252", /* VRFY */ - US"0", /* delivery; not relevant */ - US"0" /* unknown; not relevant */ + [ACL_WHERE_PRDR] = US"550", +#endif + [ACL_WHERE_AUTH] = US"503", + [ACL_WHERE_CONNECT] = US"550", + [ACL_WHERE_ETRN] = US"458", + [ACL_WHERE_EXPN] = US"550", + [ACL_WHERE_HELO] = US"550", + [ACL_WHERE_STARTTLS] = US"550", + [ACL_WHERE_VRFY] = US"252", }; uschar *add_environment = NULL; @@ -1003,6 +999,9 @@ uschar *hosts_proxy = NULL; #endif uschar *hosts_treat_as_local = NULL; uschar *hosts_require_helo = US"*"; +#ifdef EXPERIMENTAL_WELLKNOWN +uschar *hosts_wellknown = NULL; +#endif #ifdef EXPERIMENTAL_XCLIENT uschar *hosts_xclient = NULL; #endif @@ -1671,3 +1670,5 @@ const uschar *warnmsg_delay = NULL; const uschar *warnmsg_recipients = NULL; /* End of globals.c */ +/* vi: aw ai sw=2 +*/ commit 4687a69c269ee3f2a7f0625e0147a503fd9d3d0b Author: Jeremy Harris Date: Tue Mar 26 17:36:59 2024 +0000 tidying diff --git a/src/src/acl.c b/src/src/acl.c index 29441dfc1..d719a937b 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1366,7 +1366,7 @@ uschar * target = store_get(TARGET_SIZE, GET_TAINTED); client's HELO domain. If the client has not said HELO, use its IP address instead. If it's a local client (exim -bs), CSA isn't applicable. */ -while (isspace(*domain) && *domain != '\0') ++domain; +while (isspace(*domain) && *domain) ++domain; if (*domain == '\0') domain = sender_helo_name; if (!domain) domain = sender_host_address; if (!sender_host_address) return CSA_UNKNOWN; @@ -1867,9 +1867,10 @@ switch(vp->value) verify_sender_address = sender_address; else { - while (isspace(*s)) s++; - if (*s++ != '=') goto BAD_VERIFY; - while (isspace(*s)) s++; + if (Uskip_whitespace(&s) != '=') + goto BAD_VERIFY; + s++; + Uskip_whitespace(&s); verify_sender_address = string_copy(s); } } @@ -1911,13 +1912,13 @@ while ((ss = string_nextinlist(&list, &sep, NULL, 0))) callout = CALLOUT_TIMEOUT_DEFAULT; if (*(ss += 7)) { - while (isspace(*ss)) ss++; + Uskip_whitespace(&ss); if (*ss++ == '=') { const uschar * sublist = ss; int optsep = ','; - while (isspace(*sublist)) sublist++; + Uskip_whitespace(&sublist); for (uschar * opt; opt = string_nextinlist(&sublist, &optsep, NULL, 0); ) { callout_opt_t * op; @@ -1931,14 +1932,14 @@ while ((ss = string_nextinlist(&list, &sep, NULL, 0))) if (op->has_option) { opt += Ustrlen(op->name); - while (isspace(*opt)) opt++; + Uskip_whitespace(&opt); if (*opt++ != '=') { *log_msgptr = string_sprintf("'=' expected after " "\"%s\" in ACL verify condition \"%s\"", op->name, arg); return ERROR; } - while (isspace(*opt)) opt++; + Uskip_whitespace(&opt); } if (op->timeval && (period = v_period(opt, arg, log_msgptr)) < 0) return ERROR; @@ -1981,14 +1982,14 @@ while ((ss = string_nextinlist(&list, &sep, NULL, 0))) quota = TRUE; if (*(ss += 5)) { - while (isspace(*ss)) ss++; + Uskip_whitespace(&ss); if (*ss++ == '=') { const uschar * sublist = ss; int optsep = ','; int period; - while (isspace(*sublist)) sublist++; + Uskip_whitespace(&sublist); for (uschar * opt; opt = string_nextinlist(&sublist, &optsep, NULL, 0); ) if (Ustrncmp(opt, "cachepos=", 9) == 0) if ((period = v_period(opt += 9, arg, log_msgptr)) < 0) @@ -3892,7 +3893,7 @@ for (; cb; cb = cb->next) } s++; } - while (isspace(*s)) s++; + Uskip_whitespace(&s); if (logbits == 0) logbits = LOG_MAIN; log_write(0, logbits, "%s", string_printing(s)); @@ -4316,19 +4317,17 @@ if (!s) /* At top level, we expand the incoming string. At lower levels, it has already been expanded as part of condition processing. */ -if (acl_level == 0) +if (acl_level != 0) + ss = s; +else if (!(ss = expand_string(s))) { - if (!(ss = expand_string(s))) - { - if (f.expand_string_forcedfail) return OK; - *log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s", s, - expand_string_message); - return ERROR; - } + if (f.expand_string_forcedfail) return OK; + *log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s", s, + expand_string_message); + return ERROR; } -else ss = s; -while (isspace(*ss)) ss++; +Uskip_whitespace(&ss); /* If we can't find a named ACL, the default is to parse it as an inline one. (Unless it begins with a slash; non-existent files give rise to an error.) */ @@ -4617,8 +4616,8 @@ if (!(tmp = string_dequote(&s)) || !(name = expand_string(tmp))) for (i = 0; i < 9; i++) { - while (*s && isspace(*s)) s++; - if (!*s) break; + if (!Uskip_whitespace(&s)) + break; if (!(tmp = string_dequote(&s)) || !(tmp_arg[i] = expand_string(tmp))) { tmp = name; diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 460fd8bb7..13a3c2d66 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -490,7 +490,7 @@ while (Ufgets(buffer, 256, stdin) != NULL) { count = Uatoi(cmd); while (isdigit((uschar)*cmd)) cmd++; - while (isspace((uschar)*cmd)) cmd++; + Uskip_whitespace(&cmd); } if (Ustrncmp(cmd, "open", 4) == 0) @@ -498,7 +498,7 @@ while (Ufgets(buffer, 256, stdin) != NULL) int i; open_db *odb; uschar *s = cmd + 4; - while (isspace((uschar)*s)) s++; + Uskip_whitespace(&s); for (i = 0; i < max_db; i++) if (dbblock[i].dbptr == NULL) break; @@ -534,8 +534,7 @@ while (Ufgets(buffer, 256, stdin) != NULL) else if (Ustrncmp(cmd, "write", 5) == 0) { int rc = 0; - uschar *key = cmd + 5; - uschar *data; + uschar * key = cmd + 5, * data; if (current < 0) { @@ -543,11 +542,11 @@ while (Ufgets(buffer, 256, stdin) != NULL) continue; } - while (isspace((uschar)*key)) key++; + Uskip_whitespace(&key); data = key; - while (*data != 0 && !isspace((uschar)*data)) data++; + while (*data && !isspace((uschar)*data)) data++; *data++ = 0; - while (isspace((uschar)*data)) data++; + Uskip_whitespace(&data); dbwait = (dbdata_wait *)(&structbuffer); Ustrcpy(dbwait->text, data); @@ -562,13 +561,13 @@ while (Ufgets(buffer, 256, stdin) != NULL) else if (Ustrncmp(cmd, "read", 4) == 0) { - uschar *key = cmd + 4; + uschar * key = cmd + 4; if (current < 0) { printf("No current database\n"); continue; } - while (isspace((uschar)*key)) key++; + Uskip_whitespace(&key); start = clock(); while (count-- > 0) dbwait = (dbdata_wait *)dbfn_read_with_length(dbblock+ current, key, NULL); @@ -578,13 +577,13 @@ while (Ufgets(buffer, 256, stdin) != NULL) else if (Ustrncmp(cmd, "delete", 6) == 0) { - uschar *key = cmd + 6; + uschar * key = cmd + 6; if (current < 0) { printf("No current database\n"); continue; } - while (isspace((uschar)*key)) key++; + Uskip_whitespace(&key); dbfn_delete(dbblock + current, key); } @@ -614,8 +613,8 @@ while (Ufgets(buffer, 256, stdin) != NULL) else if (Ustrncmp(cmd, "close", 5) == 0) { - uschar *s = cmd + 5; - while (isspace((uschar)*s)) s++; + uschar * s = cmd + 5; + Uskip_whitespace(&s); i = Uatoi(s); if (i >= max_db || dbblock[i].dbptr == NULL) printf("Not open\n"); else { @@ -629,8 +628,8 @@ while (Ufgets(buffer, 256, stdin) != NULL) else if (Ustrncmp(cmd, "file", 4) == 0) { - uschar *s = cmd + 4; - while (isspace((uschar)*s)) s++; + uschar * s = cmd + 4; + Uskip_whitespace(&s); i = Uatoi(s); if (i >= max_db || dbblock[i].dbptr == NULL) printf("Not open\n"); else current = i; @@ -682,3 +681,5 @@ return 0; #endif /* End of dbfn.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/exim.c b/src/src/exim.c index 3170bef98..5c9e64021 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -2632,14 +2632,11 @@ on the second character (the one after '-'), to save some effort. */ reset_point = store_mark(); while (Ufgets(big_buffer, big_buffer_size, trust_list)) { - uschar *start = big_buffer, *nl; - while (*start && isspace(*start)) - start++; - if (*start != '/') + uschar * start = big_buffer, * nl; + if (Uskip_whitespace(&start) != '/') continue; - nl = Ustrchr(start, '\n'); - if (nl) - *nl = 0; + if ((nl = Ustrchr(start, '\n'))) + *nl = '\0'; trusted_configs[nr_configs++] = string_copy(start); if (nr_configs == nelem(trusted_configs)) break; @@ -2698,7 +2695,7 @@ on the second character (the one after '-'), to save some effort. */ const uschar * s = argrest; opt_D_used = TRUE; - while (isspace(*s)) s++; + Uskip_whitespace(&s); if (*s < 'A' || *s > 'Z') exim_fail("exim: macro name set by -D must start with " @@ -2711,11 +2708,10 @@ on the second character (the one after '-'), to save some effort. */ } name[ptr] = 0; if (ptr == 0) { badarg = TRUE; break; } - while (isspace(*s)) s++; - if (*s != 0) + if (Uskip_whitespace(&s)) { if (*s++ != '=') { badarg = TRUE; break; } - while (isspace(*s)) s++; + Uskip_whitespace(&s); } for (m = macros_user; m; m = m->next) @@ -5918,7 +5914,7 @@ for (BOOL more = TRUE; more; ) receive_add_recipient(string_copy_taint(recipient, GET_TAINTED), -1); s = ss; if (!finished) - while (*(++s) != 0 && (*s == ',' || isspace(*s))); + while (*++s && (*s == ',' || isspace(*s))); } } diff --git a/src/src/expand.c b/src/src/expand.c index a916eee64..5ea4dc6d4 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1262,7 +1262,8 @@ while (*s) while (*s && *s != '=' && !isspace(*s)) s++; dkeylength = s - dkey; - if (Uskip_whitespace(&s) == '=') while (isspace(*++s)); + if (Uskip_whitespace(&s) == '=') + while (isspace(*++s)) ; data = string_dequote(&s); if (length == dkeylength && strncmpic(key, dkey, length) == 0) @@ -4114,7 +4115,7 @@ if (!*error) if (*s != ')') *error = US"expecting closing parenthesis"; else - while (isspace(*++s)); + while (isspace(*++s)) ; else if (*s) *error = US"expecting operator"; *sptr = s; diff --git a/src/src/filter.c b/src/src/filter.c index b56b593b8..18567f17c 100644 --- a/src/src/filter.c +++ b/src/src/filter.c @@ -276,16 +276,11 @@ nextsigchar(const uschar *ptr, BOOL comment_allowed) for (;;) { while (isspace(*ptr)) - { - if (*ptr == '\n') line_number++; - ptr++; - } + if (*ptr++ == '\n') line_number++; if (comment_allowed && *ptr == '#') - { - while (*(++ptr) != '\n' && *ptr != 0); - continue; - } - else break; + while (*++ptr != '\n' && *ptr) ; + else + break; } return ptr; } @@ -311,18 +306,19 @@ Returns: pointer to the next significant character after the word static const uschar * nextword(const uschar *ptr, uschar *buffer, int size, BOOL bracket) { -uschar *bp = buffer; -while (*ptr != 0 && !isspace(*ptr) && +uschar * bp = buffer; +while (*ptr && !isspace(*ptr) && (!bracket || (*ptr != '(' && *ptr != ')'))) - { - if (bp - buffer < size - 1) *bp++ = *ptr++; else + if (bp - buffer < size - 1) + *bp++ = *ptr++; + else { *error_pointer = string_sprintf("word is too long in line %d of " "filter file (max = %d chars)", line_number, size); break; } - } -*bp = 0; + +*bp = '\0'; return nextsigchar(ptr, TRUE); } @@ -410,8 +406,8 @@ int value, count; if (sscanf(CS s, "%i%n", &value, &count) != 1) return 0; if (tolower(s[count]) == 'k') { value *= 1024; count++; } if (tolower(s[count]) == 'm') { value *= 1024*1024; count++; } -while (isspace((s[count]))) count++; -if (s[count] != 0) return 0; +while (isspace(s[count])) count++; +if (s[count]) return 0; *ok = TRUE; return value; } @@ -2006,8 +2002,7 @@ while (commands) if (subtype == TRUE) { - while (isspace(*s)) s++; - if (*s) + if (Uskip_whitespace(&s)) { header_add(htype_other, "%s%s", s, s[Ustrlen(s)-1] == '\n' ? "" : "\n"); @@ -2226,7 +2221,7 @@ while (commands) gstring * log_addr = NULL; if (!to) to = expand_string(US"$reply_address"); - while (isspace(*to)) to++; + Uskip_whitespace(&to); for (tt = to; *tt; tt++) /* Get rid of newlines */ if (*tt == '\n') @@ -2298,7 +2293,7 @@ while (commands) /* Move on past this address */ tt = ss + (*ss ? 1 : 0); - while (isspace(*tt)) tt++; + Uskip_whitespace(&tt); } if (log_addr) @@ -2612,3 +2607,5 @@ return yield; /* End of filter.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 050baa3b7..af1ad9dab 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -154,8 +154,7 @@ gstring * yield = string_get(256); /* If the string starts with '>' we change the output separator. If it's followed by ';' or ',' we set the TXT output separator. */ -while (isspace(*keystring)) keystring++; -if (*keystring == '>') +if (Uskip_whitespace(&keystring) == '>') { outsep = keystring + 1; keystring += 2; @@ -169,7 +168,7 @@ if (*keystring == '>') outsep2 = US""; keystring++; } - while (isspace(*keystring)) keystring++; + Uskip_whitespace(&keystring); } /* Check for a modifier keyword. */ @@ -234,14 +233,14 @@ for (;;) else break; - while (isspace(*keystring)) keystring++; + Uskip_whitespace(&keystring); if (*keystring++ != ',') { *errmsg = US"dnsdb modifier syntax error"; rc = DEFER; goto out; } - while (isspace(*keystring)) keystring++; + Uskip_whitespace(&keystring); } /* Figure out the "type" value if it is not T_TXT. @@ -272,7 +271,7 @@ if ((equals = Ustrchr(keystring, '=')) != NULL) } keystring = equals + 1; - while (isspace(*keystring)) keystring++; + Uskip_whitespace(&keystring); } /* Initialize the resolver in case this is the first time it has been used. */ diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index b93782cc3..90cde6c86 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -1083,20 +1083,15 @@ control_ldap_search(const uschar *ldap_url, int search_type, uschar **res, uschar **errmsg) { BOOL defer_break = FALSE; -int timelimit = LDAP_NO_LIMIT; -int sizelimit = LDAP_NO_LIMIT; +int timelimit = LDAP_NO_LIMIT, sizelimit = LDAP_NO_LIMIT; int tcplimit = 0; int sep = 0; int dereference = LDAP_DEREF_NEVER; -void* referrals = LDAP_OPT_ON; -const uschar *url = ldap_url; -const uschar *p; -uschar *user = NULL; -uschar *password = NULL; -uschar *local_servers = NULL; -const uschar *list; +void * referrals = LDAP_OPT_ON; +const uschar * url = ldap_url, * p, * list; +uschar * user = NULL, * password = NULL, * local_servers = NULL; -while (isspace(*url)) url++; +Uskip_whitespace(&url); /* Until the string begins "ldap", search for the other parameter settings that are recognized. They are of the form NAME=VALUE, with the value being @@ -1175,7 +1170,7 @@ while (strncmpic(url, US"ldap", 4) != 0) DEBUG(D_lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg); return DEFER; } - while (isspace(*url)) url++; + Uskip_whitespace(&url); continue; } } diff --git a/src/src/lookups/lsearch.c b/src/src/lookups/lsearch.c index 33e8c5157..7b78de916 100644 --- a/src/src/lookups/lsearch.c +++ b/src/src/lookups/lsearch.c @@ -291,8 +291,8 @@ for (BOOL this_is_eol, last_was_eol = TRUE; this_is_comment = (this_is_comment || (buffer[0] == 0 || buffer[0] == '#')); if (this_is_comment) continue; if (!isspace((uschar)buffer[0])) break; - while (isspace((uschar)*s)) s++; - *(--s) = ' '; + Uskip_whitespace(&s); + *--s = ' '; } if (this_is_comment) continue; diff --git a/src/src/lookups/oracle.c b/src/src/lookups/oracle.c index d0604c245..c25b7c0ee 100644 --- a/src/src/lookups/oracle.c +++ b/src/src/lookups/oracle.c @@ -408,9 +408,9 @@ while (cda->rc != NO_DATA_FOUND) /* Loop for each row */ else for (int i = 0; i < num_fields; i++) { int slen; - uschar *s = US desc[i].buf; + uschar * s = US desc[i].buf; - while (*s != 0 && isspace(*s)) s++; + Uskip_whitespace(&s); slen = Ustrlen(s); while (slen > 0 && isspace(s[slen-1])) slen--; result = string_catn(result, s, slen); diff --git a/src/src/lookups/redis.c b/src/src/lookups/redis.c index 7b680f086..53b479142 100644 --- a/src/src/lookups/redis.c +++ b/src/src/lookups/redis.c @@ -212,7 +212,7 @@ if(sdata[1]) int siz, ptr, i; uschar c; - while (isspace(*s)) s++; + Uskip_whitespace(&s); for (i = 0; *s && i < nele(argv); i++) { @@ -224,7 +224,7 @@ if(sdata[1]) argv[i] = string_from_gstring(g); DEBUG(D_lookup) debug_printf_indent("REDIS: argv[%d] '%s'\n", i, argv[i]); - while (isspace(*s)) s++; + Uskip_whitespace(&s); } /* Run the command. We use the argv form rather than plain as that parses diff --git a/src/src/match.c b/src/src/match.c index 8b1a3bef6..2cb499359 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -599,7 +599,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) if (*ss == '!') { yield = FAIL; - while (isspace((*(++ss)))); + while (isspace(*++ss)) ; } else yield = OK; @@ -825,15 +825,14 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) while (Ufgets(filebuffer, sizeof(filebuffer), f) != NULL) { - uschar *error; - uschar *sss = filebuffer; + uschar * error, * sss = filebuffer; while ((ss = Ustrchr(sss, '#')) != NULL) { if ((type != MCL_ADDRESS && type != MCL_LOCALPART) || ss == filebuffer || isspace(ss[-1])) { - *ss = 0; + *ss = '\0'; break; } sss = ss + 1; @@ -841,20 +840,19 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) ss = filebuffer + Ustrlen(filebuffer); /* trailing space */ while (ss > filebuffer && isspace(ss[-1])) ss--; - *ss = 0; + *ss = '\0'; ss = filebuffer; - while (isspace(*ss)) ss++; /* leading space */ - - if (!*ss) continue; /* ignore empty */ + if (!Uskip_whitespace(&ss)) /* leading space */ + continue; /* ignore empty */ file_yield = yield; /* positive yield */ sss = ss; /* for debugging */ if (*ss == '!') /* negation */ { - file_yield = (file_yield == OK)? FAIL : OK; - while (isspace((*(++ss)))); + file_yield = file_yield == OK ? FAIL : OK; + while (isspace(*++ss)) ; } switch ((func)(arg, ss, valueptr, &error)) @@ -1157,7 +1155,7 @@ if (pattern[0] == '@' && pattern[1] == '@') if (*ss == '!') { local_yield = FAIL; - while (isspace((*(++ss)))); + while (isspace(*++ss)) ; } else local_yield = OK; diff --git a/src/src/moan.c b/src/src/moan.c index 6fe82b29c..641540839 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -762,13 +762,12 @@ llen = domain++ - recipient; while ((item = string_nextinlist(&listptr, &sep, NULL, 0))) { - const uschar *newaddress = item; - const uschar *pattern = string_dequote(&newaddress); + const uschar * newaddress = item; + const uschar * pattern = string_dequote(&newaddress); /* If no new address found, just skip this item. */ - while (isspace(*newaddress)) newaddress++; - if (*newaddress == 0) continue; + if (!Uskip_whitespace(&newaddress)) continue; /* We now have an item to match as an address in item, and the additional address in newaddress. If the pattern matches, expand the new address string diff --git a/src/src/parse.c b/src/src/parse.c index ecdbe9f8d..4a75d229e 100644 --- a/src/src/parse.c +++ b/src/src/parse.c @@ -1363,7 +1363,7 @@ for (;;) *error = string_sprintf("\"%.*s\" is not permitted", len, s); return FF_ERROR; } - while (*ss && isspace(*ss)) ss++; /* skip leading whitespace */ + Uskip_whitespace(&ss); /* skip leading whitespace */ if ((len = Ustrlen(ss)) > 0) /* ignore trailing newlines */ for (const uschar * t = ss + len - 1; t >= ss && *t == '\n'; t--) len--; *error = string_copyn(ss, len); /* becomes the error */ diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 21e17c61e..565ee068e 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -679,8 +679,7 @@ for (const uschar * ele = raw_record, * tspec, * end, * val; *ele; ele = end) DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, tspec, val); while (taglen > 1 && isspace(tspec[taglen-1])) taglen--; /* Ignore whitespace before = */ - while (isspace(*val)) - val++; /* Ignore whitespace after = */ + Uskip_whitespace(&val); /* Ignore whitespace after = */ if (isspace(val[ Ustrlen(val)-1 ])) { /* Ignore whitespace after value */ gstring * g = string_cat(NULL, val); diff --git a/src/src/proxy.c b/src/src/proxy.c index fbce11163..e2d3bace0 100644 --- a/src/src/proxy.c +++ b/src/src/proxy.c @@ -396,7 +396,7 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0) /* Step through the string looking for the required fields. Ensure strict adherence to required formatting, exit for any error. */ p += 5; - if (!isspace(*(p++))) + if (!isspace(*p++)) { DEBUG(D_receive) debug_printf("Missing space after PROXY command\n"); goto proxyfail; @@ -417,7 +417,7 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0) } p += Ustrlen(iptype); - if (!isspace(*(p++))) + if (!isspace(*p++)) { DEBUG(D_receive) debug_printf("Missing space after TCP4/6 command\n"); goto proxyfail; diff --git a/src/src/readconf.c b/src/src/readconf.c index 5b486d0b6..3db3bdd69 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -1050,7 +1050,7 @@ for (;;) (Ustrncmp(ss+8, "_if_exists", 10) == 0 && isspace(ss[18])))) { uschar *t; - int include_if_exists = isspace(ss[8])? 0 : 10; + int include_if_exists = isspace(ss[8]) ? 0 : 10; config_file_item *save; struct stat statbuf; @@ -1644,8 +1644,7 @@ uschar name2[EXIM_DRIVERNAME_MAX]; /* There may be leading spaces; thereafter, we expect an option name starting with a letter. */ -while (isspace(*s)) s++; -if (!isalpha(*s)) +if (!isalpha( Uskip_whitespace(&s) )) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "option setting expected: %s", s); /* Read the name of the option, and skip any subsequent white space. If @@ -1660,7 +1659,7 @@ for (int n = 0; n < 2; n++) s++; } name[ptr] = 0; - while (isspace(*s)) s++; + Uskip_whitespace(&s); if (Ustrcmp(name, "hide") != 0) break; issecure = opt_secure; ptr = 0; @@ -1720,7 +1719,7 @@ else if (*s && (offset != 0 || *s != '=')) /* Skip white space after = */ -if (*s == '=') while (isspace((*(++s)))); +if (*s == '=') while (isspace(*++s)); /* If there is a data block and the opt_public flag is not set, change the data block pointer to the private options block. */ @@ -2202,8 +2201,7 @@ switch (type) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "absolute value of integer \"%s\" is too large (overflow)", s); - while (isspace(*endptr)) endptr++; - if (*endptr) + if (Uskip_whitespace(&endptr)) extra_chars_error(endptr, inttype, US"integer value for ", name); value = (int)lvalue; @@ -2251,8 +2249,7 @@ switch (type) if (errno == ERANGE) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "absolute value of integer \"%s\" is too large (overflow)", s); - while (isspace(*endptr)) endptr++; - if (*endptr != 0) + if (Uskip_whitespace(&endptr)) extra_chars_error(endptr, inttype, US"integer value for ", name); if (data_block) @@ -2347,7 +2344,7 @@ switch (type) list[count+1] = value; if (snext == NULL) break; s = snext + 1; - while (isspace(*s)) s++; + Uskip_whitespace(&s); } if (count > list[0] - 2) @@ -3570,8 +3567,7 @@ if (host_number_string) "failed to expand localhost_number \"%s\": %s", host_number_string, expand_string_message); n = Ustrtol(s, &end, 0); - while (isspace(*end)) end++; - if (*end) + if (Uskip_whitespace(&end)) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "localhost_number value is not a number: %s", s); if (n > LOCALHOST_MAX) @@ -4019,10 +4015,9 @@ Returns: time in seconds or fixed point number * 1000 */ static int -retry_arg(const uschar **paddr, int type) +retry_arg(const uschar ** paddr, int type) { -const uschar *p = *paddr; -const uschar *pp; +const uschar * p = *paddr, * pp; if (*p++ != ',') log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "comma expected"); @@ -4030,7 +4025,7 @@ Uskip_whitespace(&p); pp = p; while (isalnum(*p) || (type == 1 && *p == '.')) p++; -if (*p != 0 && !isspace(*p) && *p != ',' && *p != ';') +if (*p && !isspace(*p) && *p != ',' && *p != ';') log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "comma or semicolon expected"); *paddr = p; @@ -4433,10 +4428,8 @@ for (const config_line_item * i = config_lines; i; i = i->next) r = store_mark(); /* skip over to the first non-space */ - for (current = string_copy(i->line); *current && isspace(*current); ++current) - ; - - if (!*current) + current = string_copy(i->line); + if (!Uskip_whitespace(¤t)) continue; /* Collapse runs of spaces. We stop this if we encounter one of the @@ -4444,11 +4437,10 @@ for (const config_line_item * i = config_lines; i; i = i->next) for (p = current; *p; p++) if (isspace(*p)) { - uschar *next; + uschar * next = p; if (*p != ' ') *p = ' '; - for (next = p; isspace(*next); ++next) - ; + Uskip_whitespace(&p); if (next - p > 1) memmove(p+1, next, Ustrlen(next)+1); diff --git a/src/src/receive.c b/src/src/receive.c index a56ff473e..9dbf45df9 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -2251,8 +2251,7 @@ OVERSIZE: if (isspace(*p)) break; while (mac_isgraph(*p) && *p != ':') p++; - while (isspace(*p)) p++; - if (*p != ':') + if (Uskip_whitespace(&p) != ':') { body_zerocount = had_zero; break; @@ -2453,13 +2452,14 @@ for (header_line * h = header_list->next; h; h = h->next) if (!smtp_input) { int len; - uschar *s = Ustrchr(h->text, ':') + 1; - while (isspace(*s)) s++; + uschar * s = Ustrchr(h->text, ':') + 1; + + Uskip_whitespace(&s); len = h->slen - (s - h->text) - 1; if (Ustrlen(originator_login) == len && strncmpic(s, originator_login, len) == 0) { - uschar *name = is_resent? US"Resent-From" : US"From"; + uschar * name = is_resent ? US"Resent-From" : US"From"; header_add(htype_from, "%s: %s <%s@%s>\n", name, originator_name, originator_login, qualify_domain_sender); from_header = header_last; @@ -2514,15 +2514,13 @@ for (header_line * h = header_list->next; h; h = h->next) if (filter_test != FTEST_NONE) { - uschar *start = h->text + 12; - uschar *end = start + Ustrlen(start); - while (isspace(*start)) start++; + uschar * start = h->text + 12; + uschar * end = start + Ustrlen(start); + + Uskip_whitespace(&start); while (end > start && isspace(end[-1])) end--; if (*start == '<' && end[-1] == '>') - { - start++; - end--; - } + { start++; end--; } return_path = string_copyn(start, end - start); printf("Return-path taken from \"Return-path:\" header line\n"); } @@ -2626,7 +2624,7 @@ if (extract_recip) (!contains_resent_headers || strncmpic(h->text, US"resent-", 7) == 0)) { uschar * s = Ustrchr(h->text, ':') + 1; - while (isspace(*s)) s++; + Uskip_whitespace(&s); f.parse_allow_group = TRUE; /* Allow address group syntax */ @@ -2706,7 +2704,7 @@ if (extract_recip) /* Move on past this address */ s = ss + (*ss ? 1 : 0); - while (isspace(*s)) s++; + Uskip_whitespace(&s); } /* Next address */ f.parse_allow_group = FALSE; /* Reset group syntax flags */ diff --git a/src/src/rewrite.c b/src/src/rewrite.c index 9ee5a6794..ce35c4365 100644 --- a/src/src/rewrite.c +++ b/src/src/rewrite.c @@ -452,7 +452,7 @@ header_line * newh = NULL; rmark function_reset_point = store_mark(); uschar * s = Ustrchr(h->text, ':') + 1; -while (isspace(*s)) s++; +Uskip_whitespace(&s); DEBUG(D_rewrite) /* The header text includes the trailing newline */ debug_printf_indent("rewrite_one_header: type=%c:\n %s", h->type, h->text); @@ -493,7 +493,7 @@ while (*s) recipient = parse_extract_address(s, &errmess, &start, &end, &domain, FALSE); *ss1 = terminator; s = ss + (*ss ? 1 : 0); - while (isspace(*s)) s++; + Uskip_whitespace(&s); /* There isn't much we can do for syntactic disasters at this stage. Pro tem (possibly for ever) ignore them. diff --git a/src/src/rfc2047.c b/src/src/rfc2047.c index 18263f9ab..1ab25150a 100644 --- a/src/src/rfc2047.c +++ b/src/src/rfc2047.c @@ -313,8 +313,8 @@ while (mimeword) mimeword = decode_mimeword(string, lencheck, &q1, &q2, &endword, &dlen, &dptr); if (mimeword) { - uschar *s = string; - while (isspace(*s)) s++; + uschar * s = string; + Uskip_whitespace(&s); if (s == mimeword) string = s; } } diff --git a/src/src/route.c b/src/src/route.c index 0fdcdf2ed..afd43d866 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -266,12 +266,12 @@ for (router_instance * r = routers; r; r = r->next) else if (Ustrncmp(s, "reroute:", 8) == 0) { s += 8; - while (isspace(*s)) s++; + Uskip_whitespace(&s); if (Ustrncmp(s, "rewrite:", 8) == 0) { r->self_rewrite = TRUE; s += 8; - while (isspace(*s)) s++; + Uskip_whitespace(&s); } r->self = s; r->self_code = self_reroute; @@ -693,13 +693,13 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) if (*ss == '+') { eacces_code = 1; - while (isspace((*(++ss)))); + while (isspace(*++ss)); } if (*ss == '!') { invert = TRUE; - while (isspace((*(++ss)))); + while (isspace(*++ss)); } if (*ss != '/') @@ -1463,7 +1463,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); ) } name += 2; - while (isspace(*assignment)) assignment++; + Uskip_whitespace(&assignment); if (!(val = expand_string(US assignment))) if (f.expand_string_forcedfail) diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c index 45378ce3d..ed497336b 100644 --- a/src/src/routers/manualroute.c +++ b/src/src/routers/manualroute.c @@ -156,17 +156,17 @@ static BOOL parse_route_item(const uschar *s, const uschar **domain, const uschar **hostlist, const uschar **options) { -while (*s != 0 && isspace(*s)) s++; +Uskip_whitespace(&s); if (domain) { if (!*s) return FALSE; /* missing data */ *domain = string_dequote(&s); - while (*s && isspace(*s)) s++; + Uskip_whitespace(&s); } *hostlist = string_dequote(&s); -while (*s && isspace(*s)) s++; +Uskip_whitespace(&s); *options = s; return TRUE; } @@ -333,8 +333,9 @@ lookup_type = LK_DEFAULT; while (*options) { unsigned n; - const uschar *s = options; - while (*options != 0 && !isspace(*options)) options++; + const uschar * s = options; + + while (*options && !isspace(*options)) options++; n = options-s; if (Ustrncmp(s, "randomize", n) == 0) randomize = TRUE; @@ -368,7 +369,7 @@ while (*options) if (*options) { options++; - while (*options != 0 && isspace(*options)) options++; + while (*options && isspace(*options)) options++; } } diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index b1d736f94..5f0f50cd9 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -363,10 +363,10 @@ buffer[len] = 0; DEBUG(D_route) debug_printf("command wrote: %s\n", buffer); rword = buffer; -while (isspace(*rword)) rword++; +Uskip_whitespace(&rword); rdata = rword; while (*rdata && !isspace(*rdata)) rdata++; -if (*rdata) *rdata++ = 0; +if (*rdata) *rdata++ = '\0'; /* The word must be a known yield name. If it is "REDIRECT", the rest of the line is redirection data, as for a .forward file. It may not contain filter diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index f62d6fbf2..79176687d 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1227,7 +1227,7 @@ for (smtp_cmd_list * p = cmd_list; p < cmd_list + nelem(cmd_list); p++) follow the sender address. */ smtp_cmd_argument = smtp_cmd_buffer + p->len; - while (isspace(*smtp_cmd_argument)) smtp_cmd_argument++; + Uskip_whitespace(&smtp_cmd_argument); Ustrcpy(smtp_data_buffer, smtp_cmd_argument); smtp_cmd_data = smtp_data_buffer; @@ -3807,8 +3807,8 @@ while (done <= 0) if (*smtp_cmd_data) { - *smtp_cmd_data++ = 0; - while (isspace(*smtp_cmd_data)) smtp_cmd_data++; + *smtp_cmd_data++ = '\0'; + Uskip_whitespace(&smtp_cmd_data); } /* Search for an authentication mechanism which is configured for use @@ -3919,10 +3919,10 @@ while (done <= 0) if (!f.sender_host_unknown) { BOOL old_helo_verified = f.helo_verified; - uschar *p = smtp_cmd_data; + uschar * p = smtp_cmd_data; - while (*p != 0 && !isspace(*p)) { *p = tolower(*p); p++; } - *p = 0; + while (*p && !isspace(*p)) { *p = tolower(*p); p++; } + *p = '\0'; /* Force a reverse lookup if HELO quoted something in helo_lookup_domains because otherwise the log can be confusing. */ diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 895b594fc..888a0006e 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -704,13 +704,13 @@ if (format) if (outblock->authenticating) { - uschar *p = big_buffer; + uschar * p = big_buffer; if (Ustrncmp(big_buffer, "AUTH ", 5) == 0) { p += 5; - while (isspace(*p)) p++; + Uskip_whitespace(&p); while (!isspace(*p)) p++; - while (isspace(*p)) p++; + Uskip_whitespace(&p); } while (*p) *p++ = '*'; } diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index e6a1c6fa4..64e8c711a 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -5170,8 +5170,7 @@ if (!expand_check(option_spec, US"openssl_options", &exp, &end)) for (uschar * s = exp; *s; /**/) { - while (isspace(*s)) ++s; - if (*s == '\0') + if (!Uskip_whitespace(&s)) break; if (*s != '+' && *s != '-') { diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index 690ec4a92..67d48a1cb 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -235,13 +235,12 @@ that needs to be removed */ s = newlist + Ustrlen(newlist); while (s > newlist && (isspace(s[-1]) || s[-1] == ',')) s--; -*s = 0; +*s = '\0'; /* Check to see if there any addresses left; if not, return NULL */ s = newlist; -while (s && isspace(*s)) s++; -if (*s) +if (Uskip_whitespace(&s)) return newlist; store_reset(reset_point); @@ -592,7 +591,7 @@ for (h = header_list; h; h = h->next) if (h) { message_id = Ustrchr(h->text, ':') + 1; - while (isspace(*message_id)) message_id++; + Uskip_whitespace(&message_id); fprintf(fp, "In-Reply-To: %s", message_id); } diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index 60a20c8fe..f8a1427b9 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -562,7 +562,7 @@ if (testflag(addr, af_pfr) && addr->local_part[0] == '|') else { cmd = addr->local_part + 1; - while (isspace(*cmd)) cmd++; + Uskip_whitespace(&cmd); expand_arguments = testflag(addr, af_expand_pipe); expand_fail = FAIL; } diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 736592352..ed5994241 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -533,7 +533,7 @@ switch(*errno_value) case ERRNO_SMTPFORMAT: /* Handle malformed SMTP response */ s = string_printing(buffer); - while (isspace(*s)) s++; + Uskip_whitespace(&s); *message = *s == 0 ? string_sprintf("Malformed SMTP reply (an empty line) " "in response to %s%s", pl, smtp_command) @@ -815,8 +815,7 @@ uschar * match; if (regex_match(regex_LIMITS, sx->buffer, -1, &match)) for (const uschar * s = sx->buffer + Ustrlen(match); *s; ) { - while (isspace(*s)) s++; - if (*s == '\n') break; + if (Uskip_whitespace(&s) == '\n') break; if (strncmpic(s, US"MAILMAX=", 8) == 0) { @@ -1694,8 +1693,8 @@ if ( sx->esmtp { DEBUG(D_transport) debug_printf("skipping %s authenticator: %s\n", au->name, - (au->client)? "client_condition is false" : - "not configured as a client"); + au->client ? "client_condition is false" + : "not configured as a client"); continue; } @@ -1703,15 +1702,14 @@ if ( sx->esmtp while (*p) { - int len = Ustrlen(au->public_name); - int rc; + int len = Ustrlen(au->public_name), rc; - while (isspace(*p)) p++; + Uskip_whitespace(&p); if (strncmpic(au->public_name, p, len) != 0 || - (p[len] != 0 && !isspace(p[len]))) + (p[len] && !isspace(p[len]))) { - while (*p != 0 && !isspace(*p)) p++; + while (*p && !isspace(*p)) p++; continue; } diff --git a/src/src/verify.c b/src/src/verify.c index 78923651c..4f3bafb04 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -2612,12 +2612,12 @@ for (int i = 0; i < 3 && !done; i++) f.parse_allow_group = TRUE; - while (*s != 0) + while (*s) { - address_item *vaddr; + address_item * vaddr; while (isspace(*s) || *s == ',') s++; - if (*s == 0) break; /* End of header */ + if (!*s) break; /* End of header */ ss = parse_find_address_end(s, FALSE); @@ -2628,7 +2628,7 @@ for (int i = 0; i < 3 && !done; i++) while (isspace(ss[-1])) ss--; terminator = *ss; - *ss = 0; + *ss = '\0'; HDEBUG(D_verify) debug_printf("verifying %.*s header address %s\n", (int)(endname - h->text), h->text, s); @@ -2873,17 +2873,17 @@ if (sscanf(CS buffer + qlen, "%d , %d%n", &received_sender_port, goto END_OFF; p = buffer + qlen + n; -while(isspace(*p)) p++; +Uskip_whitespace(&p); if (*p++ != ':') goto END_OFF; -while(isspace(*p)) p++; +Uskip_whitespace(&p); if (Ustrncmp(p, "USERID", 6) != 0) goto END_OFF; p += 6; -while(isspace(*p)) p++; +Uskip_whitespace(&p); if (*p++ != ':') goto END_OFF; -while (*p != 0 && *p != ':') p++; -if (*p++ == 0) goto END_OFF; -while(isspace(*p)) p++; -if (*p == 0) goto END_OFF; +while (*p && *p != ':') p++; +if (!*p++) goto END_OFF; +Uskip_whitespace(&p); +if (!*p) goto END_OFF; /* The rest of the line is the data we want. We turn it into printing characters when we save it, so that it cannot mess up the format of any logging @@ -3083,7 +3083,7 @@ if (iplookup) key = filename; while (*key != 0 && !isspace(*key)) key++; filename = string_copyn(filename, key - filename); - while (isspace(*key)) key++; + Uskip_whitespace(&key); } else if (mac_islookup(search_type, lookup_querystyle)) { diff --git a/src/src/xclient.c b/src/src/xclient.c index 2a8be9b0e..2219cb027 100644 --- a/src/src/xclient.c +++ b/src/src/xclient.c @@ -248,7 +248,7 @@ for (state = XCLIENT_SKIP_SPACES; *s; ) } case XCLIENT_SKIP_SPACES: - while (*s && isspace (*s)) s++; + Uskip_whitespace(&s); state = XCLIENT_READ_COMMAND; break; commit 3f77bd134b64c532748b83c3931df07058268b5e Author: Jeremy Harris Date: Tue Mar 26 19:52:49 2024 +0000 tidying diff --git a/src/exim_monitor/em_log.c b/src/exim_monitor/em_log.c index fbcb6b1c0..49f649d7e 100644 --- a/src/exim_monitor/em_log.c +++ b/src/exim_monitor/em_log.c @@ -294,7 +294,7 @@ if (LOG != NULL) if ((p = Ustrstr(buffer, "==")) != NULL) { - queue_item *qq = find_queue(id, queue_noop, 0); + queue_item * qq = find_queue(id, queue_noop, 0); if (qq) { dest_item *d; @@ -302,14 +302,12 @@ if (LOG != NULL) p += 2; while (isspace(*p)) p++; q = p; - while (*p != 0 && !isspace(*p)) + while (*p && !isspace(*p)) { if (*p++ != '\"') continue; - while (*p != 0) - { + while (*p) if (*p == '\\') p += 2; - else if (*p++ == '\"') break; - } + else if (*p++ == '\"') break; } *p++ = 0; if ((r = strstric(q, qualify_domain, FALSE)) != NULL && diff --git a/src/src/auths/cram_md5.c b/src/src/auths/cram_md5.c index 8f00ee498..5817be7c9 100644 --- a/src/src/auths/cram_md5.c +++ b/src/src/auths/cram_md5.c @@ -198,7 +198,7 @@ The former is now the preferred variable; the latter is the original one. Then check that the remaining length is 32. */ auth_vars[0] = expand_nstring[1] = clear; -while (*clear && !isspace(*clear)) clear++; +Uskip_nonwhite(&clear); if (!isspace(*clear)) return FAIL; *clear++ = 0; diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 13a3c2d66..389d1518e 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -544,8 +544,8 @@ while (Ufgets(buffer, 256, stdin) != NULL) Uskip_whitespace(&key); data = key; - while (*data && !isspace((uschar)*data)) data++; - *data++ = 0; + Uskip_nonwhite(&data); + *data++ = '\0'; Uskip_whitespace(&data); dbwait = (dbdata_wait *)(&structbuffer); diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index 9f5f2f042..bd24faa5b 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -379,7 +379,7 @@ while (Ufgets(line, max_insize, f) != NULL) else { keystart = s; - while (*s != 0 && *s != ':' && !isspace(*s)) s++; + while (*s && *s != ':' && !isspace(*s)) s++; exim_datum_size_set(&key, s - keystart + add_zero); } @@ -401,11 +401,11 @@ while (Ufgets(line, max_insize, f) != NULL) keybuffer[i] = 0; started = 1; - while (isspace(*s))s++; + while (isspace(*s)) s++; if (*s == ':') { s++; - while (isspace(*s))s++; + while (isspace(*s)) s++; } if (*s != 0) { diff --git a/src/src/functions.h b/src/src/functions.h index 0e657d7c4..d811c62a3 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -767,6 +767,12 @@ Return the next char as there's enough places using it to be useful. */ static inline uschar skip_whitespace(const uschar ** sp) { while (isspace(**sp)) (*sp)++; return **sp; } +/* Ditto, non-whitespace */ + +#define Uskip_nonwhite(sp) skip_nonwhite(CUSS sp) +static inline uschar skip_nonwhite(const uschar ** sp) +{ while (**sp && !isspace(**sp)) (*sp)++; return **sp; } + /******************************************************************************/ diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c index ed497336b..ffd6eeaca 100644 --- a/src/src/routers/manualroute.c +++ b/src/src/routers/manualroute.c @@ -335,7 +335,7 @@ while (*options) unsigned n; const uschar * s = options; - while (*options && !isspace(*options)) options++; + Uskip_nonwhite(&options); n = options-s; if (Ustrncmp(s, "randomize", n) == 0) randomize = TRUE; @@ -369,7 +369,7 @@ while (*options) if (*options) { options++; - while (*options && isspace(*options)) options++; + Uskip_whitespace(&options); } } diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index 5f0f50cd9..39645cd23 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -365,7 +365,7 @@ DEBUG(D_route) debug_printf("command wrote: %s\n", buffer); rword = buffer; Uskip_whitespace(&rword); rdata = rword; -while (*rdata && !isspace(*rdata)) rdata++; +Uskip_nonwhite(&rdata); if (*rdata) *rdata++ = '\0'; /* The word must be a known yield name. If it is "REDIRECT", the rest of the diff --git a/src/src/search.c b/src/src/search.c index 168c25e6a..d0eb84b3b 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -247,7 +247,7 @@ if (mac_islookup(search_type, lookup_absfilequery)) if (*query == '/') { uschar * s = query; - while (*query && !isspace(*query)) query++; + Uskip_nonwhite(&query); *fnamep = string_copyn(s, query - s); Uskip_whitespace(&query); } diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 79176687d..70e4b95df 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1946,6 +1946,9 @@ while (done <= 0) case HELP_CMD: case NOOP_CMD: case ETRN_CMD: +#ifdef EXPERIMENTAL_WELLKNOWN + case WELLKNOWN_CMD: +#endif bsmtp_transaction_linecount = receive_linecount; break; @@ -2991,8 +2994,8 @@ switch (where) if (where == ACL_WHERE_AUTH) /* avoid logging auth creds */ { - uschar * s; - for (s = smtp_cmd_data; *s && !isspace(*s); ) s++; + uschar * s = smtp_cmd_data; + Uskip_nonwhite(&s); lim = s - smtp_cmd_data; /* atop after method */ } what = string_sprintf("%s %.*s", acl_wherenames[where], lim, place); @@ -5694,7 +5697,7 @@ while (done <= 0) case TOO_MANY_NONMAIL_CMD: s = smtp_cmd_buffer; - while (*s && !isspace(*s)) s++; + Uskip_nonwhite(&s); incomplete_transaction_log(US"too many non-mail commands"); log_write(0, LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " "nonmail commands (last was \"%.*s\")", host_and_ident(FALSE), diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 888a0006e..a78b15fbd 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -709,7 +709,7 @@ if (format) { p += 5; Uskip_whitespace(&p); - while (!isspace(*p)) p++; + Uskip_nonwhite(&p); Uskip_whitespace(&p); } while (*p) *p++ = '*'; diff --git a/src/src/string.c b/src/src/string.c index af187c199..379be2035 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -649,7 +649,7 @@ uschar * t, * yield; /* First find the end of the string */ if (*s != '\"') - while (*s && !isspace(*s)) s++; + Uskip_nonwhite(&s); else { s++; diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 64e8c711a..34612adea 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -5179,7 +5179,8 @@ for (uschar * s = exp; *s; /**/) return FALSE; } adding = *s++ == '+'; - for (end = s; *end && !isspace(*end); ) end++; + end = s; + Uskip_nonwhite(&end); item_parsed = tls_openssl_one_option_parse(string_copyn(s, end-s), &item); if (!item_parsed) { diff --git a/src/src/verify.c b/src/src/verify.c index 4f3bafb04..065deec41 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -3081,7 +3081,7 @@ if (iplookup) { filename = semicolon + 1; key = filename; - while (*key != 0 && !isspace(*key)) key++; + Uskip_nonwhite(&key); filename = string_copyn(filename, key - filename); Uskip_whitespace(&key); } diff --git a/src/src/xclient.c b/src/src/xclient.c index 2219cb027..fb9d95c5e 100644 --- a/src/src/xclient.c +++ b/src/src/xclient.c @@ -172,7 +172,7 @@ for (state = XCLIENT_SKIP_SPACES; *s; ) uschar * val; word = ++s; /* skip the = */ - while (*s && !isspace(*s)) s++; + Uskip_nonwhite(&s); len = s - word; DEBUG(D_transport) debug_printf(" XCLIENT: \tvalue %.*s\n", len, word); commit f168d6a2c93ee92d87744ce09c45a0ec666f889c Author: Jeremy Harris Date: Wed Mar 27 15:40:03 2024 +0000 typoes diff --git a/src/src/globals.c b/src/src/globals.c index e23188b34..2885caa23 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -387,7 +387,7 @@ BOOL mua_wrapper = FALSE; BOOL preserve_message_logs = FALSE; BOOL print_topbitchars = FALSE; BOOL prod_requires_admin = TRUE; -#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) || defined(EXPERIMETAL_XCLIENT) +#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) || defined(EXPERIMENTAL_XCLIENT) BOOL proxy_session = FALSE; #endif diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 70e4b95df..f65ab6603 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -2554,7 +2554,7 @@ if (!f.sender_host_unknown) if (smtp_batched_input) return TRUE; -#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) || defined(EXPERIMETAL_XCLIENT) +#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) || defined(EXPERIMENTAL_XCLIENT) proxy_session = FALSE; #endif commit 4e19eed51a7f777e1e18b60c636e0c9bfb82c23b Author: Jeremy Harris Date: Wed Mar 27 16:04:50 2024 +0000 Fix encoding for AUTH= on MAIL FROM diff --git a/src/src/auths/xtextencode.c b/src/src/auths/xtextencode.c index c08288831..75be18161 100644 --- a/src/src/auths/xtextencode.c +++ b/src/src/auths/xtextencode.c @@ -29,31 +29,14 @@ Returns: a pointer to the zero-terminated xtext string, which uschar * auth_xtextencode(uschar *clear, int len) { -uschar *code; -uschar *p = US clear; -uschar *pp; -int c = len; -int count = 1; -register int x; - -/* We have to do a prepass to find out how many specials there are, -in order to get the right amount of store. */ - -while (c -- > 0) - count += ((x = *p++) < 33 || x > 127 || x == '+' || x == '=')? 3 : 1; - -pp = code = store_get(count, clear); - -p = US clear; -c = len; -while (c-- > 0) - if ((x = *p++) < 33 || x > 127 || x == '+' || x == '=') - pp += sprintf(CS pp, "+%.02x", x); /* There's always room */ - else - *pp++ = x; - -*pp = 0; -return code; +gstring * g = NULL; +for(uschar ch; len > 0; len--, clear++) + g = (ch = *clear) < 33 || ch > 126 || ch == '+' || ch == '=' + ? string_fmt_append(g, "+%.02X", ch) + : string_catn(g, clear, 1); +gstring_release_unused(g); +return string_from_gstring(g); } + /* End of xtextencode.c */ commit a600ccb4a236549ed1a950d3fc783a1e2e9de2cb Author: Jeremy Harris Date: Fri Mar 29 17:37:05 2024 +0000 Logging: fix receive-time crash with recipients-logging. Broken-by: d12746bc15d8 diff --git a/src/src/log.c b/src/src/log.c index f85823520..1a77f2cdb 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -601,6 +601,22 @@ if (type == lt_debug) unlink(CS debuglog_name); +/* Append to a gstring, in no-extend (or rebuffer) mode +and without taint-checking. Thanks to the no-extend, the +gstring struct never needs reallocation; we ignore the +infore that the initial space allocation for the string +was exceeded, and just leave it potentially truncated. */ + +static void +string_fmt_append_noextend(gstring * g, char * fmt, ...) +{ +va_list ap; +va_start(ap, fmt); +/* can return NULL if it truncates; just ignore */ +(void) string_vformat(g, SVFMT_TAINT_NOCHK, fmt, ap); +va_end(ap); +} + /************************************************* * Add configuration file info to log line * *************************************************/ @@ -609,24 +625,28 @@ if (type == lt_debug) unlink(CS debuglog_name); once for real). Arguments: - ptr pointer to the end of the line we are building - flags log flags + g extensible-string referring to static buffer, + usable after return + flags log flags -Returns: updated pointer +Returns: nothing */ -static gstring * +static void log_config_info(gstring * g, int flags) { -g = string_cat(g, US"Exim configuration error"); +string_fmt_append_noextend(g, "Exim configuration error"); if (flags & (LOG_CONFIG_FOR & ~LOG_CONFIG)) - return string_cat(g, US" for "); - -if (flags & (LOG_CONFIG_IN & ~LOG_CONFIG)) - g = string_fmt_append(g, " in line %d of %s", config_lineno, config_filename); + string_fmt_append_noextend(g, " for "); +else + { + if (flags & (LOG_CONFIG_IN & ~LOG_CONFIG)) + string_fmt_append_noextend(g, " in line %d of %s", + config_lineno, config_filename); -return string_catn(g, US":\n ", 4); + string_fmt_append_noextend(g, ":\n "); + } } @@ -813,7 +833,7 @@ log_write(unsigned int selector, int flags, const char *format, ...) int paniclogfd; ssize_t written_len; gstring gs = { .size = LOG_BUFFER_SIZE-2, .ptr = 0, .s = log_buffer }; -gstring * g; +gstring * g = &gs; va_list ap; /* If panic_recurseflag is set, we have failed to open the panic log. This is @@ -823,7 +843,7 @@ original log line that caused the problem. Afterwards, expire. */ if (panic_recurseflag) { - uschar *extra = panic_save_buffer ? panic_save_buffer : US""; + uschar * extra = panic_save_buffer ? panic_save_buffer : US""; if (debug_file) debug_printf("%s%s", extra, log_buffer); if (log_stderr && log_stderr != debug_file) fprintf(log_stderr, "%s%s", extra, log_buffer); @@ -924,45 +944,43 @@ in one go so that it doesn't get split when multi-processing. */ DEBUG(D_any|D_v) { - int i; - - g = string_catn(&gs, US"LOG:", 4); + string_fmt_append_noextend(g, "LOG:"); /* Show the selector that was passed into the call. */ - for (i = 0; i < log_options_count; i++) + for (int i = 0; i < log_options_count; i++) { unsigned int bitnum = log_options[i].bit; if (bitnum < BITWORDSIZE && selector == BIT(bitnum)) - g = string_fmt_append(g, " %s", log_options[i].name); + string_fmt_append_noextend(g, " %s", log_options[i].name); } - g = string_fmt_append(g, "%s%s%s%s\n ", + string_fmt_append_noextend(g, "%s%s%s%s\n ", flags & LOG_MAIN ? " MAIN" : "", flags & LOG_PANIC ? " PANIC" : "", (flags & LOG_PANIC_DIE) == LOG_PANIC_DIE ? " DIE" : "", flags & LOG_REJECT ? " REJECT" : ""); - if (flags & LOG_CONFIG) g = log_config_info(g, flags); + if (flags & LOG_CONFIG) log_config_info(g, flags); /* We want to be able to log tainted info, but log_buffer is directly malloc'd. So use deliberately taint-nonchecking routines to build into it, trusting that we will never expand the results. */ va_start(ap, format); - i = g->ptr; if (!string_vformat(g, SVFMT_TAINT_NOCHK, format, ap)) { - g->ptr = i; - g = string_cat(g, US"**** log string overflowed log buffer ****"); + uschar * s = US"**** log string overflowed log buffer ****"; + gstring_trim(g, Ustrlen(s)); + string_fmt_append_noextend(g, "%s", s); } va_end(ap); debug_printf("%Y\n", g); - gs.size = LOG_BUFFER_SIZE-2; /* Having used the buffer for debug output, */ - gs.ptr = 0; /* reset it for the real use. */ - gs.s = log_buffer; + /* Having used the buffer for debug output, reset it for the real use. */ + + gstring_reset(g); } /* If no log file is specified, we are in a mess. */ @@ -986,33 +1004,32 @@ if (!write_rejectlog) flags &= ~LOG_REJECT; /* Create the main message in the log buffer. Do not include the message id when called by a utility. */ -g = string_fmt_append(&gs, "%s ", tod_stamp(tod_log)); +string_fmt_append_noextend(&gs, "%s ", tod_stamp(tod_log)); if (LOGGING(pid)) { if (!syslog_pid) pid_position[0] = g->ptr; /* remember begin … */ - g = string_fmt_append(g, "[%d] ", (int)getpid()); + string_fmt_append_noextend(g, "[%ld] ", (long)getpid()); if (!syslog_pid) pid_position[1] = g->ptr; /* … and end+1 of the PID */ } if (f.really_exim && message_id[0]) - g = string_fmt_append(g, "%s ", message_id); + string_fmt_append_noextend(g, "%s ", message_id); if (flags & LOG_CONFIG) - g = log_config_info(g, flags); + log_config_info(g, flags); va_start(ap, format); { - int i = g->ptr; - /* We want to be able to log tainted info, but log_buffer is directly malloc'd. So use deliberately taint-nonchecking routines to build into it, trusting that we will never expand the results. */ if (!string_vformat(g, SVFMT_TAINT_NOCHK, format, ap)) { - g->ptr = i; - g = string_cat(g, US"**** log string overflowed log buffer ****\n"); + uschar * s = US"**** log string overflowed log buffer ****\n"; + gstring_trim(g, Ustrlen(s)); + string_fmt_append_noextend(g, "%s", s); } } va_end(ap); @@ -1020,30 +1037,29 @@ va_end(ap); /* Add the raw, unrewritten, sender to the message if required. This is done this way because it kind of fits with LOG_RECIPIENTS. */ -if ( flags & LOG_SENDER - && g->ptr < LOG_BUFFER_SIZE - 10 - Ustrlen(raw_sender)) - g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " from <%s>", raw_sender); +if (flags & LOG_SENDER) + string_fmt_append_noextend(g, " from <%s>", raw_sender); /* Add list of recipients to the message if required; the raw list, before rewriting, was saved in raw_recipients. There may be none, if an ACL discarded them all. */ -if ( flags & LOG_RECIPIENTS - && g->ptr < LOG_BUFFER_SIZE - 6 - && raw_recipients_count > 0) +if (flags & LOG_RECIPIENTS && raw_recipients_count > 0) { - g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " for", NULL); + string_fmt_append_noextend(g, " for"); for (int i = 0; i < raw_recipients_count; i++) - { - const uschar * s = raw_recipients[i]; - if (LOG_BUFFER_SIZE - g->ptr < Ustrlen(s) + 3) break; - g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s", s); + if (!string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s", raw_recipients[i])) + { + uschar * s = US""; + gstring_trim(g, Ustrlen(s)); + string_fmt_append_noextend(g, "%s", s); + break; } } /* actual size, now we are placing the newline (and space for NUL) */ gs.size = LOG_BUFFER_SIZE; -g = string_catn(g, US"\n", 1); +string_fmt_append_noextend(g, "\n"); string_from_gstring(g); /* Handle loggable errors when running a utility, or when address testing. @@ -1117,8 +1133,7 @@ if ( flags & LOG_MAIN /* Failing to write to the log is disastrous */ - written_len = write_gstring_to_fd_buf(mainlogfd, g); - if (written_len != g->ptr) + if ((written_len = write_gstring_to_fd_buf(mainlogfd, g)) != g->ptr) { log_write_failed(US"main log", g->ptr, written_len); /* That function does not return */ @@ -1135,53 +1150,39 @@ if (flags & LOG_REJECT) { if (header_list && LOGGING(rejected_header)) { - gstring * g2; int i; if (recipients_count > 0) { /* List the sender */ - g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, + string_fmt_append_noextend(g, "Envelope-from: <%s>\n", sender_address); - if (g2) g = g2; /* List up to 5 recipients */ - g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, + string_fmt_append_noextend(g, "Envelope-to: <%s>\n", recipients_list[0].address); - if (g2) g = g2; for (i = 1; i < recipients_count && i < 5; i++) - { - g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, + string_fmt_append_noextend(g, " <%s>\n", recipients_list[i].address); - if (g2) g = g2; - } if (i < recipients_count) - { - g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " ...\n", NULL); - if (g2) g = g2; - } + string_fmt_append_noextend(g, " ...\n", NULL); } - /* A header with a NULL text is an unfilled in Received: header */ + /* A header with a NULL text is an unfilled-in Received: header */ for (header_line * h = header_list; h; h = h->next) if (h->text) - { - g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, - "%c %s", h->type, h->text); - if (g2) - g = g2; - else /* Buffer is full; truncate */ - { - gstring_trim(g, 100); /* For message and separator */ + if (!string_fmt_append_f(g, SVFMT_TAINT_NOCHK, + "%c %s", h->type, h->text)) + { /* Buffer is full; truncate */ + gstring_trim(g, 100); /* space for message and separator */ gstring_trim_trailing(g, '\n'); - g = string_cat(g, US"\n*** truncated ***\n"); + string_fmt_append_noextend(g, "\n*** truncated ***\n"); break; } - } } /* Write to syslog or to a log file */ @@ -1232,8 +1233,7 @@ if (flags & LOG_REJECT) if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino; } - written_len = write_gstring_to_fd_buf(rejectlogfd, g); - if (written_len != g->ptr) + if ((written_len = write_gstring_to_fd_buf(rejectlogfd, g)) != g->ptr) { log_write_failed(US"reject log", g->ptr, written_len); /* That function does not return */ @@ -1267,8 +1267,7 @@ if (flags & LOG_PANIC) if (panic_save_buffer) (void) write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer)); - written_len = write_gstring_to_fd_buf(paniclogfd, g); - if (written_len != g->ptr) + if ((written_len = write_gstring_to_fd_buf(paniclogfd, g)) != g->ptr) { int save_errno = errno; write_syslog(LOG_CRIT, log_buffer); @@ -1562,3 +1561,5 @@ if (kill) unlink_log(lt_debug); /* End of log.c */ +/* vi: sw ai sw=2 +*/ diff --git a/src/src/string.c b/src/src/string.c index 379be2035..baa19f426 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1333,7 +1333,7 @@ Arguments: ap variable-args pointer Flags: - SVFMT_EXTEND buffer can be created or exteded as needed + SVFMT_EXTEND buffer can be created or extended as needed SVFMT_REBUFFER buffer can be recopied to tainted mem as needed SVFMT_TAINT_NOCHK do not check inputs for taint commit ad64ad24d66f32af7af302b625f7a7be0ac6b988 Author: Jeremy Harris Date: Fri Mar 29 20:42:47 2024 +0000 inlining diff --git a/src/src/functions.h b/src/src/functions.h index d811c62a3..b2f948650 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -567,7 +567,6 @@ extern gstring *string_append_listele_n(gstring *, uschar, const uschar *, unsig extern gstring *string_append2_listele_n(gstring *, const uschar *, const uschar *, unsigned) WARN_UNUSED_RESULT; extern uschar *string_base62_32(unsigned long int); extern uschar *string_base62_64(unsigned long int); -extern gstring *string_cat (gstring *, const uschar * ) WARN_UNUSED_RESULT; extern gstring *string_catn(gstring *, const uschar *, int) WARN_UNUSED_RESULT; extern int string_compare_by_pointer(const void *, const void *); extern uschar *string_copy_dnsdomain(uschar *); @@ -1050,6 +1049,18 @@ if (g) store_release_above_3(g->s + (g->size = g->ptr + 1), file, line); } +/* plain string append to a growable-string */ + +static inline gstring * string_cat(gstring * g, const uschar * s) + WARN_UNUSED_RESULT; + +static inline gstring * +string_cat(gstring * g, const uschar * s) +{ +return string_catn(g, s, Ustrlen(s)); +} + + /* sprintf-append to a growable-string */ #define string_fmt_append(g, fmt, ...) \ @@ -1085,6 +1096,7 @@ g->s = s; } /* Append one gstring to another */ + static inline gstring * gstring_append(gstring * dest, gstring * item) { diff --git a/src/src/string.c b/src/src/string.c index baa19f426..cd76e1f1c 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1234,13 +1234,6 @@ return g; } -gstring * -string_cat(gstring * g, const uschar * s) -{ -return string_catn(g, s, Ustrlen(s)); -} - - /************************************************* * Append strings to another string * commit 5e0ccec4397bd2d21cc1473681a62e7c2fb6afbe Author: Jeremy Harris Date: Thu Apr 4 15:53:53 2024 +0100 Retries: rework DB keys, and fix exinext IPv6. Bug 3086 diff --git a/src/src/deliver.c b/src/src/deliver.c index 70f44535f..0157743a1 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -2039,7 +2039,7 @@ static BOOL previously_transported(address_item *addr, BOOL testing) { uschar * s = string_sprintf("%s/%s", - addr->unique + (testflag(addr, af_homonym)? 3:0), addr->transport->name); + addr->unique + (testflag(addr, af_homonym) ? 3:0), addr->transport->name); if (tree_search(tree_nonrecipients, s) != 0) { @@ -3142,7 +3142,7 @@ while (addr_local) if (result == DEFER || testflag(addr2, af_lt_retry_exists)) { int flags = result == DEFER ? 0 : rf_delete; - uschar *retry_key = string_copy(tp->retry_use_local_part + uschar * retry_key = string_copy(tp->retry_use_local_part ? addr2->address_retry_key : addr2->domain_retry_key); *retry_key = 'T'; retry_add_item(addr2, retry_key, flags); @@ -7292,7 +7292,7 @@ while (addr_new) /* Loop until all addresses dealt with */ addr->unique = string_sprintf("%s:%s", addr->address, addr->parent->unique + - (testflag(addr->parent, af_homonym)? 3:0)); + (testflag(addr->parent, af_homonym) ? 3:0)); addr->address_retry_key = addr->domain_retry_key = string_sprintf("T:%s", addr->unique); @@ -7729,7 +7729,7 @@ while (addr_new) /* Loop until all addresses dealt with */ else if (testflag(addr, af_dr_retry_exists)) { - uschar *altkey = string_sprintf("%s:<%s>", addr->address_retry_key, + uschar * altkey = string_sprintf("%s:<%s>", addr->address_retry_key, sender_address); retry_add_item(addr, altkey, rf_delete); retry_add_item(addr, addr->address_retry_key, rf_delete); diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 4d213773b..c868832b1 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -628,7 +628,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); print_time(retry->first_failed)); printf("%s ", print_time(retry->last_try)); printf("%s %s\n", print_time(retry->next_try), - (retry->expired)? "*" : ""); + retry->expired ? "*" : ""); break; case type_wait: diff --git a/src/src/exinext.src b/src/src/exinext.src index 882ad5f60..5724812c4 100644 --- a/src/src/exinext.src +++ b/src/src/exinext.src @@ -195,45 +195,18 @@ perl - $exim_path "$eximmacdef" $argone $spool_directory $qualify_domain $config $printed = 1; if (/^\s*T:[^:\s]*:/) { + # We rely on non-space-containing strings, for parsing + ($key,$error,$error2,$text) = /^\s*T:(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/; - # Parsing the keys is a nightmare because of IPv6. The design of the - # format for the keys is a complete shambles. All my fault (PH). But - # I don't want to change it just for this purpose. If they key - # contains more than 3 colons, we have an IPv6 address, because - # an IPv6 address must contain at least two colons. - - # Deal with IPv4 addresses (3 colons or fewer) - - if ($key !~ /:([^:]*?:){3}/) - { - ($host,$ip,$port,$msgid) = $key =~ - /^([^:]*):([^:]*)(?::([^:]*)(?::(\S*)|)|)/; - } - - # Deal with IPv6 addresses; sorting out the colons is a complete - # mess. We should be able to find the host name and IP address from - # further in the message. That seems the easiest escape plan here. We - # can use those to match the rest of the key. - - else - { - ($host,$ip) = $text =~ /host\s(\S+)\s\[([^]]+)\]/; - if (defined $host) - { - ($port,$msgid) = $key =~ - /^$host:$ip(?::([^:]*)(?::(\S*)|)|)/; - } - - # This will probably be wrong... - - else - { - ($host,$ip) = $key =~ /([^:]*):(.*)/; - } - } - - printf("Transport: %s [%s]", $host, $ip); + ($host,$ip,$port,$msgid) = $key =~ + /^([^:[]*|\[[^]]*\]) # host (could be an ip) + :([^:[]*|\[[^]]*\]) # ip + (?::(\d{1,5}))? # maybe port + (?::(\S{23}))? # maybe msgid + $/x; + + printf("Transport: %s %s", $host, $ip); print ":$port" if defined $port; print " $msgid" if defined $msgid; print " error $error: $text\n"; diff --git a/src/src/functions.h b/src/src/functions.h index b2f948650..9f6396a17 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -454,11 +454,14 @@ extern BOOL regex_match_and_setup(const pcre2_code *, const uschar *, int, in extern const pcre2_code *regex_compile(const uschar *, mcs_flags, uschar **, pcre2_compile_context *); extern const pcre2_code *regex_must_compile(const uschar *, mcs_flags, BOOL); -extern void retry_add_item(address_item *, uschar *, int); + +extern void retry_add_item(address_item *, const uschar *, int); extern BOOL retry_check_address(const uschar *, host_item *, uschar *, BOOL, - uschar **, uschar **); + const uschar **, const uschar **); extern retry_config *retry_find_config(const uschar *, const uschar *, int, int); -extern BOOL retry_ultimate_address_timeout(uschar *, const uschar *, +extern const uschar *retry_host_key_build(const host_item *, BOOL, + const uschar *); +extern BOOL retry_ultimate_address_timeout(const uschar *, const uschar *, dbdata_retry *, time_t); extern void retry_update(address_item **, address_item **, address_item **); extern const uschar *rewrite_address(const uschar *, BOOL, BOOL, rewrite_rule *, int); diff --git a/src/src/retry.c b/src/src/retry.c index 42393d424..6b977dd58 100644 --- a/src/src/retry.c +++ b/src/src/retry.c @@ -31,7 +31,7 @@ Returns: TRUE if the ultimate timeout has been reached */ BOOL -retry_ultimate_address_timeout(uschar *retry_key, const uschar *domain, +retry_ultimate_address_timeout(const uschar * retry_key, const uschar *domain, dbdata_retry *retry_record, time_t now) { BOOL address_timeout; @@ -75,6 +75,29 @@ return address_timeout; +const uschar * +retry_host_key_build(const host_item * host, BOOL incl_ip, + const uschar * portstring) +{ +const uschar * s = host->name; +gstring * g = string_is_ip_address(s, NULL) + ? string_fmt_append(NULL, "T:[%s]", s) /* wrap a name which is a bare ip */ + : string_fmt_append(NULL, "T:%s", s); + +s = host->address; +if (incl_ip) + g = Ustrchr(s, ':') + ? string_fmt_append(g, ":[%s]", s) /* wrap an ipv6 */ + : string_fmt_append(g, ":%s", s); + +if (portstring) + g = string_cat(g, portstring); + +gstring_release_unused(g); +return string_from_gstring(g); +} + + /************************************************* * Set status of a host+address item * *************************************************/ @@ -124,11 +147,12 @@ Returns: TRUE if the host has expired but is usable because BOOL retry_check_address(const uschar *domain, host_item *host, uschar *portstring, - BOOL include_ip_address, uschar **retry_host_key, uschar **retry_message_key) + BOOL include_ip_address, + const uschar **retry_host_key, const uschar **retry_message_key) { BOOL yield = FALSE; time_t now = time(NULL); -uschar * host_key, * message_key; +const uschar * host_key, * message_key; open_db dbblock, * dbm_file; tree_node * node; dbdata_retry * host_retry_record, * message_retry_record; @@ -143,14 +167,11 @@ if (host->status != hstatus_unknown) return FALSE; host->status = hstatus_usable; /* Generate the host key for the unusable tree and the retry database. Ensure -host names are lower cased (that's what %S does). */ - -host_key = include_ip_address - ? string_sprintf("T:%S:%s%s", host->name, host->address, portstring) - : string_sprintf("T:%S%s", host->name, portstring); - -/* Generate the message-specific key */ +host names are lower cased (that's what %S does). +Generate the message-specific key too. +Be sure to maintain lack-of-spaces in retry keys; exinext depends on it. */ +host_key = retry_host_key_build(host, include_ip_address, portstring); message_key = string_sprintf("%s:%s", host_key, message_id); /* Search the tree of unusable IP addresses. This is filled in when deliveries @@ -290,7 +311,7 @@ Returns: nothing */ void -retry_add_item(address_item *addr, uschar *key, int flags) +retry_add_item(address_item * addr, const uschar * key, int flags) { retry_item * rti = store_get(sizeof(retry_item), GET_UNTAINTED); host_item * host = addr->host_used; @@ -343,11 +364,11 @@ Returns: pointer to retry rule, or NULL */ retry_config * -retry_find_config(const uschar *key, const uschar *alternate, int basic_errno, +retry_find_config(const uschar * key, const uschar * alternate, int basic_errno, int more_errno) { -const uschar *colon = Ustrchr(key, ':'); -retry_config *yield; +const uschar * colon = Ustrchr(key, ':'); +retry_config * yield; /* If there's a colon in the key, there are two possibilities: @@ -355,7 +376,8 @@ retry_config *yield; hostname:ip+port - In this case, we copy the host name. + In this case, we copy the host name (which could be an [ip], including + being an [ipv6], and we drop the []). (2) This is a key for a pipe, file, or autoreply delivery, in the format @@ -369,6 +391,8 @@ retry_config *yield; if (colon) key = isalnum(*key) ? string_copyn(key, colon-key) /* the hostname */ + : *key == '[' + ? string_copyn(key+1, Ustrchr(key, ']')-1-key) /* the ip */ : Ustrrchr(key, ':') + 1; /* Take from the last colon */ /* Sort out the keys */ @@ -932,3 +956,5 @@ DEBUG(D_retry) debug_printf("end of retry processing\n"); } /* End of retry.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/string.c b/src/src/string.c index cd76e1f1c..a627611af 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1698,7 +1698,7 @@ while (*fp) } /* If a width is not specified and the precision is specified, set - the width to the precision, or the string length if shorted. */ + the width to the precision, or the string length if shorter. */ else if (precision >= 0) width = precision < slen ? precision : slen; diff --git a/src/src/structs.h b/src/src/structs.h index b16a8a3f2..8aab54055 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -480,7 +480,7 @@ can be tried. */ typedef struct retry_item { struct retry_item *next; /* for chaining */ - uschar *key; /* string identifying host/address/message */ + const uschar *key; /* string identifying host/address/message */ int basic_errno; /* error code for this destination */ int more_errno; /* additional error information */ uschar *message; /* local error message */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index ed5994241..a5f99edaa 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -1306,7 +1306,7 @@ while (count-- > 0) if (testflag(addr, af_dr_retry_exists)) { - uschar *altkey = string_sprintf("%s:<%s>", addr->address_retry_key, + uschar * altkey = string_sprintf("%s:<%s>", addr->address_retry_key, sender_address); retry_add_item(addr, altkey, rf_delete); retry_add_item(addr, addr->address_retry_key, rf_delete); @@ -1322,7 +1322,7 @@ while (count-- > 0) else if (errno == ETIMEDOUT) { - uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>", + uschar * message = string_sprintf("SMTP timeout after RCPT TO:<%s>", transport_rcpt_address(addr, sx->conn_args.tblock->rcpt_include_affixes)); set_errno_nohost(sx->first_addr, ETIMEDOUT, message, DEFER, FALSE, &sx->delivery_start); retry_add_item(addr, addr->address_retry_key, 0); @@ -5376,7 +5376,7 @@ retry_non_continued: BOOL host_is_expired = FALSE, message_defer = FALSE, some_deferred = FALSE; address_item * first_addr = NULL; uschar * interface = NULL; - uschar * retry_host_key = NULL, * retry_message_key = NULL; + const uschar * retry_host_key = NULL, * retry_message_key = NULL; uschar * serialize_key = NULL; /* Deal slightly better with a possible Linux kernel bug that results @@ -5873,9 +5873,7 @@ retry_non_continued: ob->expand_retry_include_ip_address, &incl_ip) != OK) incl_ip = TRUE; /* error; use most-specific retry record */ - retry_host_key = incl_ip - ? string_sprintf("T:%S:%s%s", host->name, host->address, pistring) - : string_sprintf("T:%S%s", host->name, pistring); + retry_host_key = retry_host_key_build(host, incl_ip, pistring); } /* If a delivery of another message over an existing SMTP connection @@ -5921,10 +5919,8 @@ retry_non_continued: ob->expand_retry_include_ip_address, &incl_ip) != OK) incl_ip = TRUE; /* error; use most-specific retry record */ - retry_message_key = incl_ip - ? string_sprintf("T:%S:%s%s:%s", host->name, host->address, pistring, - message_id) - : string_sprintf("T:%S%s:%s", host->name, pistring, message_id); + retry_message_key = string_sprintf("%s:%s", + retry_host_key_build(host, incl_ip, pistring), message_id); } retry_add_item(addrlist, retry_message_key, rf_message | rf_host | delete_flag); diff --git a/src/src/tree.c b/src/src/tree.c index eb54829db..2c703583e 100644 --- a/src/src/tree.c +++ b/src/src/tree.c @@ -65,6 +65,7 @@ if (!tree_insertnode(&tree_duplicates, node)) store_reset(rpoint); +#ifndef COMPILE_UTILITY /************************************************* * Add entry to unusable addresses tree * *************************************************/ @@ -76,12 +77,11 @@ Returns: nothing */ void -tree_add_unusable(const host_item *h) +tree_add_unusable(const host_item * h) { rmark rpoint = store_mark(); -tree_node *node; -uschar s[256]; -sprintf(CS s, "T:%.200s:%s", h->name, h->address); +tree_node * node; +const uschar * s = retry_host_key_build(h, TRUE, NULL); node = store_get(sizeof(tree_node) + Ustrlen(s), is_tainted(h->name) || is_tainted(h->address) ? GET_TAINTED : GET_UNTAINTED); Ustrcpy(node->name, s); @@ -89,7 +89,7 @@ node->data.val = h->why; if (h->status == hstatus_unusable_expired) node->data.val += 256; if (!tree_insertnode(&tree_unusable, node)) store_reset(rpoint); } - +#endif /************************************************* commit 9ae8613607b12257e1fe59c603119bc5d4cd3474 Author: Daniel Golle Date: Fri Apr 5 00:39:56 2024 +0100 Debug: use difftime() diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index a5f99edaa..ddd6ad7e1 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -945,7 +945,8 @@ if ( sx->early_pipe_active if (!(er = dbfn_read_enforce_length(dbm_file, ehlo_resp_key, sizeof(dbdata_ehlo_resp)))) debug_printf("no ehlo-resp record!\n"); else - debug_printf("ehlo-resp record is %d seconds old\n", time(NULL) - er->time_stamp); + debug_printf("ehlo-resp record is %.0f seconds old\n", + difftime(time(NULL), er->time_stamp)); } dbfn_delete(dbm_file, ehlo_resp_key); commit 86e5b23559e50f107620aefeb52f4a856f988421 Author: Jeremy Harris Date: Fri Apr 5 11:27:10 2024 +0100 SRS: fix encode for local-part with zero-length quoted element. Bug 3087 diff --git a/src/src/expand.c b/src/src/expand.c index 5ea4dc6d4..1d121756d 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -7117,7 +7117,7 @@ while (*s) gstring_release_unused(h); s = string_from_gstring(h); } - g = string_cat(g, s); + if (s) g = string_cat(g, s); } /* Assume that if the original local_part had quotes commit 8a5d7421f117c332c90b94bfd6f50ca71494d705 Author: Jeremy Harris Date: Wed Apr 10 17:10:05 2024 +0100 DMARC: Avoid using Resent-From: header. Bug 3029 diff --git a/src/src/receive.c b/src/src/receive.c index 9dbf45df9..9fae6ad60 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1748,7 +1748,7 @@ uschar *user_msg, *log_msg; /* Working header pointers */ rmark reset_point; -header_line *next; +header_line * next; /* Flags for noting the existence of certain headers (only one left) */ @@ -1756,15 +1756,16 @@ BOOL date_header_exists = FALSE; /* Pointers to receive the addresses of headers whose contents we need. */ -header_line *from_header = NULL; -header_line *subject_header = NULL; -header_line *msgid_header = NULL; -header_line *received_header; +header_line * from_header = NULL; +#ifdef SUPPORT_DMARC +header_line * dmarc_from_header = NULL; +#endif +header_line * subject_header = NULL, * msgid_header = NULL, * received_header; BOOL msgid_header_newly_created = FALSE; /* Variables for use when building the Received: header. */ -uschar *timestamp; +uschar * timestamp; int tslen; /* Time of creation of message_id */ @@ -2446,6 +2447,9 @@ for (header_line * h = header_list->next; h; h = h->next) case htype_from: h->type = htype_from; +#ifdef SUPPORT_DMARC + if (!is_resent) dmarc_from_header = h; +#endif if (!resents_exist || is_resent) { from_header = h; @@ -3619,7 +3623,7 @@ else #endif /* WITH_CONTENT_SCAN */ #ifdef SUPPORT_DMARC - dmarc_store_data(from_header); + dmarc_store_data(dmarc_from_header); #endif #ifndef DISABLE_PRDR @@ -4622,3 +4626,5 @@ return yield; /* TRUE if more messages (SMTP only) */ } /* End of receive.c */ +/* vi: se aw ai sw=2 +*/ commit e4cdc6558fcf05e3923442ec7831adbe58c3e7a7 Author: Jeremy Harris Date: Thu Apr 11 11:53:24 2024 +0100 Use compressed form of ipv6 in $sender_host_address under -bh. Bug 3027 diff --git a/src/src/exim.c b/src/src/exim.c index 5c9e64021..040df2cd0 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -2339,9 +2339,9 @@ on the second character (the one after '-'), to save some effort. */ /* -bh: Host checking - an IP address must follow. */ case 'h': - if (!*argrest || Ustrcmp(argrest, "c") == 0) + if ( (!*argrest || Ustrcmp(argrest, "c") == 0) + && ++i < argc) { - if (++i >= argc) { badarg = TRUE; break; } sender_host_address = string_copy_taint( exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-bh"), GET_TAINTED); @@ -2349,7 +2349,8 @@ on the second character (the one after '-'), to save some effort. */ f.host_checking_callout = *argrest == 'c'; message_logs = FALSE; } - else badarg = TRUE; + else + badarg = TRUE; break; /* -bi: This option is used by sendmail to initialize *the* alias file, @@ -5443,11 +5444,14 @@ if (host_checking) } /* In case the given address is a non-canonical IPv6 address, canonicalize - it. The code works for both IPv4 and IPv6, as it happens. */ + it. Use the compressed form for IPv6. */ size = host_aton(sender_host_address, x); sender_host_address = store_get(48, GET_UNTAINTED); /* large enough for full IPv6 */ - (void)host_nmtoa(size, x, -1, sender_host_address, ':'); + if (size == 1) + (void) host_nmtoa(size, x, -1, sender_host_address, ':'); + else + (void) ipv6_nmtoa(x, sender_host_address); /* Now set up for testing */ @@ -6189,3 +6193,5 @@ return 0; /* To stop compiler warning */ /* End of exim.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/functions.h b/src/src/functions.h index 9f6396a17..f0b600ccc 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -311,7 +311,7 @@ extern BOOL host_is_tls_on_connect_port(int); extern int host_item_get_port(host_item *); extern void host_mask(int, int *, int); extern int host_name_lookup(void); -extern int host_nmtoa(int, int *, int, uschar *, int); +extern int host_nmtoa(int, const int *, int, uschar *, int); extern uschar *host_ntoa(int, const void *, uschar *, int *); extern int host_scan_for_local_hosts(host_item *, host_item **, BOOL *); diff --git a/src/src/host.c b/src/src/host.c index 08e946548..381f2a5fc 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -1061,19 +1061,15 @@ Returns: the number of characters placed in buffer, not counting */ int -host_nmtoa(int count, int *binary, int mask, uschar *buffer, int sep) +host_nmtoa(int count, const int * binary, int mask, uschar * buffer, int sep) { -int j; -uschar *tt = buffer; +uschar * tt = buffer; if (count == 1) - { - j = binary[0]; - for (int i = 24; i >= 0; i -= 8) + for (int j = binary[0], i = 24; i >= 0; i -= 8) tt += sprintf(CS tt, "%d.", (j >> i) & 255); - } else - for (int i = 0; i < 4; i++) + for (int j, i = 0; i < 4; i++) { j = binary[i]; tt += sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep); commit cfc6689a7a29220a44457961283773fdbfdce3ef Author: Jeremy Harris Date: Sun Apr 14 10:04:37 2024 +0100 tidying diff --git a/src/src/filter.c b/src/src/filter.c index 18567f17c..8f29eda3e 100644 --- a/src/src/filter.c +++ b/src/src/filter.c @@ -71,35 +71,6 @@ enum { had_neither, had_else, had_elif, had_endif }; static BOOL read_command_list(const uschar **, filter_cmd ***, BOOL); -/* The string arguments for the mail command. The header line ones (that are -permitted to include \n followed by white space) first, and then the body text -one (it can have \n anywhere). Then the file names and once_repeat, which may -not contain \n. */ - -static const char *mailargs[] = { /* "to" must be first, and */ - "to", /* "cc" and "bcc" must follow */ - "cc", - "bcc", - "from", - "reply_to", - "subject", - "extra_headers", /* miscellaneous added header lines */ - "text", - "file", - "log", - "once", - "once_repeat" -}; - -/* The count of string arguments */ - -#define MAILARGS_STRING_COUNT (nelem(mailargs)) - -/* The count of string arguments that are actually passed over as strings -(once_repeat is converted to an int). */ - -#define mailargs_string_passed (MAILARGS_STRING_COUNT - 1) - /* This defines the offsets for the arguments; first the string ones, and then the non-string ones. The order must be as above. */ @@ -120,21 +91,50 @@ enum { mailarg_index_to, mailargs_total /* total number of arguments */ }; +/* The string arguments for the mail command. The header line ones (that are +permitted to include \n followed by white space) first, and then the body text +one (it can have \n anywhere). Then the file names and once_repeat, which may +not contain \n. */ + +static const char *mailargs[] = { /* "to" must be first, and */ + [mailarg_index_to] = "to", /* "cc" and "bcc" must follow */ + [mailarg_index_cc] = "cc", + [mailarg_index_bcc] = "bcc", + [mailarg_index_from] = "from", + [mailarg_index_reply_to] = "reply_to", + [mailarg_index_subject] = "subject", + [mailarg_index_headers] = "extra_headers", /* misc added header lines */ + [mailarg_index_text] = "text", + [mailarg_index_file] = "file", + [mailarg_index_log] = "log", + [mailarg_index_once] = "once", + [mailarg_index_once_repeat] = "once_repeat" +}; + +/* The count of string arguments */ + +#define MAILARGS_STRING_COUNT (nelem(mailargs)) + +/* The count of string arguments that are actually passed over as strings +(once_repeat is converted to an int). */ + +#define mailargs_string_passed (MAILARGS_STRING_COUNT - 1) + /* Offsets in the data structure for the string arguments (note that once_repeat isn't a string argument at this point.) */ -static int reply_offsets[] = { /* must be in same order as above */ - offsetof(reply_item, to), - offsetof(reply_item, cc), - offsetof(reply_item, bcc), - offsetof(reply_item, from), - offsetof(reply_item, reply_to), - offsetof(reply_item, subject), - offsetof(reply_item, headers), - offsetof(reply_item, text), - offsetof(reply_item, file), - offsetof(reply_item, logfile), - offsetof(reply_item, oncelog), +static int reply_offsets[] = { + [mailarg_index_to] = offsetof(reply_item, to), + [mailarg_index_cc] = offsetof(reply_item, cc), + [mailarg_index_bcc] = offsetof(reply_item, bcc), + [mailarg_index_from] = offsetof(reply_item, from), + [mailarg_index_reply_to] = offsetof(reply_item, reply_to), + [mailarg_index_subject] = offsetof(reply_item, subject), + [mailarg_index_headers] = offsetof(reply_item, headers), + [mailarg_index_text] = offsetof(reply_item, text), + [mailarg_index_file] = offsetof(reply_item, file), + [mailarg_index_log] = offsetof(reply_item, logfile), + [mailarg_index_once] = offsetof(reply_item, oncelog), }; /* Condition identities and names, with negated versions for some @@ -147,20 +147,48 @@ enum { cond_and, cond_or, cond_personal, cond_begins, cond_BEGINS, cond_manualthaw, cond_foranyaddress }; static const char *cond_names[] = { - "and", "or", "personal", - "begins", "BEGINS", "ends", "ENDS", - "is", "IS", "matches", "MATCHES", "contains", - "CONTAINS", "delivered", "above", "below", "error_message", - "first_delivery", "manually_thawed", "foranyaddress" }; + [cond_and] = "and", + [cond_or] = "or", + [cond_personal] = "personal", + [cond_begins] = "begins", + [cond_BEGINS] = "BEGINS", + [cond_ends] = "ends", + [cond_ENDS] = "ENDS", + [cond_is] = "is", + [cond_IS] = "IS", + [cond_matches] = "matches", + [cond_MATCHES] = "MATCHES", + [cond_contains] = "contains", + [cond_CONTAINS] = "CONTAINS", + [cond_delivered] = "delivered", + [cond_above] = "above", + [cond_below] = "below", + [cond_errormsg] = "error_message", + [cond_firsttime] = "first_delivery", + [cond_manualthaw] = "manually_thawed", + [cond_foranyaddress] = "foranyaddress" }; static const char *cond_not_names[] = { - "", "", "not personal", - "does not begin", "does not BEGIN", - "does not end", "does not END", - "is not", "IS not", "does not match", - "does not MATCH", "does not contain", "does not CONTAIN", - "not delivered", "not above", "not below", "not error_message", - "not first_delivery", "not manually_thawed", "not foranyaddress" }; + [cond_and] = "", + [cond_or] = "", + [cond_personal] = "not personal", + [cond_begins] = "does not begin", + [cond_BEGINS] = "does not BEGIN", + [cond_ends] = "does not end", + [cond_ENDS] = "does not END", + [cond_is] = "is not", + [cond_IS] = "IS not", + [cond_matches] = "does not match", + [cond_MATCHES] = "does not MATCH", + [cond_contains] = "does not contain", + [cond_CONTAINS] = "does not CONTAIN", + [cond_delivered] = "not delivered", + [cond_above] = "not above", + [cond_below] = "not below", + [cond_errormsg] = "not error_message", + [cond_firsttime] = "not first_delivery", + [cond_manualthaw] = "not manually_thawed", + [cond_foranyaddress] = "not foranyaddress" }; /* Tables of binary condition words and their corresponding types. Not easy to amalgamate with the above because of the different variants. */ @@ -196,34 +224,34 @@ static int cond_types[] = { cond_BEGINS, cond_BEGINS, cond_CONTAINS, /* Command identities */ -enum { add_command, defer_command, deliver_command, elif_command, else_command, - endif_command, finish_command, fail_command, freeze_command, - headers_command, if_command, logfile_command, logwrite_command, - mail_command, noerror_command, pipe_command, save_command, seen_command, - testprint_command, unseen_command, vacation_command }; +enum { ADD_COMMAND, DEFER_COMMAND, DELIVER_COMMAND, ELIF_COMMAND, ELSE_COMMAND, + ENDIF_COMMAND, FINISH_COMMAND, FAIL_COMMAND, FREEZE_COMMAND, + HEADERS_COMMAND, IF_COMMAND, LOGFILE_COMMAND, LOGWRITE_COMMAND, + MAIL_COMMAND, NOERROR_COMMAND, PIPE_COMMAND, SAVE_COMMAND, SEEN_COMMAND, + TESTPRINT_COMMAND, UNSEEN_COMMAND, VACATION_COMMAND }; static const char * command_list[] = { - [add_command] = "add", - [defer_command] = "defer", - [deliver_command] = "deliver", - [elif_command] = "elif", - [else_command] = "else", - [endif_command] = "endif", - [finish_command] = "finish", - [fail_command] = "fail", - [freeze_command] = "freeze", - [headers_command] = "headers", - [if_command] = "if", - [logfile_command] = "logfile", - [logwrite_command] = "logwrite", - [mail_command] = "mail", - [noerror_command] = "noerror", - [pipe_command] = "pipe", - [save_command] = "save", - [seen_command] = "seen", - [testprint_command] = "testprint", - [unseen_command] = "unseen", - [vacation_command] = "vacation" + [ADD_COMMAND] = "add", + [DEFER_COMMAND] = "defer", + [DELIVER_COMMAND] = "deliver", + [ELIF_COMMAND] = "elif", + [ELSE_COMMAND] = "else", + [ENDIF_COMMAND] = "endif", + [FINISH_COMMAND] = "finish", + [FAIL_COMMAND] = "fail", + [FREEZE_COMMAND] = "freeze", + [HEADERS_COMMAND] = "headers", + [IF_COMMAND] = "if", + [LOGFILE_COMMAND] = "logfile", + [LOGWRITE_COMMAND] = "logwrite", + [MAIL_COMMAND] = "mail", + [NOERROR_COMMAND] = "noerror", + [PIPE_COMMAND] = "pipe", + [SAVE_COMMAND] = "save", + [SEEN_COMMAND] = "seen", + [TESTPRINT_COMMAND] = "testprint", + [UNSEEN_COMMAND] = "unseen", + [VACATION_COMMAND] = "vacation" }; static int command_list_count = nelem(command_list); @@ -232,27 +260,27 @@ static int command_list_count = nelem(command_list); If the top bit is set, it means that the default for the command is "seen". */ static uschar command_exparg_count[] = { - [add_command] = 2, - [defer_command] = 1, - [deliver_command] = 128+2, - [elif_command] = 0, - [else_command] = 0, - [endif_command] = 0, - [finish_command] = 0, - [fail_command] = 1, - [freeze_command] = 1, - [headers_command] = 1, - [if_command] = 0, - [logfile_command] = 1, - [logwrite_command] = 1, - [mail_command] = MAILARGS_STRING_COUNT, - [noerror_command] = 0, - [pipe_command] = 128+0, - [save_command] = 128+1, - [seen_command] = 0, - [testprint_command] = 1, - [unseen_command] = 0, - [vacation_command] = MAILARGS_STRING_COUNT + [ADD_COMMAND] = 2, + [DEFER_COMMAND] = 1, + [DELIVER_COMMAND] = 128+2, + [ELIF_COMMAND] = 0, + [ELSE_COMMAND] = 0, + [ENDIF_COMMAND] = 0, + [FINISH_COMMAND] = 0, + [FAIL_COMMAND] = 1, + [FREEZE_COMMAND] = 1, + [HEADERS_COMMAND] = 1, + [IF_COMMAND] = 0, + [LOGFILE_COMMAND] = 1, + [LOGWRITE_COMMAND] = 1, + [MAIL_COMMAND] = MAILARGS_STRING_COUNT, + [NOERROR_COMMAND] = 0, + [PIPE_COMMAND] = 128+0, + [SAVE_COMMAND] = 128+1, + [SEEN_COMMAND] = 0, + [TESTPRINT_COMMAND] = 1, + [UNSEEN_COMMAND] = 0, + [VACATION_COMMAND] = MAILARGS_STRING_COUNT }; @@ -795,8 +823,8 @@ switch(c->type) case cond_errormsg: case cond_firsttime: case cond_manualthaw: - debug_printf("%s", name); - break; + debug_printf("%s", name); + break; case cond_is: case cond_IS: @@ -810,31 +838,31 @@ switch(c->type) case cond_ENDS: case cond_above: case cond_below: - debug_printf("%s %s %s", c->left.u, name, c->right.u); - break; + debug_printf("%s %s %s", c->left.u, name, c->right.u); + break; case cond_and: - if (!c->testfor) debug_printf("not ("); - print_condition(c->left.c, FALSE); - debug_printf(" %s ", cond_names[c->type]); - print_condition(c->right.c, FALSE); - if (!c->testfor) debug_printf(")"); - break; + if (!c->testfor) debug_printf("not ("); + print_condition(c->left.c, FALSE); + debug_printf(" %s ", cond_names[c->type]); + print_condition(c->right.c, FALSE); + if (!c->testfor) debug_printf(")"); + break; case cond_or: - if (!c->testfor) debug_printf("not ("); - else if (!toplevel) debug_printf("("); - print_condition(c->left.c, FALSE); - debug_printf(" %s ", cond_names[c->type]); - print_condition(c->right.c, FALSE); - if (!toplevel || !c->testfor) debug_printf(")"); - break; + if (!c->testfor) debug_printf("not ("); + else if (!toplevel) debug_printf("("); + print_condition(c->left.c, FALSE); + debug_printf(" %s ", cond_names[c->type]); + print_condition(c->right.c, FALSE); + if (!toplevel || !c->testfor) debug_printf(")"); + break; case cond_foranyaddress: - debug_printf("%s %s (", name, c->left.u); - print_condition(c->right.c, FALSE); - debug_printf(")"); - break; + debug_printf("%s %s (", name, c->left.u); + print_condition(c->right.c, FALSE); + debug_printf(")"); + break; } } @@ -904,15 +932,15 @@ switch (command) stored in the second argument slot. Neither may be preceded by seen, unseen or noerror. */ - case add_command: - case headers_command: - if (seen_force || noerror_force) - { - *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" " - "found before an \"%s\" command near line %d", - command_list[command], line_number); - yield = FALSE; - } + case ADD_COMMAND: + case HEADERS_COMMAND: + if (seen_force || noerror_force) + { + *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" " + "found before an \"%s\" command near line %d", + command_list[command], line_number); + yield = FALSE; + } /* Fall through */ /* Logwrite, logfile, pipe, and testprint all take a single argument, save @@ -920,303 +948,303 @@ switch (command) have "errors_to
" in a system filter, or in a user filter if the address is the current one. */ - case deliver_command: - case logfile_command: - case logwrite_command: - case pipe_command: - case save_command: - case testprint_command: + case DELIVER_COMMAND: + case LOGFILE_COMMAND: + case LOGWRITE_COMMAND: + case PIPE_COMMAND: + case SAVE_COMMAND: + case TESTPRINT_COMMAND: - ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); - if (!*buffer) - *error_pointer = string_sprintf("\"%s\" requires an argument " - "near line %d of filter file", command_list[command], line_number); + ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); + if (!*buffer) + *error_pointer = string_sprintf("\"%s\" requires an argument " + "near line %d of filter file", command_list[command], line_number); - if (*error_pointer) yield = FALSE; else - { - union argtypes argument, second_argument; + if (*error_pointer) yield = FALSE; else + { + union argtypes argument, second_argument; - argument.u = second_argument.u = NULL; + argument.u = second_argument.u = NULL; - if (command == add_command) - { - argument.u = string_copy(buffer); - ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); - if (!*buffer || Ustrcmp(buffer, "to") != 0) - *error_pointer = string_sprintf("\"to\" expected in \"add\" command " - "near line %d of filter file", line_number); - else - { - ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); - if (!*buffer) - *error_pointer = string_sprintf("value missing after \"to\" " - "near line %d of filter file", line_number); - else second_argument.u = string_copy(buffer); - } - } + if (command == ADD_COMMAND) + { + argument.u = string_copy(buffer); + ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); + if (!*buffer || Ustrcmp(buffer, "to") != 0) + *error_pointer = string_sprintf("\"to\" expected in \"add\" command " + "near line %d of filter file", line_number); + else + { + ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); + if (!*buffer) + *error_pointer = string_sprintf("value missing after \"to\" " + "near line %d of filter file", line_number); + else second_argument.u = string_copy(buffer); + } + } - else if (command == headers_command) - { - if (Ustrcmp(buffer, "add") == 0) - second_argument.b = TRUE; - else - if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE; - else - if (Ustrcmp(buffer, "charset") == 0) - second_argument.b = TRUE_UNSET; - else - { - *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" " - "expected after \"headers\" near line %d of filter file", - line_number); - yield = FALSE; - } + else if (command == HEADERS_COMMAND) + { + if (Ustrcmp(buffer, "add") == 0) + second_argument.b = TRUE; + else + if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE; + else + if (Ustrcmp(buffer, "charset") == 0) + second_argument.b = TRUE_UNSET; + else + { + *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" " + "expected after \"headers\" near line %d of filter file", + line_number); + yield = FALSE; + } - if (!f.system_filtering && second_argument.b != TRUE_UNSET) - { - *error_pointer = string_sprintf("header addition and removal is " - "available only in system filters: near line %d of filter file", - line_number); - yield = FALSE; - break; - } + if (!f.system_filtering && second_argument.b != TRUE_UNSET) + { + *error_pointer = string_sprintf("header addition and removal is " + "available only in system filters: near line %d of filter file", + line_number); + yield = FALSE; + break; + } - if (yield) - { - ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); - if (!*buffer) - *error_pointer = string_sprintf("value missing after \"add\", " - "\"remove\", or \"charset\" near line %d of filter file", - line_number); - else argument.u = string_copy(buffer); - } - } + if (yield) + { + ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); + if (!*buffer) + *error_pointer = string_sprintf("value missing after \"add\", " + "\"remove\", or \"charset\" near line %d of filter file", + line_number); + else argument.u = string_copy(buffer); + } + } - /* The argument for the logwrite command must end in a newline, and the save - and logfile commands can have an optional mode argument. The deliver - command can have an optional "errors_to
" for a system filter, - or for a user filter if the address is the user's address. Accept the - syntax here - the check is later. */ + /* The argument for the logwrite command must end in a newline, and the save + and logfile commands can have an optional mode argument. The deliver + command can have an optional "errors_to
" for a system filter, + or for a user filter if the address is the user's address. Accept the + syntax here - the check is later. */ - else - { - if (command == logwrite_command) - { - int len = Ustrlen(buffer); - if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n"); - } + else + { + if (command == LOGWRITE_COMMAND) + { + int len = Ustrlen(buffer); + if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n"); + } - argument.u = string_copy(buffer); + argument.u = string_copy(buffer); - if (command == save_command || command == logfile_command) - { - if (isdigit(*ptr)) - { - ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); - second_argument.i = (int)Ustrtol(buffer, NULL, 8); - } - else second_argument.i = -1; - } + if (command == SAVE_COMMAND || command == LOGFILE_COMMAND) + { + if (isdigit(*ptr)) + { + ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); + second_argument.i = (int)Ustrtol(buffer, NULL, 8); + } + else second_argument.i = -1; + } - else if (command == deliver_command) - { - const uschar *save_ptr = ptr; - ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); - if (Ustrcmp(buffer, "errors_to") == 0) - { - ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); - second_argument.u = string_copy(buffer); - } - else ptr = save_ptr; - } - } + else if (command == DELIVER_COMMAND) + { + const uschar *save_ptr = ptr; + ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); + if (Ustrcmp(buffer, "errors_to") == 0) + { + ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); + second_argument.u = string_copy(buffer); + } + else ptr = save_ptr; + } + } - /* Set up the command block. Seen defaults TRUE for delivery commands, - FALSE for logging commands, and it doesn't matter for testprint, as - that doesn't change the "delivered" status. */ + /* Set up the command block. Seen defaults TRUE for delivery commands, + FALSE for logging commands, and it doesn't matter for testprint, as + that doesn't change the "delivered" status. */ - if (*error_pointer) yield = FALSE; - else - { - new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED); - new->next = NULL; - **lastcmdptr = new; - *lastcmdptr = &(new->next); - new->command = command; - new->seen = seen_force? seen_value : command_exparg_count[command] >= 128; - new->noerror = noerror_force; - new->args[0] = argument; - new->args[1] = second_argument; + if (*error_pointer) yield = FALSE; + else + { + new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED); + new->next = NULL; + **lastcmdptr = new; + *lastcmdptr = &(new->next); + new->command = command; + new->seen = seen_force? seen_value : command_exparg_count[command] >= 128; + new->noerror = noerror_force; + new->args[0] = argument; + new->args[1] = second_argument; + } } - } - break; + break; /* Elif, else and endif just set a flag if expected. */ - case elif_command: - case else_command: - case endif_command: - if (seen_force || noerror_force) - { - *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" " - "near line %d is not followed by a command", line_number); - yield = FALSE; - } + case ELIF_COMMAND: + case ELSE_COMMAND: + case ENDIF_COMMAND: + if (seen_force || noerror_force) + { + *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" " + "near line %d is not followed by a command", line_number); + yield = FALSE; + } - if (expect_endif > 0) - had_else_endif = (command == elif_command)? had_elif : - (command == else_command)? had_else : had_endif; - else - { - *error_pointer = string_sprintf("unexpected \"%s\" command near " - "line %d of filter file", buffer, line_number); - yield = FALSE; - } - break; + if (expect_endif > 0) + had_else_endif = (command == ELIF_COMMAND)? had_elif : + (command == ELSE_COMMAND)? had_else : had_endif; + else + { + *error_pointer = string_sprintf("unexpected \"%s\" command near " + "line %d of filter file", buffer, line_number); + yield = FALSE; + } + break; /* Defer, freeze, and fail are available only if permitted. */ - case defer_command: - cmd_bit = RDO_DEFER; - goto DEFER_FREEZE_FAIL; + case DEFER_COMMAND: + cmd_bit = RDO_DEFER; + goto DEFER_FREEZE_FAIL; - case fail_command: - cmd_bit = RDO_FAIL; - goto DEFER_FREEZE_FAIL; + case FAIL_COMMAND: + cmd_bit = RDO_FAIL; + goto DEFER_FREEZE_FAIL; - case freeze_command: - cmd_bit = RDO_FREEZE; + case FREEZE_COMMAND: + cmd_bit = RDO_FREEZE; DEFER_FREEZE_FAIL: - if ((filter_options & cmd_bit) == 0) - { - *error_pointer = string_sprintf("filtering command \"%s\" is disabled: " - "near line %d of filter file", buffer, line_number); - yield = FALSE; - break; - } + if ((filter_options & cmd_bit) == 0) + { + *error_pointer = string_sprintf("filtering command \"%s\" is disabled: " + "near line %d of filter file", buffer, line_number); + yield = FALSE; + break; + } - /* A text message can be provided after the "text" keyword, or - as a string in quotes. */ + /* A text message can be provided after the "text" keyword, or + as a string in quotes. */ - saveptr = ptr; - ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); - if (*saveptr != '\"' && (!*buffer || Ustrcmp(buffer, "text") != 0)) - { - ptr = saveptr; - fmsg = US""; - } - else - { - if (*saveptr != '\"') - ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); - fmsg = string_copy(buffer); - } + saveptr = ptr; + ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); + if (*saveptr != '\"' && (!*buffer || Ustrcmp(buffer, "text") != 0)) + { + ptr = saveptr; + fmsg = US""; + } + else + { + if (*saveptr != '\"') + ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); + fmsg = string_copy(buffer); + } - /* Drop through and treat as "finish", but never set "seen". */ + /* Drop through and treat as "finish", but never set "seen". */ - seen_value = FALSE; + seen_value = FALSE; - /* Finish has no arguments; fmsg defaults to NULL */ + /* Finish has no arguments; fmsg defaults to NULL */ - case finish_command: - new = store_get(sizeof(filter_cmd), GET_UNTAINTED); - new->next = NULL; - **lastcmdptr = new; - *lastcmdptr = &(new->next); - new->command = command; - new->seen = seen_force ? seen_value : FALSE; - new->args[0].u = fmsg; - break; + case FINISH_COMMAND: + new = store_get(sizeof(filter_cmd), GET_UNTAINTED); + new->next = NULL; + **lastcmdptr = new; + *lastcmdptr = &(new->next); + new->command = command; + new->seen = seen_force ? seen_value : FALSE; + new->args[0].u = fmsg; + break; /* Seen, unseen, and noerror are not allowed before if, which takes a condition argument and then and else sub-commands. */ - case if_command: - if (seen_force || noerror_force) - { - *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" " - "found before an \"if\" command near line %d", - line_number); - yield = FALSE; - } + case IF_COMMAND: + if (seen_force || noerror_force) + { + *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" " + "found before an \"if\" command near line %d", + line_number); + yield = FALSE; + } - /* Set up the command block for if */ + /* Set up the command block for if */ - new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED); - new->next = NULL; - **lastcmdptr = new; - *lastcmdptr = &new->next; - new->command = command; - new->seen = FALSE; - new->args[0].u = NULL; - new->args[1].u = new->args[2].u = NULL; - new->args[3].u = ptr; + new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED); + new->next = NULL; + **lastcmdptr = new; + *lastcmdptr = &new->next; + new->command = command; + new->seen = FALSE; + new->args[0].u = NULL; + new->args[1].u = new->args[2].u = NULL; + new->args[3].u = ptr; - /* Read the condition */ + /* Read the condition */ - ptr = read_condition(ptr, &new->args[0].c, TRUE); - if (*error_pointer) { yield = FALSE; break; } + ptr = read_condition(ptr, &new->args[0].c, TRUE); + if (*error_pointer) { yield = FALSE; break; } - /* Read the commands to be obeyed if the condition is true */ + /* Read the commands to be obeyed if the condition is true */ - newlastcmdptr = &(new->args[1].f); - if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE; + newlastcmdptr = &(new->args[1].f); + if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE; - /* If commands were successfully read, handle the various possible - terminators. There may be a number of successive "elif" sections. */ + /* If commands were successfully read, handle the various possible + terminators. There may be a number of successive "elif" sections. */ - else - { - while (had_else_endif == had_elif) + else { - filter_cmd *newnew = - store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED); - new->args[2].f = newnew; - new = newnew; - new->next = NULL; - new->command = command; - new->seen = FALSE; - new->args[0].u = NULL; - new->args[1].u = new->args[2].u = NULL; - new->args[3].u = ptr; - - ptr = read_condition(ptr, &new->args[0].c, TRUE); - if (*error_pointer) { yield = FALSE; break; } - newlastcmdptr = &(new->args[1].f); - if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) - yield = FALSE; - } + while (had_else_endif == had_elif) + { + filter_cmd *newnew = + store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED); + new->args[2].f = newnew; + new = newnew; + new->next = NULL; + new->command = command; + new->seen = FALSE; + new->args[0].u = NULL; + new->args[1].u = new->args[2].u = NULL; + new->args[3].u = ptr; + + ptr = read_condition(ptr, &new->args[0].c, TRUE); + if (*error_pointer) { yield = FALSE; break; } + newlastcmdptr = &(new->args[1].f); + if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) + yield = FALSE; + } - if (yield == FALSE) break; + if (yield == FALSE) break; - /* Handle termination by "else", possibly following one or more - "elsif" sections. */ + /* Handle termination by "else", possibly following one or more + "elsif" sections. */ - if (had_else_endif == had_else) - { - newlastcmdptr = &(new->args[2].f); - if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) - yield = FALSE; - else if (had_else_endif != had_endif) - { - *error_pointer = string_sprintf("\"endif\" missing near line %d of " - "filter file", line_number); - yield = FALSE; - } - } + if (had_else_endif == had_else) + { + newlastcmdptr = &(new->args[2].f); + if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) + yield = FALSE; + else if (had_else_endif != had_endif) + { + *error_pointer = string_sprintf("\"endif\" missing near line %d of " + "filter file", line_number); + yield = FALSE; + } + } - /* Otherwise the terminator was "endif" - this is checked by - read_command_list(). The pointer is already set to NULL. */ - } + /* Otherwise the terminator was "endif" - this is checked by + read_command_list(). The pointer is already set to NULL. */ + } - /* Reset the terminator flag. */ + /* Reset the terminator flag. */ - had_else_endif = had_neither; - break; + had_else_endif = had_neither; + break; /* The mail & vacation commands have a whole slew of keyworded arguments. @@ -1225,150 +1253,150 @@ switch (command) are logically booleans, because they are stored in a uschar * value, we use NULL and not FALSE, to keep 64-bit compilers happy. */ - case mail_command: - case vacation_command: - new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), GET_UNTAINTED); - new->next = NULL; - new->command = command; - new->seen = seen_force ? seen_value : FALSE; - new->noerror = noerror_force; - for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL; - - /* Read keyword/value pairs until we hit one that isn't. The data - must contain only printing chars plus tab, though the "text" value - can also contain newlines. The "file" keyword can be preceded by the - word "expand", and "return message" has no data. */ - - for (;;) - { - const uschar *saveptr = ptr; - ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); - if (*error_pointer) - { yield = FALSE; break; } - - /* Ensure "return" is followed by "message"; that's a complete option */ - - if (Ustrcmp(buffer, "return") == 0) + case MAIL_COMMAND: + case VACATION_COMMAND: + new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), GET_UNTAINTED); + new->next = NULL; + new->command = command; + new->seen = seen_force ? seen_value : FALSE; + new->noerror = noerror_force; + for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL; + + /* Read keyword/value pairs until we hit one that isn't. The data + must contain only printing chars plus tab, though the "text" value + can also contain newlines. The "file" keyword can be preceded by the + word "expand", and "return message" has no data. */ + + for (;;) { - new->args[mailarg_index_return].u = US""; /* not NULL => TRUE */ + const uschar *saveptr = ptr; ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); - if (Ustrcmp(buffer, "message") != 0) - { - *error_pointer = string_sprintf("\"return\" not followed by \"message\" " - " near line %d of filter file", line_number); - yield = FALSE; - break; - } - continue; - } + if (*error_pointer) + { yield = FALSE; break; } - /* Ensure "expand" is followed by "file", then fall through to process the - file keyword. */ + /* Ensure "return" is followed by "message"; that's a complete option */ - if (Ustrcmp(buffer, "expand") == 0) - { - new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */ - ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); - if (Ustrcmp(buffer, "file") != 0) - { - *error_pointer = string_sprintf("\"expand\" not followed by \"file\" " - " near line %d of filter file", line_number); - yield = FALSE; - break; - } - } + if (Ustrcmp(buffer, "return") == 0) + { + new->args[mailarg_index_return].u = US""; /* not NULL => TRUE */ + ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); + if (Ustrcmp(buffer, "message") != 0) + { + *error_pointer = string_sprintf("\"return\" not followed by \"message\" " + " near line %d of filter file", line_number); + yield = FALSE; + break; + } + continue; + } - /* Scan for the keyword */ + /* Ensure "expand" is followed by "file", then fall through to process the + file keyword. */ - for (i = 0; i < MAILARGS_STRING_COUNT; i++) - if (Ustrcmp(buffer, mailargs[i]) == 0) break; + if (Ustrcmp(buffer, "expand") == 0) + { + new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */ + ptr = nextword(ptr, buffer, sizeof(buffer), FALSE); + if (Ustrcmp(buffer, "file") != 0) + { + *error_pointer = string_sprintf("\"expand\" not followed by \"file\" " + " near line %d of filter file", line_number); + yield = FALSE; + break; + } + } - /* Not found keyword; assume end of this command */ + /* Scan for the keyword */ - if (i >= MAILARGS_STRING_COUNT) - { - ptr = saveptr; - break; - } + for (i = 0; i < MAILARGS_STRING_COUNT; i++) + if (Ustrcmp(buffer, mailargs[i]) == 0) break; - /* Found keyword, read the data item */ + /* Not found keyword; assume end of this command */ - ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); - if (*error_pointer) - { yield = FALSE; break; } - else new->args[i].u = string_copy(buffer); - } + if (i >= MAILARGS_STRING_COUNT) + { + ptr = saveptr; + break; + } - /* If this is the vacation command, apply some default settings to - some of the arguments. */ + /* Found keyword, read the data item */ - if (command == vacation_command) - { - if (!new->args[mailarg_index_file].u) + ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE); + if (*error_pointer) + { yield = FALSE; break; } + else new->args[i].u = string_copy(buffer); + } + + /* If this is the vacation command, apply some default settings to + some of the arguments. */ + + if (command == VACATION_COMMAND) { - new->args[mailarg_index_file].u = string_copy(US".vacation.msg"); - new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */ + if (!new->args[mailarg_index_file].u) + { + new->args[mailarg_index_file].u = string_copy(US".vacation.msg"); + new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */ + } + if (!new->args[mailarg_index_log].u) + new->args[mailarg_index_log].u = string_copy(US".vacation.log"); + if (!new->args[mailarg_index_once].u) + new->args[mailarg_index_once].u = string_copy(US".vacation"); + if (!new->args[mailarg_index_once_repeat].u) + new->args[mailarg_index_once_repeat].u = string_copy(US"7d"); + if (!new->args[mailarg_index_subject].u) + new->args[mailarg_index_subject].u = string_copy(US"On vacation"); } - if (!new->args[mailarg_index_log].u) - new->args[mailarg_index_log].u = string_copy(US".vacation.log"); - if (!new->args[mailarg_index_once].u) - new->args[mailarg_index_once].u = string_copy(US".vacation"); - if (!new->args[mailarg_index_once_repeat].u) - new->args[mailarg_index_once_repeat].u = string_copy(US"7d"); - if (!new->args[mailarg_index_subject].u) - new->args[mailarg_index_subject].u = string_copy(US"On vacation"); - } - /* Join the address on to the chain of generated addresses */ + /* Join the address on to the chain of generated addresses */ - **lastcmdptr = new; - *lastcmdptr = &(new->next); - break; + **lastcmdptr = new; + *lastcmdptr = &(new->next); + break; /* Seen and unseen just set flags */ - case seen_command: - case unseen_command: - if (!*ptr) - { - *error_pointer = string_sprintf("\"seen\" or \"unseen\" " - "near line %d is not followed by a command", line_number); - yield = FALSE; - } - if (seen_force) - { - *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated " - "near line %d", line_number); - yield = FALSE; - } - seen_value = (command == seen_command); - seen_force = TRUE; - was_seen_or_unseen = TRUE; - break; + case SEEN_COMMAND: + case UNSEEN_COMMAND: + if (!*ptr) + { + *error_pointer = string_sprintf("\"seen\" or \"unseen\" " + "near line %d is not followed by a command", line_number); + yield = FALSE; + } + if (seen_force) + { + *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated " + "near line %d", line_number); + yield = FALSE; + } + seen_value = (command == SEEN_COMMAND); + seen_force = TRUE; + was_seen_or_unseen = TRUE; + break; /* So does noerror */ - case noerror_command: - if (!*ptr) - { - *error_pointer = string_sprintf("\"noerror\" " - "near line %d is not followed by a command", line_number); - yield = FALSE; - } - noerror_force = TRUE; - was_noerror = TRUE; - break; + case NOERROR_COMMAND: + if (!*ptr) + { + *error_pointer = string_sprintf("\"noerror\" " + "near line %d is not followed by a command", line_number); + yield = FALSE; + } + noerror_force = TRUE; + was_noerror = TRUE; + break; /* Oops */ default: - *error_pointer = string_sprintf("unknown filtering command \"%s\" " - "near line %d of filter file", buffer, line_number); - yield = FALSE; - break; + *error_pointer = string_sprintf("unknown filtering command \"%s\" " + "near line %d of filter file", buffer, line_number); + yield = FALSE; + break; } if (!was_seen_or_unseen && !was_noerror) @@ -1712,7 +1740,7 @@ while (commands) switch(commands->command) { - case add_command: + case ADD_COMMAND: for (i = 0; i < 2; i++) { const uschar *ss = expargs[i]; @@ -1744,7 +1772,7 @@ while (commands) /* A deliver command's argument must be a valid address. Its optional second argument (system filter only) must also be a valid address. */ - case deliver_command: + case DELIVER_COMMAND: for (i = 0; i < 2; i++) { s = expargs[i]; @@ -1820,7 +1848,7 @@ while (commands) } break; - case save_command: + case SAVE_COMMAND: s = expargs[0]; mode = commands->args[1].i; @@ -1863,7 +1891,7 @@ while (commands) } break; - case pipe_command: + case PIPE_COMMAND: s = string_copy(commands->args[0].u); if (filter_test != FTEST_NONE) { @@ -1913,7 +1941,7 @@ while (commands) /* Set up the file name and mode, and close any previously open file. */ - case logfile_command: + case LOGFILE_COMMAND: log_mode = commands->args[1].i; if (log_mode == -1) log_mode = 0600; if (log_fd >= 0) @@ -1929,7 +1957,7 @@ while (commands) } break; - case logwrite_command: + case LOGWRITE_COMMAND: s = expargs[0]; if (filter_test != FTEST_NONE) @@ -1988,7 +2016,7 @@ while (commands) command is rejected at parse time otherwise. However "headers charset" is always permitted. */ - case headers_command: + case HEADERS_COMMAND: { int subtype = commands->args[1].i; s = expargs[0]; @@ -2032,17 +2060,17 @@ while (commands) very long by the inclusion of message headers; truncate if it is, and also ensure printing characters so as not to mess up log files. */ - case defer_command: + case DEFER_COMMAND: ff_name = US"defer"; ff_ret = FF_DEFER; goto DEFERFREEZEFAIL; - case fail_command: + case FAIL_COMMAND: ff_name = US"fail"; ff_ret = FF_FAIL; goto DEFERFREEZEFAIL; - case freeze_command: + case FREEZE_COMMAND: ff_name = US"freeze"; ff_ret = FF_FREEZE; @@ -2062,7 +2090,7 @@ while (commands) DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg); return ff_ret; - case finish_command: + case FINISH_COMMAND: if (filter_test != FTEST_NONE) { indent(); @@ -2074,7 +2102,7 @@ while (commands) finish_obeyed = TRUE; return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED; - case if_command: + case IF_COMMAND: { uschar *save_address = filter_thisaddress; int ok = FF_DELIVERED; @@ -2099,8 +2127,8 @@ while (commands) return path is unset or if a non-trusted user supplied -f <> as the return path. */ - case mail_command: - case vacation_command: + case MAIL_COMMAND: + case VACATION_COMMAND: if (!return_path || !*return_path) { if (filter_test != FTEST_NONE) @@ -2196,7 +2224,7 @@ while (commands) indent(); printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M", to ? to : US"", - commands->command == vacation_command ? " (vacation)" : "", + commands->command == VACATION_COMMAND ? " (vacation)" : "", commands->noerror ? " (noerror)" : ""); for (i = 1; i < MAILARGS_STRING_COUNT; i++) { @@ -2238,7 +2266,7 @@ while (commands) debug_printf_indent("Filter: %smail to: %s%s%s\n", commands->seen ? "seen " : "", to, - commands->command == vacation_command ? " (vacation)" : "", + commands->command == VACATION_COMMAND ? " (vacation)" : "", commands->noerror ? " (noerror)" : ""); for (i = 1; i < MAILARGS_STRING_COUNT; i++) { @@ -2344,7 +2372,7 @@ while (commands) } break; - case testprint_command: + case TESTPRINT_COMMAND: if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0) { const uschar *s = string_printing(expargs[0]); diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 37b5f5e24..799bee062 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -731,7 +731,7 @@ if (eblock != NULL) ob->syntax_errors_text)) /* Custom message */ return DEFER; - if (filtertype != FILTER_FORWARD || generated == NULL) + if (filtertype != FILTER_FORWARD || !generated) { addr->message = US"syntax error in redirection data"; return DECLINE; @@ -744,7 +744,7 @@ calling sort_errors_and_headers() in case this router declines - that function may modify the errors_address field in the current address, and we don't want to do that for a decline. */ -if (generated != NULL) +if (generated) { if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK) return xrc; diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index 67d48a1cb..803202b52 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -475,10 +475,9 @@ if (oncelog && *oncelog && to) else { EXIM_DATUM key_datum, result_datum; - uschar * dirname, * s; + uschar * s = Ustrrchr(oncelog, '/'); + uschar * dirname = s ? string_copyn(oncelog, s - oncelog) : NULL; - dirname = (s = Ustrrchr(oncelog, '/')) - ? string_copyn(oncelog, s - oncelog) : NULL; if (!(dbm_file = exim_dbopen(oncelog, dirname, O_RDWR|O_CREAT, ob->mode))) { addr->transport_return = DEFER; @@ -811,3 +810,5 @@ return FALSE; #endif /*!MACRO_PREDEF*/ #endif /*TRANSPORT_AUTOREPOL*/ /* End of transport/autoreply.c */ +/* vi: aw ai sw=2 +*/ commit b84bf19797130ef766e668ea3f26f664c9afb0e8 Author: Jeremy Harris Date: Fri May 3 18:18:00 2024 +0100 constify diff --git a/src/src/deliver.c b/src/src/deliver.c index 0157743a1..43ac7fd41 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -859,9 +859,10 @@ Return: string expansion from listener, or NULL */ uschar * -event_raise(uschar * action, const uschar * event, uschar * ev_data, int * errnop) +event_raise(const uschar * action, const uschar * event, const uschar * ev_data, + int * errnop) { -uschar * s; +const uschar * s; if (action) { DEBUG(D_deliver) @@ -872,7 +873,7 @@ if (action) event_name = event; event_data = ev_data; - if (!(s = expand_string(action)) && *expand_string_message) + if (!(s = expand_cstring(action)) && *expand_string_message) log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand event_action %s in %s: %s\n", event, transport_name ? transport_name : US"main", expand_string_message); @@ -880,7 +881,8 @@ if (action) event_name = event_data = NULL; /* If the expansion returns anything but an empty string, flag for - the caller to modify his normal processing + the caller to modify his normal processing. Copy the string to + de-const it. */ if (s && *s) { @@ -888,7 +890,7 @@ if (action) debug_printf("Event(%s): event_action returned \"%s\"\n", event, s); if (errnop) *errnop = ERRNO_EVENT; - return s; + return string_copy(s); } } return NULL; diff --git a/src/src/functions.h b/src/src/functions.h index f0b600ccc..9407b44df 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -253,7 +253,7 @@ extern BOOL dscp_lookup(const uschar *, int, int *, int *, int *); extern void enq_end(uschar *); extern BOOL enq_start(uschar *, unsigned); #ifndef DISABLE_EVENT -extern uschar *event_raise(uschar *, const uschar *, uschar *, int *); +extern uschar *event_raise(const uschar *, const uschar *, const uschar *, int *); extern void msg_event_raise(const uschar *, const address_item *); #endif diff --git a/src/src/globals.c b/src/src/globals.c index 2885caa23..4e5fd2991 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -909,10 +909,10 @@ int error_handling = ERRORS_SENDER; uschar *errors_reply_to = NULL; int errors_sender_rc = EXIT_FAILURE; #ifndef DISABLE_EVENT -uschar *event_action = NULL; /* expansion for delivery events */ -uschar *event_data = NULL; /* auxiliary data variable for event */ -int event_defer_errno = 0; -const uschar *event_name = NULL; /* event name variable */ +uschar *event_action = NULL; /* expansion for delivery events */ +const uschar *event_data = NULL; /* auxiliary data variable for event */ +int event_defer_errno = 0; +const uschar *event_name = NULL; /* event name variable */ #endif diff --git a/src/src/globals.h b/src/src/globals.h index 427590050..30c8bbad4 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -602,7 +602,7 @@ extern int errors_sender_rc; /* Return after message to sender*/ #ifndef DISABLE_EVENT extern uschar *event_action; /* expansion for delivery events */ -extern uschar *event_data; /* event data */ +extern const uschar *event_data; /* event data */ extern int event_defer_errno; /* error number set when a remote delivery is deferred with a host error */ extern const uschar *event_name; /* event classification */ #endif commit e8a0da772adc2892e661dec2bad4f36196c9128f Author: Jeremy Harris Date: Sat May 4 15:43:36 2024 +0100 Debug: markup ASCII control-chars diff --git a/src/src/string.c b/src/src/string.c index a627611af..170b47b23 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1623,7 +1623,7 @@ while (*fp) goto INSERT_GSTRING; } - case 'W': /* Maybe mark up spaces & newlines */ + case 'W': /* Maybe mark up ctrls, spaces & newlines */ s = va_arg(ap, char *); if (Ustrpbrk(s, " \n") && !IS_DEBUG(D_noutf8)) { @@ -1646,7 +1646,15 @@ while (*fp) if (precision >= 0) precision += 3; break; default: - zg = string_catn(zg, CUS s, 1); + if (*s <= ' ') + { /* base of UTF8 symbols for ASCII control chars */ + uschar ctrl_symbol[3] = {[0]=0xe2, [1]=0x90, [2]=0x80}; + ctrl_symbol[2] |= *s; + zg = string_catn(zg, ctrl_symbol, 3); + if (precision >= 0) precision += 2; + } + else + zg = string_catn(zg, CUS s, 1); break; } } commit 4fd2b1700eb79bbeeea4887b93f1235171976e24 Author: Jeremy Harris Date: Sun May 5 18:11:45 2024 +0100 Events: dns:fail Bug 3011 diff --git a/src/src/acl.c b/src/src/acl.c index d719a937b..4e88fc1ac 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -4450,7 +4450,7 @@ while ((acl_current = acl)) verbs[acl->verb], acl_name); if (basic_errno != ERRNO_CALLOUTDEFER) { - if (search_error_message != NULL && *search_error_message != 0) + if (search_error_message && *search_error_message) *log_msgptr = search_error_message; if (smtp_return_error_details) f.acl_temp_details = TRUE; } diff --git a/src/src/dns.c b/src/src/dns.c index 74c5a58c5..b22f4d327 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -1010,7 +1010,7 @@ won't return any. If fully_qualified_name is not NULL, set it to point to the full name returned by the resolver, if this is different to what it is given, unless the returned name starts with "*" as some nameservers seem to be returning -wildcards in this form. In international mode "different" means "alabel +wildcards in this form. In international mode "different" means "a-label forms are different". Arguments: @@ -1028,11 +1028,13 @@ Returns: DNS_SUCCEED successful lookup */ int -dns_lookup(dns_answer *dnsa, const uschar *name, int type, - const uschar **fully_qualified_name) +dns_lookup(dns_answer * dnsa, const uschar * name, int type, + const uschar ** fully_qualified_name) { -const uschar *orig_name = name; +const uschar * orig_name = name; BOOL secure_so_far = TRUE; +int rc = DNS_FAIL; +const uschar * errstr = NULL; /* By default, assume the resolver follows CNAME chains (and returns NODATA for an unterminated one). If it also does that for a CNAME loop, fine; if it returns @@ -1046,12 +1048,11 @@ for (int i = 0; i <= dns_cname_loops; i++) uschar * data; dns_record cname_rr, type_rr; dns_scan dnss; - int rc; /* DNS lookup failures get passed straight back. */ if ((rc = dns_basic_lookup(dnsa, name, type)) != DNS_SUCCEED) - return rc; + goto not_good; /* We should have either records of the required type, or a CNAME record, or both. We need to know whether both exist for getting the fully qualified @@ -1105,13 +1106,19 @@ for (int i = 0; i <= dns_cname_loops; i++) its not existing. */ if (!cname_rr.data) - return DNS_FAIL; + { + errstr = US"no_hit_yet_no_cname"; + goto not_good; + } /* DNS data comes from the outside, hence tainted */ data = store_get(256, GET_TAINTED); if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0) - return DNS_FAIL; + { + errstr = US"bad_expand"; + goto not_good; + } name = data; if (!dns_is_secure(dnsa)) @@ -1120,11 +1127,48 @@ for (int i = 0; i <= dns_cname_loops; i++) DEBUG(D_dns) debug_printf("CNAME found: change to %s\n", name); } /* Loop back to do another lookup */ -/*Control reaches here after 10 times round the CNAME loop. Something isn't +/* Control reaches here after 10 times round the CNAME loop. Something isn't right... */ log_write(0, LOG_MAIN, "CNAME loop for %s encountered", orig_name); -return DNS_FAIL; +errstr = US"cname_loop"; + +not_good: + { + const uschar * s = NULL; + BOOL save_flag = f.search_find_defer; + uschar * save_serr = search_error_message; + + if (!transport_name) + s = event_action; + else + for(transport_instance * tp = transports; tp; tp = tp->next) + if (Ustrcmp(tp->name, transport_name) == 0) + { s = tp->event_action; break; } + + if (s) + { + if (Ustrchr(name, ':')) /* unlikely, but may as well bugproof */ + { + gstring * g = NULL; + while (*name) + { + if (*name == ':') g = string_catn(g, name, 1); + g = string_catn(g, name++, 1); + } + name = string_from_gstring(g); + } + event_raise(s, US"dns:fail", + string_sprintf("%s:%s:%s", + errstr ? errstr : dns_rc_names[rc], name, dns_text_type(type)), + NULL); + } + + /*XXX what other state could an expansion in the eventhandler mess up? */ + search_error_message = save_serr; + f.search_find_defer = save_flag; + return rc; + } } commit cf9f324212bddcc09f405b94b9a01a5c99ffe19b Author: Jeremy Harris Date: Mon May 6 17:57:21 2024 +0100 Testsuite: munge retry DB dumps for long pathnames diff --git a/src/src/EDITME b/src/src/EDITME index 85d24f73f..4a33677d5 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -60,8 +60,8 @@ # for you by the OS-specific configuration. If Exim compiles without any # problems, you probably do not have to worry about the DBM library. If you # do want or need to change it, you should first read the discussion in the -# file doc/dbm.discuss.txt, which also contains instructions for testing Exim's -# interface to the DBM library. +# file doc/doc-txt/dbm.discuss.txt, which also contains instructions for testing +# Exim's interface to the DBM library. # In Local/Makefiles blank lines and lines starting with # are ignored. It is # also permitted to use the # character to add a comment to a setting, for diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h index 2d7199eda..ed1b5566d 100644 --- a/src/src/hintsdb.h +++ b/src/src/hintsdb.h @@ -24,6 +24,10 @@ utilities as well as the main Exim binary. */ #if defined(USE_TDB) +# if defined(USE_DB) || defined(USE_GDBM) +# error USE_TDB conflict with alternate definition +# endif + /* ************************* tdb interface ************************ */ /*XXX https://manpages.org/tdb/3 mentions concurrent writes. Could we lose the file lock? */ @@ -157,6 +161,10 @@ d->dptr = NULL; #elif defined USE_DB +# if defined(USE_TDB) || defined(USE_GDBM) +# error USE_DB conflict with alternate definition +# endif + # include /* 1.x did no locking @@ -482,6 +490,10 @@ exim_datum_free(EXIM_DATUM * d) #elif defined USE_GDBM /*XXX TODO: exim's locfile not needed */ +# if defined(USE_TDB) || defined(USE_DB) +# error USE_GDBM conflict with alternate definition +# endif + # include /* Basic DB type */ @@ -609,7 +621,7 @@ static inline void exim_datum_free(EXIM_DATUM * d) { free(d->dptr); } -/* size limit */ +/* size limit. GDBM is int-max limited, but we want to be less silly */ # define EXIM_DB_RLIMIT 150 @@ -621,7 +633,7 @@ exim_datum_free(EXIM_DATUM * d) /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM -interface */ +interface (which seems to be a wrapper for GDBM) */ /********************* ndbm interface definitions **********************/ @@ -745,7 +757,7 @@ exim_datum_free(EXIM_DATUM * d) # define EXIM_DB_RLIMIT 150 -#endif /* USE_GDBM */ +#endif /* !USE_GDBM */ diff --git a/src/src/retry.c b/src/src/retry.c index 6b977dd58..6ccef4f98 100644 --- a/src/src/retry.c +++ b/src/src/retry.c @@ -678,7 +678,13 @@ for (int i = 0; i < 3; i++) ? US string_printing(rti->message) : US"unknown error"; message_length = Ustrlen(message); - if (message_length > EXIM_DB_RLIMIT) message_length = EXIM_DB_RLIMIT; + if (message_length > EXIM_DB_RLIMIT) + { + DEBUG(D_retry) + debug_printf_indent("truncating message from %u to %u bytes\n", + message_length, EXIM_DB_RLIMIT); + message_length = EXIM_DB_RLIMIT; + } /* Read a retry record from the database or construct a new one. Ignore an old one if it is too old since it was last updated. */ diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 0279659f2..f495f9571 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -1368,7 +1368,7 @@ if (!isdirectory) && ob->create_file == create_belowhome) if (is_tainted(path)) { - DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path); + DEBUG(D_transport) debug_printf("below-home: de-tainting path '%s'\n", path); path = string_copy_taint(path, GET_UNTAINTED); } @@ -2207,7 +2207,7 @@ else if (is_tainted(path)) if (ob->create_file == create_belowhome) { - DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path); + DEBUG(D_transport) debug_printf("below-home: de-tainting path '%s'\n", path); path = string_copy_taint(path, GET_UNTAINTED); } else commit 1d2868b2d90c230dd4ae42e6f3c7e4958ed75de5 Author: Jeremy Harris Date: Wed May 8 11:31:52 2024 +0100 Debug: fix showing option name for list (vs. list content) It's done in a hacky way (always was) and is fragile. Turns out, too fragile to be good. - some lists, we cannot match up to an option name eg. stderr/0002 - some, we're falling back to comparing the list content; this gets duplicates and thus gives incorrect info, which is worse than no info (we could scan for dups, I guess?) Why do we get dups when we're comparing the addrs of the string? - mmm, do we Really get dups? - Yes: same option across two routers. Must be a static init for a default. In which case, does it being a dup matter? - OK, we can check router_name / transport_name Resulting testsuite sterr changes only partial, here. There's a double check on local_parts in routers (always was). Why? One buildfarm animal (groundhog) is missing a "list element" line possibly associated with dnssec_request_domains. Why? diff --git a/src/src/deliver.c b/src/src/deliver.c index 43ac7fd41..f3c9203e4 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -903,6 +903,7 @@ const uschar * save_domain = deliver_domain; const uschar * save_local = deliver_localpart; const uschar * save_host = deliver_host; const uschar * save_address = deliver_host_address; +uschar * save_rn = router_name, * save_tn = transport_name; const int save_port = deliver_host_port; router_name = addr->router ? addr->router->name : NULL; @@ -939,7 +940,8 @@ deliver_host_address = save_address; deliver_host = save_host; deliver_localpart = save_local; deliver_domain = save_domain; -router_name = transport_name = NULL; +router_name = save_rn; +router_name = save_tn; } #endif /*DISABLE_EVENT*/ diff --git a/src/src/functions.h b/src/src/functions.h index 9407b44df..08fa24f3d 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -427,7 +427,7 @@ extern int rda_is_filter(const uschar *); extern BOOL readconf_depends(driver_instance *, uschar *); extern void readconf_driver_init(uschar *, driver_instance **, driver_info *, int, void *, int, optionlist *, int); -extern uschar *readconf_find_option(void *); +extern const uschar *readconf_find_option(void *); extern void readconf_main(BOOL); extern void readconf_options_from_list(optionlist *, unsigned, const uschar *, uschar *); extern BOOL readconf_print(const uschar *, const uschar *, BOOL); diff --git a/src/src/macros.h b/src/src/macros.h index 3341f5f41..2938b2523 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1195,7 +1195,8 @@ When doing en extended loop of matching, release store periodically. */ #define REGEX_LOOPCOUNT_STORE_RESET 1000 -/* Debug an option access. Use for non-list ones about to be expanded. */ +/* Debug an option access. Use for non-list ones about to be expanded +(lists have their own debugging, under D_list). */ #define GET_OPTION(name) \ DEBUG(D_expand) debug_printf("try option " name "\n"); diff --git a/src/src/match.c b/src/src/match.c index 2cb499359..4b128a609 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -437,18 +437,19 @@ BOOL textonly_re; /* Save time by not scanning for the option name when we don't need it. */ -HDEBUG(D_any) +HDEBUG(D_any) /* always give the query. Give results only for D_lists */ { - uschar * listname = readconf_find_option(listptr); + const uschar * listname = readconf_find_option(listptr); if (*listname) ot = string_sprintf("%s in %s?", name, listname); } -/* If the list is empty, the answer is no. Skip the debugging output for -an unnamed list. */ +/* If the list is empty, the answer is no. */ if (!*listptr) { - HDEBUG(D_lists) if (ot) debug_printf_indent("%s no (option unset)\n", ot); + HDEBUG(D_lists) + if (ot) debug_printf_indent("%s no (option unset)\n", ot); + else debug_printf_indent("%s not in empty list (option unset? cannot trace name)\n", name); return FAIL; } @@ -505,7 +506,7 @@ if (textonly_re) switch (type) #define LIST_LIMIT_PR 2048 HDEBUG(D_any) if (!ot) - { + { /* We failed to identify an option name, so give the list text */ int n, m; gstring * g = string_fmt_append(NULL, "%s in \"%n%.*s%n\"", name, &n, LIST_LIMIT_PR, list, &m); @@ -527,7 +528,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { uschar * ss = sss; - HDEBUG(D_lists) debug_printf_indent("list element: %s\n", ss); + HDEBUG(D_lists) debug_printf_indent("list element: %W\n", ss); /* Address lists may contain +caseful, to restore caseful matching of the local part. We have to know the layout of the control block, unfortunately. @@ -618,7 +619,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) namedlist_block * nb; tree_node * t; - DEBUG(D_lists) + HDEBUG(D_lists) { debug_printf_indent(" start sublist %s\n", ss+1); expand_level += 2; } if (!(t = tree_search(*anchorptr, ss+1))) @@ -655,7 +656,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { int res = match_check_list(&(nb->string), 0, anchorptr, &use_cache_bits, func, arg, type, name, valueptr); - DEBUG(D_lists) + HDEBUG(D_lists) { expand_level -= 2; debug_printf_indent(" end sublist %s\n", ss+1); } switch (res) @@ -695,7 +696,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) p->next = nb->cache_data; nb->cache_data = p; if (*valueptr) - DEBUG(D_lists) debug_printf_indent("data from lookup saved for " + HDEBUG(D_lists) debug_printf_indent("data from lookup saved for " "cache for %s: key '%s' value '%s'\n", ss, p->key, *valueptr); } } @@ -707,7 +708,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) else { - DEBUG(D_lists) + HDEBUG(D_lists) { expand_level -= 2; debug_printf_indent("cached %s match for %s\n", @@ -725,7 +726,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) *valueptr = p->data; break; } - DEBUG(D_lists) debug_printf_indent("cached lookup data = %s\n", *valueptr); + HDEBUG(D_lists) debug_printf_indent("cached lookup data = %s\n", *valueptr); } } @@ -749,7 +750,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { case OK: HDEBUG(D_lists) debug_printf_indent("%s %s (matched \"%s\")\n", ot, - (yield == OK)? "yes" : "no", sss); + yield == OK ? "yes" : "no", sss); goto YIELD_RETURN; case DEFER: @@ -757,8 +758,8 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) error = string_sprintf("DNS lookup of \"%s\" deferred", ss); if (ignore_defer) { - HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_defer\n", - error); + HDEBUG(D_lists) + debug_printf_indent("%s: item ignored by +ignore_defer\n", error); break; } if (include_defer) @@ -777,8 +778,8 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) case ERROR: if (ignore_unknown) { - HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_unknown\n", - error); + HDEBUG(D_lists) debug_printf_indent( + "%s: item ignored by +ignore_unknown\n", error); } else { @@ -812,8 +813,8 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) if (!f) { - uschar * listname = readconf_find_option(listptr); - if (listname[0] == 0) + const uschar * listname = readconf_find_option(listptr); + if (!*listname) listname = string_sprintf("\"%s\"", *listptr); log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", string_open_failed("%s when checking %s", sss, listname)); @@ -859,8 +860,8 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { case OK: (void)fclose(f); - HDEBUG(D_lists) debug_printf_indent("%s %s (matched \"%s\" in %s)\n", ot, - yield == OK ? "yes" : "no", sss, filename); + HDEBUG(D_lists) debug_printf_indent("%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. */ @@ -874,8 +875,8 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) error = string_sprintf("DNS lookup of %s deferred", ss); if (ignore_defer) { - HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_defer\n", - error); + HDEBUG(D_lists) + debug_printf_indent("%s: item ignored by +ignore_defer\n", error); break; } (void)fclose(f); @@ -892,13 +893,13 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) case ERROR: if (ignore_unknown) { - HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_unknown\n", - error); + HDEBUG(D_lists) debug_printf_indent( + "%s: item ignored by +ignore_unknown\n", error); } else { HDEBUG(D_lists) debug_printf_indent("%s %s (%s)\n", ot, - include_unknown? "yes":"no", error); + include_unknown ? "yes":"no", error); (void)fclose(f); if (!include_unknown) { @@ -922,20 +923,19 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) /* End of list reached: if the last item was negated yield OK, else FAIL. */ -HDEBUG(D_lists) - HDEBUG(D_lists) - { - expand_level--; - debug_printf_indent("%s %s (end of list)\n", ot, yield == OK ? "no":"yes"); - } - return yield == OK ? FAIL : OK; - +HDEBUG(D_any) + { + HDEBUG(D_lists) expand_level--; + debug_printf_indent("%s %s (end of list)\n", ot, yield == OK ? "no":"yes"); + } +return yield == OK ? FAIL : OK; + /* Something deferred */ DEFER_RETURN: - HDEBUG(D_lists) + HDEBUG(D_any) { - expand_level--; + HDEBUG(D_lists) expand_level--; debug_printf_indent("%s list match deferred for %s\n", ot, sss); } return DEFER; @@ -1390,3 +1390,5 @@ return match_address_list(address, TRUE, TRUE, listptr, NULL, -1, sep, NULL); } /* End of match.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/readconf.c b/src/src/readconf.c index 3db3bdd69..d87a56f3d 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -592,46 +592,104 @@ static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item); pointer variables in the options table or in option tables for various drivers. For debugging output, it is useful to be able to find the name of the option which is currently being processed. This function finds it, if it exists, by -searching the table(s). +searching the table(s) for a value with the given content. Arguments: a value that is presumed to be in the table above Returns: the option name, or an empty string */ -uschar * -readconf_find_option(void *p) +const uschar * +readconf_find_option(void * listptr) { -for (int i = 0; i < nelem(optionlist_config); i++) - if (p == optionlist_config[i].v.value) return US optionlist_config[i].name; +uschar * list = * USS listptr; +const uschar * name = NULL, * drname = NULL; + +for (optionlist * o = optionlist_config; /* main-config options */ + o < optionlist_config + optionlist_config_size; o++) + if (listptr == o->v.value) + return US o->name; for (router_instance * r = routers; r; r = r->next) + if (router_name && Ustrcmp(r->name, router_name) == 0) { - router_info *ri = r->info; - for (int i = 0; i < *ri->options_count; i++) - { - if ((ri->options[i].type & opt_mask) != opt_stringptr) continue; - if (p == CS (r->options_block) + ri->options[i].v.offset) - return US ri->options[i].name; - } + const router_info * ri = r->info; + + /* Check for a listptr match first */ + + for (optionlist * o = optionlist_routers; /* generic options */ + o < optionlist_routers + optionlist_routers_size; o++) + if ( (o->type & opt_mask) == opt_stringptr + && listptr == CS r + o->v.offset) + return US o->name; + + for (optionlist * o = ri->options; /* private options */ + o < ri->options + *ri->options_count; o++) + if ( (o->type & opt_mask) == opt_stringptr + && listptr == CS (r->options_block) + o->v.offset) + return US o->name; + + /* Check for a list addr match, unless null */ + + if (!list) continue; + + for (optionlist * o = optionlist_routers; /* generic options */ + o < optionlist_routers + optionlist_routers_size; o++) + if ( (o->type & opt_mask) == opt_stringptr + && list == * USS(CS r + o->v.offset)) + if (name) return string_sprintf("DUP: %s %s vs. %s %s", + drname, name, r->name, o->name); + else { name = US o->name; drname = r->name; } + + for (optionlist * o = ri->options; /* private options */ + o < ri->options + *ri->options_count; o++) + if ( (o->type & opt_mask) == opt_stringptr + && list == * USS(CS (r->options_block) + o->v.offset)) + if (name) return string_sprintf("DUP: %s %s vs. %s %s", + drname, name, r->name, o->name); + else { name = US o->name; drname = r->name; } } for (transport_instance * t = transports; t; t = t->next) + if (transport_name && Ustrcmp(t->name, transport_name) == 0) { - transport_info *ti = t->info; - for (int i = 0; i < *ti->options_count; i++) - { - optionlist * op = &ti->options[i]; - if ((op->type & opt_mask) != opt_stringptr) continue; - if (p == ( op->type & opt_public - ? CS t - : CS t->options_block - ) - + op->v.offset) - return US op->name; - } + const transport_info * ti = t->info; + + /* Check for a listptr match first */ + + for (optionlist * o = optionlist_transports; /* generic options */ + o < optionlist_transports + optionlist_transports_size; o++) + if ( (o->type & opt_mask) == opt_stringptr + && listptr == CS t + o->v.offset) + return US o->name; + + for (optionlist * o = ti->options; /* private options */ + o < ti->options + *ti->options_count; o++) + if ( (o->type & opt_mask) == opt_stringptr + && listptr == CS t->options_block + o->v.offset) + return US o->name; + + /* Check for a list addr match, unless null */ + + if (!list) continue; + + for (optionlist * o = optionlist_transports; /* generic options */ + o < optionlist_transports + optionlist_transports_size; o++) + if ( (o->type & opt_mask) == opt_stringptr + && list == * USS(CS t + o->v.offset)) + if (name) return string_sprintf("DUP: %s %s vs. %s %s", + drname, name, t->name, o->name); + else { name = US o->name; drname = t->name; } + + for (optionlist * o = ti->options; /* private options */ + o < ti->options + *ti->options_count; o++) + if ( (o->type & opt_mask) == opt_stringptr + && list == * USS(CS t->options_block + o->v.offset)) + if (name) return string_sprintf("DUP: %s %s vs. %s %s", + drname, name, t->name, o->name); + else { name = US o->name; drname = t->name; } } -return US""; +return name ? name : US""; } diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index a78b15fbd..81042003f 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -365,6 +365,7 @@ if (!save_errno) { #ifdef TCP_FASTOPEN /* See if TCP Fast Open usable. Default is a traditional 3WHS connect */ + expand_level++; if (verify_check_given_host(CUSS &ob->hosts_try_fastopen, sc->host) == OK) { if (!early_data) @@ -380,6 +381,7 @@ if (!save_errno) } # endif } + expand_level--; #endif if (ip_connect(sock, sc->host_af, sc->host->address, sc->host->port, timeout, fastopen_blob) < 0) @@ -412,7 +414,7 @@ if (!save_errno) /* Both bind() and connect() succeeded, and any early-data */ - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" connected\n"); + HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("connected\n"); if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0) sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port); else @@ -496,7 +498,7 @@ HDEBUG(D_transport|D_acl|D_v) #ifdef SUPPORT_SOCKS if (ob->socks_proxy) s = string_sprintf("%svia proxy ", s); #endif - debug_printf_indent("Connecting to %s %s%s... ", sc->host->name, callout_address, s); + debug_printf_indent("Connecting to %s %s%s...\n", sc->host->name, callout_address, s); } /* Create and connect the socket */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index ddd6ad7e1..0338d6301 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -668,12 +668,15 @@ deferred_event_raise(address_item * addr, host_item * host, uschar * evstr) { uschar * action = addr->transport->event_action; const uschar * save_domain, * save_local; +uschar * save_rn, * save_tn; if (!action) return; save_domain = deliver_domain; save_local = deliver_localpart; +save_rn = router_name; +save_tn = transport_name; /*XXX would ip & port already be set up? */ deliver_host_address = string_copy(host->address); @@ -697,7 +700,8 @@ deliver_localpart = addr->local_part; deliver_localpart = save_local; deliver_domain = save_domain; -router_name = transport_name = NULL; +router_name = save_rn; +router_name = save_tn; } #endif commit 9d7795dba14939e2b743d8c3c4df81a5582b3092 Author: Jeremy Harris Date: Thu May 9 15:37:49 2024 +0100 Debug: indent DNS ops diff --git a/src/src/dns.c b/src/src/dns.c index b22f4d327..5a8c23d62 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -62,7 +62,7 @@ if (stat(CS utilname, &statbuf) >= 0) int infd, outfd, rc; uschar *argv[5]; - DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) using fakens\n", + DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) using fakens\n", name, dns_text_type(type)); argv[0] = utilname; @@ -105,17 +105,17 @@ if (stat(CS utilname, &statbuf) >= 0) case 3: h_errno = NO_RECOVERY; return -1; case 4: h_errno = NO_DATA; return -1; case 5: /* Pass on to res_search() */ - DEBUG(D_dns) debug_printf("fakens returned PASS_ON\n"); + DEBUG(D_dns) debug_printf_indent("fakens returned PASS_ON\n"); } } else { - DEBUG(D_dns) debug_printf("fakens (%s) not found\n", utilname); + DEBUG(D_dns) debug_printf_indent("fakens (%s) not found\n", utilname); } /* fakens utility not found, or it returned "pass on" */ -DEBUG(D_dns) debug_printf("passing %s on to res_search()\n", domain); +DEBUG(D_dns) debug_printf_indent("passing %s on to res_search()\n", domain); return res_search(CS domain, C_IN, type, answerptr, size); } @@ -165,13 +165,13 @@ if (dns_use_edns0 >= 0) else resp->options &= ~RES_USE_EDNS0; DEBUG(D_resolver) - debug_printf("Coerced resolver EDNS0 support %s.\n", + debug_printf_indent("Coerced resolver EDNS0 support %s.\n", dns_use_edns0 ? "on" : "off"); } #else if (dns_use_edns0 >= 0) DEBUG(D_resolver) - debug_printf("Unable to %sset EDNS0 without resolver support.\n", + debug_printf_indent("Unable to %sset EDNS0 without resolver support.\n", dns_use_edns0 ? "" : "un"); #endif @@ -187,7 +187,7 @@ if (dns_dnssec_ok >= 0) if (dns_use_edns0 == 0 && dns_dnssec_ok != 0) { DEBUG(D_resolver) - debug_printf("CONFLICT: dns_use_edns0 forced false, dns_dnssec_ok forced true, ignoring latter!\n"); + debug_printf_indent("CONFLICT: dns_use_edns0 forced false, dns_dnssec_ok forced true, ignoring latter!\n"); } else { @@ -195,18 +195,18 @@ if (dns_dnssec_ok >= 0) resp->options |= RES_USE_DNSSEC; else resp->options &= ~RES_USE_DNSSEC; - DEBUG(D_resolver) debug_printf("Coerced resolver DNSSEC support %s.\n", + DEBUG(D_resolver) debug_printf_indent("Coerced resolver DNSSEC support %s.\n", dns_dnssec_ok ? "on" : "off"); } } # else if (dns_dnssec_ok >= 0) DEBUG(D_resolver) - debug_printf("Unable to %sset DNSSEC without resolver support.\n", + debug_printf_indent("Unable to %sset DNSSEC without resolver support.\n", dns_dnssec_ok ? "" : "un"); if (use_dnssec) DEBUG(D_resolver) - debug_printf("Unable to set DNSSEC without resolver support.\n"); + debug_printf_indent("Unable to set DNSSEC without resolver support.\n"); # endif #endif /* DISABLE_DNSSEC */ @@ -353,7 +353,7 @@ char * trace = NULL; if (reset != RESET_NEXT) { dnss->rrcount = ntohs(h->qdcount); - TRACE debug_printf("%s: reset (Q rrcount %d)\n", __FUNCTION__, dnss->rrcount); + TRACE debug_printf_indent("%s: reset (Q rrcount %d)\n", __FUNCTION__, dnss->rrcount); dnss->aptr = dnsa->answer + sizeof(HEADER); /* Skip over questions; failure to expand the name just gives up */ @@ -372,7 +372,7 @@ if (reset != RESET_NEXT) /* Get the number of answer records. */ dnss->rrcount = ntohs(h->ancount); - TRACE debug_printf("%s: reset (A rrcount %d)\n", __FUNCTION__, dnss->rrcount); + TRACE debug_printf_indent("%s: reset (A rrcount %d)\n", __FUNCTION__, dnss->rrcount); /* Skip over answers if we want to look at the authority section. Also skip the NS records (i.e. authority section) if wanting to look at the additional @@ -380,15 +380,15 @@ if (reset != RESET_NEXT) if (reset == RESET_ADDITIONAL) { - TRACE debug_printf("%s: additional\n", __FUNCTION__); + TRACE debug_printf_indent("%s: additional\n", __FUNCTION__); dnss->rrcount += ntohs(h->nscount); - TRACE debug_printf("%s: reset (NS rrcount %d)\n", __FUNCTION__, dnss->rrcount); + TRACE debug_printf_indent("%s: reset (NS rrcount %d)\n", __FUNCTION__, dnss->rrcount); } if (reset == RESET_AUTHORITY || reset == RESET_ADDITIONAL) { TRACE if (reset == RESET_AUTHORITY) - debug_printf("%s: authority\n", __FUNCTION__); + debug_printf_indent("%s: authority\n", __FUNCTION__); while (dnss->rrcount-- > 0) { TRACE trace = "A-namelen"; @@ -409,13 +409,13 @@ if (reset != RESET_NEXT) } dnss->rrcount = reset == RESET_AUTHORITY ? ntohs(h->nscount) : ntohs(h->arcount); - TRACE debug_printf("%s: reset (%s rrcount %d)\n", __FUNCTION__, + TRACE debug_printf_indent("%s: reset (%s rrcount %d)\n", __FUNCTION__, reset == RESET_AUTHORITY ? "NS" : "AR", dnss->rrcount); } - TRACE debug_printf("%s: %d RRs to read\n", __FUNCTION__, dnss->rrcount); + TRACE debug_printf_indent("%s: %d RRs to read\n", __FUNCTION__, dnss->rrcount); } else - TRACE debug_printf("%s: next (%d left)\n", __FUNCTION__, dnss->rrcount); + TRACE debug_printf_indent("%s: next (%d left)\n", __FUNCTION__, dnss->rrcount); /* The variable dnss->aptr is now pointing at the next RR, and dnss->rrcount contains the number of RR records left. */ @@ -458,11 +458,11 @@ if (dnss_inc_aptr(dnsa, dnss, dnss->srr.size)) /* Return a pointer to the dns_record structure within the dns_answer. This is for convenience so that the scans can use nice-looking for loops. */ -TRACE debug_printf("%s: return %s\n", __FUNCTION__, dns_text_type(dnss->srr.type)); +TRACE debug_printf_indent("%s: return %s\n", __FUNCTION__, dns_text_type(dnss->srr.type)); return &dnss->srr; null_return: - TRACE debug_printf("%s: terminate (%d RRs left). Last op: %s; errno %d %s\n", + TRACE debug_printf_indent("%s: terminate (%d RRs left). Last op: %s; errno %d %s\n", __FUNCTION__, dnss->rrcount, trace, errno, strerror(errno)); dnss->rrcount = 0; return NULL; @@ -515,7 +515,7 @@ dns_is_secure(const dns_answer * dnsa) { #ifdef DISABLE_DNSSEC DEBUG(D_dns) - debug_printf("DNSSEC support disabled at build-time; dns_is_secure() false\n"); + debug_printf_indent("DNSSEC support disabled at build-time; dns_is_secure() false\n"); return FALSE; #else const HEADER * h = (const HEADER *) dnsa->answer; @@ -542,7 +542,7 @@ if ( !h->aa ) return FALSE; -DEBUG(D_dns) debug_printf("DNS faked the AD bit " +DEBUG(D_dns) debug_printf_indent("DNS faked the AD bit " "(got AA and matched with dns_trust_aa (%s in %s))\n", auth_name, dns_trust_aa); @@ -666,7 +666,7 @@ else (void)tree_insertnode(&tree_dns_fails, new); } -DEBUG(D_dns) debug_printf(" %s neg-cache entry for %s, ttl %d\n", +DEBUG(D_dns) debug_printf_indent(" %s neg-cache entry for %s, ttl %d\n", previous ? "update" : "writing", node_name, expiry ? (int)(expiry - time(NULL)) : -1); e->expiry = expiry; @@ -693,7 +693,7 @@ e = previous->data.ptr; val = e->data.val; rc = e->expiry && e->expiry <= time(NULL) ? -1 : val; -DEBUG(D_dns) debug_printf("DNS lookup of %.255s (%s): %scached value %s%s\n", +DEBUG(D_dns) debug_printf_indent("DNS lookup of %.255s (%s): %scached value %s%s\n", name, dns_text_type(type), rc == -1 ? "" : "using ", dns_rc_names[val], @@ -731,12 +731,12 @@ if ( h->qr == 1 /* a response */ && ntohs(h->ancount) == 0 /* no answer records */ && ntohs(h->nscount) >= 1) /* authority records */ { - DEBUG(D_dns) debug_printf("faking res_search(%s) response length as %d\n", + DEBUG(D_dns) debug_printf_indent("faking res_search(%s) response length as %d\n", dns_text_type(type), (int)sizeof(dnsa->answer)); dnsa->answerlen = sizeof(dnsa->answer); return TRUE; } -DEBUG(D_dns) debug_printf("DNS: couldn't fake dnsa len\n"); +DEBUG(D_dns) debug_printf_indent("DNS: couldn't fake dnsa len\n"); /* Maybe we should just do a second lookup for an SOA? */ return FALSE; } @@ -783,7 +783,7 @@ if (fake_dnsa_len_for_fail(dnsa, type)) return time(NULL) + ttl; } -DEBUG(D_dns) debug_printf("DNS: no SOA record found for neg-TTL\n"); +DEBUG(D_dns) debug_printf_indent("DNS: no SOA record found for neg-TTL\n"); return 0; } @@ -844,11 +844,11 @@ if ((rc = dns_fail_cache_hit(name, type)) > 0) uschar * alabel; uschar * errstr = NULL; DEBUG(D_dns) if (string_is_utf8(name)) - debug_printf("convert utf8 '%s' to alabel for for lookup\n", name); + debug_printf_indent("convert utf8 '%s' to alabel for for lookup\n", name); if ((alabel = string_domain_utf8_to_alabel(name, &errstr)), errstr) { DEBUG(D_dns) - debug_printf("DNS name '%s' utf8 conversion to alabel failed: %s\n", name, + debug_printf_indent("DNS name '%s' utf8 conversion to alabel failed: %s\n", name, errstr); f.host_find_failed_syntax = TRUE; return DNS_NOMATCH; @@ -877,7 +877,7 @@ if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT) if (!regex_match(regex_check_dns_names, name, -1, NULL)) { DEBUG(D_dns) - debug_printf("DNS name syntax check failed: %s (%s)\n", name, + debug_printf_indent("DNS name syntax check failed: %s (%s)\n", name, dns_text_type(type)); f.host_find_failed_syntax = TRUE; return DNS_NOMATCH; @@ -909,7 +909,7 @@ dnsa->answerlen = f.running_in_test_harness if (dnsa->answerlen > (int) sizeof(dnsa->answer)) { - DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) resulted in overlong packet" + DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) resulted in overlong packet" " (size %d), truncating to %u.\n", name, dns_text_type(type), dnsa->answerlen, (unsigned int) sizeof(dnsa->answer)); dnsa->answerlen = sizeof(dnsa->answer); @@ -918,12 +918,12 @@ if (dnsa->answerlen > (int) sizeof(dnsa->answer)) if (dnsa->answerlen < 0) switch (h_errno) { case HOST_NOT_FOUND: - DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave HOST_NOT_FOUND\n" + DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave HOST_NOT_FOUND\n" "returning DNS_NOMATCH\n", name, dns_text_type(type)); return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH); case TRY_AGAIN: - DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n", + DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave TRY_AGAIN\n", name, dns_text_type(type)); /* Cut this out for various test programs */ @@ -955,10 +955,10 @@ if (dnsa->answerlen < 0) switch (h_errno) if (rc != OK) { - DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n"); + DEBUG(D_dns) debug_printf_indent("returning DNS_AGAIN\n"); return dns_fail_return(name, type, 0, DNS_AGAIN); } - DEBUG(D_dns) debug_printf("%s is in dns_again_means_nonexist: returning " + DEBUG(D_dns) debug_printf_indent("%s is in dns_again_means_nonexist: returning " "DNS_NOMATCH\n", name); return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH); @@ -967,22 +967,22 @@ if (dnsa->answerlen < 0) switch (h_errno) #endif case NO_RECOVERY: - DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave NO_RECOVERY\n" + DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave NO_RECOVERY\n" "returning DNS_FAIL\n", name, dns_text_type(type)); return dns_fail_return(name, type, 0, DNS_FAIL); case NO_DATA: - DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave NO_DATA\n" + DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave NO_DATA\n" "returning DNS_NODATA\n", name, dns_text_type(type)); return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NODATA); default: - DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave unknown DNS error %d\n" + DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave unknown DNS error %d\n" "returning DNS_FAIL\n", name, dns_text_type(type), h_errno); return dns_fail_return(name, type, 0, DNS_FAIL); } -DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) succeeded\n", +DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) succeeded\n", name, dns_text_type(type)); return DNS_SUCCEED; @@ -1124,7 +1124,7 @@ for (int i = 0; i <= dns_cname_loops; i++) if (!dns_is_secure(dnsa)) secure_so_far = FALSE; - DEBUG(D_dns) debug_printf("CNAME found: change to %s\n", name); + DEBUG(D_dns) debug_printf_indent("CNAME found: change to %s\n", name); } /* Loop back to do another lookup */ /* Control reaches here after 10 times round the CNAME loop. Something isn't @@ -1216,12 +1216,12 @@ switch (type) case T_SOA: { const uschar *d = name; - while (d != 0) + while (d) { int rc = dns_lookup(dnsa, d, type, fully_qualified_name); if (rc != DNS_NOMATCH && rc != DNS_NODATA) return rc; - while (*d != 0 && *d != '.') d++; - if (*d++ == 0) break; + while (*d && *d != '.') d++; + if (!*d++) break; } return DNS_NOMATCH; } @@ -1241,7 +1241,7 @@ switch (type) dns_record *rr; dns_scan dnss; - DEBUG(D_dns) debug_printf("CSA lookup of %s\n", name); + DEBUG(D_dns) debug_printf_indent("CSA lookup of %s\n", name); srvname = string_sprintf("_client._smtp.%s", name); rc = dns_lookup(dnsa, srvname, T_SRV, NULL); @@ -1279,7 +1279,7 @@ switch (type) limit = 3; } - DEBUG(D_dns) debug_printf("CSA TLD %s\n", tld); + DEBUG(D_dns) debug_printf_indent("CSA TLD %s\n", tld); /* Do not perform the search if the top level or 2nd level domains do not exist. This is quite common, and when it occurs all the search queries would @@ -1306,7 +1306,7 @@ switch (type) if (--namesuff <= name) return DNS_NOMATCH; while (*namesuff != '.'); - DEBUG(D_dns) debug_printf("CSA parent search at %s\n", namesuff + 1); + DEBUG(D_dns) debug_printf_indent("CSA parent search at %s\n", namesuff + 1); srvname = string_sprintf("_client._smtp.%s", namesuff + 1); rc = dns_lookup(dnsa, srvname, T_SRV, NULL); diff --git a/src/src/host.c b/src/src/host.c index 381f2a5fc..26b3c2c68 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -1298,30 +1298,30 @@ host_item *last = *lastptr; host_item *prev = NULL; host_item *h; -if (removed != NULL) *removed = FALSE; +if (removed) *removed = FALSE; -if (local_interface_data == NULL) local_interface_data = host_find_interfaces(); +if (!local_interface_data) local_interface_data = host_find_interfaces(); for (h = host; h != last->next; h = h->next) { - #ifndef STAND_ALONE - if (hosts_treat_as_local != NULL) +#ifndef STAND_ALONE + if (hosts_treat_as_local) { int rc; - const uschar *save = deliver_domain; + const uschar * save = deliver_domain; deliver_domain = h->name; /* set $domain */ rc = match_isinlist(string_copylc(h->name), CUSS &hosts_treat_as_local, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL); deliver_domain = save; if (rc == OK) goto FOUND_LOCAL; } - #endif +#endif /* It seems that on many operating systems, 0.0.0.0 is treated as a synonym for 127.0.0.1 and refers to the local host. We therefore force it always to be treated as local. */ - if (h->address != NULL) + if (h->address) { if (Ustrcmp(h->address, "0.0.0.0") == 0) goto FOUND_LOCAL; for (ip_address_item * ip = local_interface_data; ip; ip = ip->next) @@ -1332,7 +1332,8 @@ for (h = host; h != last->next; h = h->next) /* Update prev to point to the last host item before any that have the same MX value as the one we have just considered. */ - if (h->next == NULL || h->next->mx != h->mx) prev = h; + if (!h->next || h->next->mx != h->mx) + prev = h; } return yield; /* No local hosts found: return HOST_FOUND or HOST_FIND_FAILED */ @@ -1342,7 +1343,7 @@ something in hosts_treat_as_local has been found. */ FOUND_LOCAL: -if (prev == NULL) +if (!prev) { HDEBUG(D_host_lookup) debug_printf((h->mx >= 0)? "local host has lowest MX\n" : @@ -1357,7 +1358,7 @@ HDEBUG(D_host_lookup) debug_printf(" %s %s %d\n", h->name, h->address, h->mx); } -if (removed != NULL) *removed = TRUE; +if (removed) *removed = TRUE; prev->next = last->next; *lastptr = prev; return yield; @@ -1568,8 +1569,7 @@ connection. */ int host_name_lookup(void) { -int old_pool, rc; -int sep = 0; +int sep = 0, old_pool, rc, yield; uschar *save_hostname; uschar **aliases; uschar *ordername; @@ -1581,6 +1581,7 @@ sender_host_dnssec = host_lookup_deferred = host_lookup_failed = FALSE; HDEBUG(D_host_lookup) debug_printf("looking up host name for %s\n", sender_host_address); +expand_level++; /* For testing the case when a lookup does not complete, we have a special reserved IP address. */ @@ -1591,7 +1592,8 @@ if (f.running_in_test_harness && HDEBUG(D_host_lookup) debug_printf("Test harness: host name lookup returns DEFER\n"); host_lookup_deferred = TRUE; - return DEFER; + yield = DEFER; + goto out; } /* Do lookups directly in the DNS or via gethostbyaddr() (or equivalent), in @@ -1649,7 +1651,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) truncated and dn_expand may fail. */ if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, - US (rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0) + US rr->data, (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0) { log_write(0, LOG_MAIN, "host name alias list truncated for %s", sender_host_address); @@ -1689,7 +1691,8 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) HDEBUG(D_host_lookup) debug_printf("IP address PTR lookup gave temporary error\n"); host_lookup_deferred = TRUE; - return DEFER; + yield = DEFER; + goto out; } } @@ -1703,7 +1706,8 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) if (rc == DEFER) { host_lookup_deferred = TRUE; - return rc; /* Can't carry on */ + yield = rc; /* Can't carry on */ + goto out; } if (rc == OK) break; /* Found a name */ } @@ -1719,7 +1723,8 @@ if (!sender_host_name) "address %s", sender_host_address); host_lookup_msg = US" (failed to find host name from IP address)"; host_lookup_failed = TRUE; - return FAIL; + yield = FAIL; + goto out; } HDEBUG(D_host_lookup) @@ -1784,7 +1789,8 @@ for (uschar * hname = sender_host_name; hname; hname = *aliases++) HDEBUG(D_host_lookup) debug_printf("temporary error for host name lookup\n"); host_lookup_deferred = TRUE; sender_host_name = NULL; - return DEFER; + yield = DEFER; + goto out; } else HDEBUG(D_host_lookup) debug_printf("no IP addresses found for %s\n", hname); @@ -1806,12 +1812,12 @@ for (uschar * hname = sender_host_name; hname; hname = *aliases++) /* If sender_host_name == NULL, it means we didn't like the name. Replace it with the first alias, if there is one. */ -if (sender_host_name == NULL && *sender_host_aliases != NULL) +if (!sender_host_name && *sender_host_aliases) sender_host_name = *sender_host_aliases++; /* If we now have a main name, all is well. */ -if (sender_host_name != NULL) return OK; +if (sender_host_name) { yield = OK; goto out; } /* We have failed to find an address that matches. */ @@ -1827,7 +1833,11 @@ host_lookup_msg = string_sprintf(" (%s does not match any IP address for %s)", sender_host_address, save_hostname); store_pool = old_pool; host_lookup_failed = TRUE; -return FAIL; +yield = FAIL; + +out: + expand_level--; + return yield; } @@ -2489,31 +2499,46 @@ Returns: HOST_FIND_FAILED Failed to find the host or domain; */ int -host_find_bydns(host_item *host, const uschar *ignore_target_hosts, int whichrrs, - uschar *srv_service, uschar *srv_fail_domains, uschar *mx_fail_domains, - const dnssec_domains *dnssec_d, - const uschar **fully_qualified_name, BOOL *removed) +host_find_bydns(host_item * host, const uschar * ignore_target_hosts, + int whichrrs, + uschar * srv_service, uschar * srv_fail_domains, uschar * mx_fail_domains, + const dnssec_domains * dnssec_d, + const uschar ** fully_qualified_name, BOOL * removed) { -host_item *h, *last; -int rc = DNS_FAIL; -int ind_type = 0; -int yield; +host_item * h, * last; +int rc = DNS_FAIL, ind_type = 0, yield; dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; -BOOL dnssec_require = dnssec_d +BOOL dnssec_require, dnssec_request; +dnssec_status_t dnssec; + +HDEBUG(D_host_lookup) + { + debug_printf_indent("check dnssec require list\n"); + expand_level++; + } +dnssec_require = dnssec_d && match_isinlist(host->name, CUSS &dnssec_d->require, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK; -BOOL dnssec_request = dnssec_require + +HDEBUG(D_host_lookup) + { + expand_level--; + debug_printf_indent("check dnssec request list\n"); + expand_level++; + } +dnssec_request = dnssec_require || ( dnssec_d && match_isinlist(host->name, CUSS &dnssec_d->request, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK); -dnssec_status_t dnssec; +HDEBUG(D_host_lookup) + expand_level--; /* Set the default fully qualified name to the incoming name, initialize the resolver if necessary, set up the relevant options, and initialize the flag that gets set for DNS syntax check errors. */ -if (fully_qualified_name != NULL) *fully_qualified_name = host->name; +if (fully_qualified_name) *fully_qualified_name = host->name; dns_init((whichrrs & HOST_FIND_QUALIFY_SINGLE) != 0, (whichrrs & HOST_FIND_SEARCH_PARENTS) != 0, dnssec_request); @@ -2525,13 +2550,12 @@ characters, so the code below should be safe. */ if (whichrrs & HOST_FIND_BY_SRV) { - gstring * g; - uschar * temp_fully_qualified_name; + uschar * s, * temp_fully_qualified_name; int prefix_length; - g = string_fmt_append(NULL, "_%s._tcp.%n%.256s", + s = string_sprintf("_%s._tcp.%n%.256s", srv_service, &prefix_length, host->name); - temp_fully_qualified_name = string_from_gstring(g); + temp_fully_qualified_name = s; ind_type = T_SRV; /* Search for SRV records. If the fully qualified name is different to @@ -2547,7 +2571,7 @@ if (whichrrs & HOST_FIND_BY_SRV) if ((dnssec_request || dnssec_require) && !dns_is_secure(dnsa) && dns_is_aa(dnsa)) - debug_printf("DNS lookup of %.256s (SRV) requested AD, but got AA\n", host->name); + debug_printf_indent("DNS lookup of %.256s (SRV) requested AD, but got AA\n", host->name); if (dnssec_request) { @@ -2557,7 +2581,7 @@ if (whichrrs & HOST_FIND_BY_SRV) { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } } - if (temp_fully_qualified_name != g->s && fully_qualified_name != NULL) + if (temp_fully_qualified_name != s && fully_qualified_name) *fully_qualified_name = temp_fully_qualified_name + prefix_length; /* On DNS failures, we give the "try again" error unless the domain is @@ -2576,7 +2600,7 @@ if (whichrrs & HOST_FIND_BY_SRV) &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) != OK) #endif { yield = HOST_FIND_AGAIN; goto out; } - DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA " + DEBUG(D_host_lookup) debug_printf_indent("DNS_%s treated as DNS_NODATA " "(domain in srv_fail_domains)\n", rc == DNS_FAIL ? "FAIL":"AGAIN"); } } @@ -2599,12 +2623,12 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) if ( (dnssec_request || dnssec_require) && !dns_is_secure(dnsa) && dns_is_aa(dnsa)) - debug_printf("DNS lookup of %.256s (MX) requested AD, but got AA\n", host->name); + debug_printf_indent("DNS lookup of %.256s (MX) requested AD, but got AA\n", host->name); if (dnssec_request) if (dns_is_secure(dnsa)) { - DEBUG(D_host_lookup) debug_printf("%s (MX resp) DNSSEC\n", host->name); + DEBUG(D_host_lookup) debug_printf_indent("%s (MX resp) DNSSEC\n", host->name); dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } else @@ -2615,13 +2639,14 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) switch (rc) { case DNS_NOMATCH: - yield = HOST_FIND_FAILED; goto out; + yield = HOST_FIND_FAILED; + goto out; case DNS_SUCCEED: if (!dnssec_require || dns_is_secure(dnsa)) break; DEBUG(D_host_lookup) - debug_printf("dnssec fail on MX for %.256s", host->name); + debug_printf_indent("dnssec fail on MX for %.256s\n", host->name); #ifndef STAND_ALONE if (match_isinlist(host->name, CUSS &mx_fail_domains, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) != OK) @@ -2637,7 +2662,7 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) != OK) #endif { yield = HOST_FIND_AGAIN; goto out; } - DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA " + DEBUG(D_host_lookup) debug_printf_indent("DNS_%s treated as DNS_NODATA " "(domain in mx_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN"); break; } @@ -2651,7 +2676,7 @@ if (rc != DNS_SUCCEED) { if (!(whichrrs & (HOST_FIND_BY_A | HOST_FIND_BY_AAAA))) { - DEBUG(D_host_lookup) debug_printf("Address records are not being sought\n"); + DEBUG(D_host_lookup) debug_printf_indent("Address records are not being sought\n"); yield = HOST_FIND_FAILED; goto out; } @@ -2672,16 +2697,16 @@ if (rc != DNS_SUCCEED) if (rc == HOST_FOUND) rc = host_scan_for_local_hosts(host, &last, removed); - else - if (rc == HOST_IGNORED) rc = HOST_FIND_FAILED; /* No special action */ + else if (rc == HOST_IGNORED) + rc = HOST_FIND_FAILED; /* No special action */ DEBUG(D_host_lookup) if (host->address) { if (fully_qualified_name) - debug_printf("fully qualified name = %s\n", *fully_qualified_name); + debug_printf_indent("fully qualified name = %s\n", *fully_qualified_name); for (host_item * h = host; h != last->next; h = h->next) - debug_printf("%s %s mx=%d sort=%d %s\n", h->name, + debug_printf_indent("%s %s mx=%d sort=%d %s\n", h->name, h->address ? h->address : US"", h->mx, h->sort_key, h->status >= hstatus_unusable ? US"*" : US""); } @@ -2758,7 +2783,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); if (strcmpic(h->name, data) == 0) { DEBUG(D_host_lookup) - debug_printf("discarded duplicate host %s (MX=%d)\n", data, + debug_printf_indent("discarded duplicate host %s (MX=%d)\n", data, precedence > h->mx ? precedence : h->mx); if (precedence >= h->mx) goto NEXT_MX_RR; /* Skip greater precedence */ if (h == host) /* Override first item */ @@ -2868,16 +2893,16 @@ if (ind_type == T_SRV) if (host == last && host->name[0] == 0) { - DEBUG(D_host_lookup) debug_printf("the single SRV record is \".\"\n"); + DEBUG(D_host_lookup) debug_printf_indent("the single SRV record is \".\"\n"); yield = HOST_FIND_FAILED; goto out; } DEBUG(D_host_lookup) { - debug_printf("original ordering of hosts from SRV records:\n"); + debug_printf_indent("original ordering of hosts from SRV records:\n"); for (h = host; h != last->next; h = h->next) - debug_printf(" %s P=%d W=%d\n", h->name, h->mx, h->sort_key % 1000); + debug_printf_indent(" %s P=%d W=%d\n", h->name, h->mx, h->sort_key % 1000); } for (pptr = &host, h = host; h != last; pptr = &h->next, h = h->next) @@ -3070,7 +3095,7 @@ if (h != last && !disable_ipv6) for (h = host; h != last; h = h->next) h->next = next; *next = temp; } -#endif +#endif /*HAVE_IPV6*/ /* Remove any duplicate IP addresses and then scan the list of hosts for any whose IP addresses are on the local host. If any are found, all hosts with the @@ -3088,8 +3113,8 @@ if (rc != HOST_FIND_FAILED) yield = rc; DEBUG(D_host_lookup) { if (fully_qualified_name) - debug_printf("fully qualified name = %s\n", *fully_qualified_name); - debug_printf("host_find_bydns yield = %s (%d); returned hosts:\n", + debug_printf_indent("fully qualified name = %s\n", *fully_qualified_name); + debug_printf_indent("host_find_bydns yield = %s (%d); returned hosts:\n", yield == HOST_FOUND ? "HOST_FOUND" : yield == HOST_FOUND_LOCAL ? "HOST_FOUND_LOCAL" : yield == HOST_FIND_SECURITY ? "HOST_FIND_SECURITY" : @@ -3098,7 +3123,7 @@ DEBUG(D_host_lookup) yield); for (h = host; h != last->next; h = h->next) { - debug_printf(" %s %s MX=%d %s", h->name, + debug_printf_indent(" %s %s MX=%d %s", h->name, !h->address ? US"" : h->address, h->mx, h->dnssec == DS_YES ? US"DNSSEC " : US""); if (h->port != PORT_NONE) debug_printf("port=%d ", h->port); diff --git a/src/src/match.c b/src/src/match.c index 4b128a609..6acbd9f61 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -194,27 +194,23 @@ if (cb->flags & MCS_AT_SPECIAL && pattern[0] == '@') { int rc; host_item h; - BOOL prim = FALSE; - BOOL secy = FALSE; - BOOL removed = FALSE; + BOOL prim = FALSE, secy = FALSE, removed = FALSE; const uschar *ss = pattern + 4; const uschar *ignore_target_hosts = NULL; - if (strncmpic(ss, US"any", 3) == 0) ss += 3; + if (strncmpic(ss, US"any", 3) == 0) + ss += 3; else if (strncmpic(ss, US"primary", 7) == 0) - { - ss += 7; - prim = TRUE; - } + { ss += 7; prim = TRUE; } else if (strncmpic(ss, US"secondary", 9) == 0) - { - ss += 9; - secy = TRUE; - } - else goto NOT_AT_SPECIAL; + { ss += 9; secy = TRUE; } + else + goto NOT_AT_SPECIAL; - if (strncmpic(ss, US"/ignore=", 8) == 0) ignore_target_hosts = ss + 8; - else if (*ss) goto NOT_AT_SPECIAL; + if (strncmpic(ss, US"/ignore=", 8) == 0) + ignore_target_hosts = ss + 8; + else if (*ss) + goto NOT_AT_SPECIAL; h.next = NULL; h.name = s; commit 1137efd94771e13988fd0ca219c575d27d31ad89 Author: Jeremy Harris Date: Fri May 10 14:51:06 2024 +0100 Testsuite: fix munging for ipv6 dns diff --git a/src/src/host.c b/src/src/host.c index 26b3c2c68..1b416997c 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -2204,7 +2204,7 @@ set_address_from_dns(host_item *host, host_item **lastptr, const uschar **fully_qualified_name, BOOL dnssec_request, BOOL dnssec_require, int whichrrs) { -host_item *thishostlast = NULL; /* Indicates not yet filled in anything */ +host_item * thishostlast = NULL; /* Indicates not yet filled in anything */ BOOL v6_find_again = FALSE; BOOL dnssec_fail = FALSE; int i; @@ -2223,12 +2223,12 @@ those sites that feel they have to flaunt the RFC rules. */ if (allow_ip && string_is_ip_address(host->name, NULL) != 0) { - #ifndef STAND_ALONE +#ifndef STAND_ALONE if ( ignore_target_hosts && verify_check_this_host(&ignore_target_hosts, NULL, host->name, host->name, NULL) == OK) return HOST_IGNORED; - #endif +#endif host->address = host->name; return HOST_FOUND; @@ -2242,7 +2242,7 @@ testing, we force an IPv4 lookup if the domain matches dns_ipv4_lookup global. On an IPv4 system, go round the loop once only, looking only for A records. */ #if HAVE_IPV6 - #ifndef STAND_ALONE +# ifndef STAND_ALONE if ( disable_ipv6 || !(whichrrs & HOST_FIND_BY_AAAA) || dns_ipv4_lookup @@ -2251,7 +2251,7 @@ On an IPv4 system, go round the loop once only, looking only for A records. */ ) i = 0; /* look up A records only */ else - #endif /* STAND_ALONE */ +# endif /* STAND_ALONE */ i = 1; /* look up AAAA and A records */ @@ -2628,7 +2628,8 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) if (dnssec_request) if (dns_is_secure(dnsa)) { - DEBUG(D_host_lookup) debug_printf_indent("%s (MX resp) DNSSEC\n", host->name); + DEBUG(D_host_lookup) + debug_printf_indent("%s (MX resp) DNSSEC\n", host->name); dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } else diff --git a/src/src/match.c b/src/src/match.c index 6acbd9f61..956ce60ad 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -427,13 +427,12 @@ unsigned int * original_cache_bits = *cache_ptr; BOOL include_unknown = FALSE, ignore_unknown = FALSE, include_defer = FALSE, ignore_defer = FALSE; const uschar * list; -uschar * sss; -uschar * ot = NULL; +uschar * ot = NULL, * sss; BOOL textonly_re; /* Save time by not scanning for the option name when we don't need it. */ -HDEBUG(D_any) /* always give the query. Give results only for D_lists */ +HDEBUG(D_any) { const uschar * listname = readconf_find_option(listptr); if (*listname) ot = string_sprintf("%s in %s?", name, listname); diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c index 80b12cba2..d3c4349b6 100644 --- a/src/src/routers/dnslookup.c +++ b/src/src/routers/dnslookup.c @@ -286,10 +286,15 @@ for (;;) if (ob->search_parents) flags |= HOST_FIND_SEARCH_PARENTS; } - rc = host_find_bydns(&h, CUS rblock->ignore_target_hosts, flags, - srv_service, ob->srv_fail_domains, ob->mx_fail_domains, - &rblock->dnssec, - &fully_qualified_name, &removed); + DEBUG(D_route) debug_printf_indent("main lookup for domain\n"); + { + expand_level++; + rc = host_find_bydns(&h, CUS rblock->ignore_target_hosts, flags, + srv_service, ob->srv_fail_domains, ob->mx_fail_domains, + &rblock->dnssec, + &fully_qualified_name, &removed); + expand_level--; + } if (removed) setflag(addr, af_local_host_removed); @@ -362,7 +367,7 @@ for (;;) As a common cause of this problem is MX records with IP addresses on the RHS, give a special message in this case. */ - if (h.mx >= 0 && h.address == NULL) + if (h.mx >= 0 && !h.address) { setflag(addr, af_pass_message); /* This is not a security risk */ if (h.name[0] == 0) commit 79c7bae7b372b89a8051ebc7c850ae9339597949 Author: Jeremy Harris Date: Sun May 12 11:49:04 2024 +0100 Fix GNU/Hurd build. Bug 3044 Contributions from Samuel Thibault and Andreas Metzler diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 6dcf18b58..b3bb87c22 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -108,7 +108,7 @@ config.h: Makefile buildconfig ../src/config.h.defaults $(EDITME) # Build the builtin-macros data struct -MACRO_HSRC = macro_predef.h os.h globals.h config.h macros.h \ +MACRO_HSRC = macro_predef.h os.h globals.h config.h macros.h path_max.h \ routers/accept.h routers/dnslookup.h routers/ipliteral.h \ routers/iplookup.h routers/manualroute.h routers/queryprogram.h \ routers/redirect.h @@ -664,7 +664,7 @@ OBJ_MONBIN = util-host_address.o \ $(MONBIN) eximon.bin: $(EXIMON_EDITME) eximon $(OBJ_MONBIN) ../exim_monitor/em_version.c \ - mytypes.h store.h macros.h + mytypes.h store.h path_max.h macros.h @echo "$(CC) exim_monitor/em_version.c" $(FE)$(CC) -o em_version.o -c \ $(CFLAGS) $(XINCLUDE) -I. ../exim_monitor/em_version.c @@ -698,6 +698,7 @@ HDRS = blob.h \ local_scan.h \ macros.h \ mytypes.h \ + path_max.h \ sha_ver.h \ structs.h \ os.h @@ -711,6 +712,7 @@ PHDRS = ../config.h \ ../local_scan.h \ ../macros.h \ ../mytypes.h \ + ../path_max.h \ ../structs.h \ ../os.h diff --git a/src/exim_monitor/em_hdr.h b/src/exim_monitor/em_hdr.h index f79686a80..074fef1d3 100644 --- a/src/exim_monitor/em_hdr.h +++ b/src/exim_monitor/em_hdr.h @@ -99,6 +99,7 @@ this interface so that this kind of kludge isn't needed. */ typedef void * hctx; #include "local_scan.h" +#include "path_max.h" #include "macros.h" #include "structs.h" #include "blob.h" diff --git a/src/exim_monitor/em_version.c b/src/exim_monitor/em_version.c index 4c562925c..432796bff 100644 --- a/src/exim_monitor/em_version.c +++ b/src/exim_monitor/em_version.c @@ -9,19 +9,9 @@ #define EM_VERSION_C -/* Needed by macros.h */ -/* Some systems have PATH_MAX and some have MAX_PATH_LEN. */ - -#ifndef PATH_MAX -# ifdef MAX_PATH_LEN -# define PATH_MAX MAX_PATH_LEN -# else -# define PATH_MAX 1024 -# endif -#endif - #include "mytypes.h" #include "store.h" +#include "path_max.h" #include "macros.h" #include #include diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 352176fa4..03e0b4124 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -98,7 +98,8 @@ cd .. for f in blob.h dbfunctions.h exim.h functions.h globals.h \ hash.h hintsdb.h hintsdb_structs.h local_scan.h \ - macros.h mytypes.h osfunctions.h store.h structs.h lookupapi.h sha_ver.h \ + macros.h mytypes.h osfunctions.h path_max.h store.h \ + structs.h lookupapi.h sha_ver.h \ \ acl.c buildconfig.c base64.c child.c crypt16.c daemon.c dbfn.c debug.c \ deliver.c directory.c dns.c dnsbl.c drtables.c dummies.c enq.c exim.c \ diff --git a/src/src/exim.h b/src/src/exim.h index 699b39165..6baf1fbb4 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -127,16 +127,6 @@ making unique names. */ # define EXIM_ARITH_MIN (-EXIM_ARITH_MAX - 1) #endif -/* Some systems have PATH_MAX and some have MAX_PATH_LEN. */ - -#ifndef PATH_MAX -# ifdef MAX_PATH_LEN -# define PATH_MAX MAX_PATH_LEN -# else -# define PATH_MAX 1024 -# endif -#endif - /* RFC 5321 specifies that the maximum length of a local-part is 64 octets and the maximum length of a domain is 255 octets, but then also defines the maximum length of a forward/reverse path as 256 not 64+1+255. @@ -532,6 +522,7 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. */ #include "local_scan.h" +#include "path_max.h" #include "macros.h" #include "hintsdb.h" #include "hintsdb_structs.h" diff --git a/src/src/os.c b/src/src/os.c index 3b49e4b9e..c4c86df95 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -878,9 +878,7 @@ os_getcwd(unsigned char * buffer, size_t size) return US getcwd(CS buffer, size); } #else -#ifndef PATH_MAX -# define PATH_MAX 4096 -#endif +# include "path_max.h" unsigned char * os_getcwd(unsigned char * buffer, size_t size) { diff --git a/src/src/path_max.h b/src/src/path_max.h new file mode 100644 index 000000000..d8df2c7bc --- /dev/null +++ b/src/src/path_max.h @@ -0,0 +1,19 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) The Exim Maintainers 2024 */ +/* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* This was in exim.h - but not all files needing it can include all of that. */ +/* Needed by macros.h */ +/* Some systems have PATH_MAX and some have MAX_PATH_LEN. */ +#ifndef PATH_MAX +# ifdef MAX_PATH_LEN +# define PATH_MAX MAX_PATH_LEN +# else +# define PATH_MAX 4096 +# endif +#endif + diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 34612adea..ca8e9b0de 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -1999,16 +1999,6 @@ SSL_CTX_free(ob->tls_preload.lib_ctx); ob->tls_preload = null_tls_preload; } -#else - -static void -tls_server_creds_invalidate(void) -{ return; } - -static void -tls_client_creds_invalidate(transport_instance * t) -{ return; } - #endif /*EXIM_HAVE_INOTIFY*/ diff --git a/src/src/tls.c b/src/src/tls.c index e6203b768..0e9a7c534 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -40,13 +40,16 @@ functions from the OpenSSL or GNU TLS libraries. */ static void tls_per_lib_daemon_init(void); static void tls_per_lib_daemon_tick(void); static unsigned tls_server_creds_init(void); -static void tls_server_creds_invalidate(void); static void tls_client_creds_init(transport_instance *, BOOL); -static void tls_client_creds_invalidate(transport_instance *); static void tls_daemon_creds_reload(void); static BOOL opt_set_and_noexpand(const uschar *); static BOOL opt_unset_or_noexpand(const uschar *); +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) +static void tls_server_creds_invalidate(void); +static void tls_client_creds_invalidate(transport_instance *); +#endif + /* This module is compiled only when it is specifically requested in the @@ -324,7 +327,9 @@ tls_client_creds_reload(BOOL watch) for(transport_instance * t = transports; t; t = t->next) if (Ustrcmp(t->driver_name, "smtp") == 0) { +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) tls_client_creds_invalidate(t); +#endif tls_client_creds_init(t, watch); } } @@ -360,7 +365,9 @@ unsigned lifetime; tls_watch_invalidate(); #endif +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) tls_server_creds_invalidate(); +#endif /* _expire is for a time-limited selfsign server cert */ tls_creds_expire = (lifetime = tls_server_creds_init()) commit a2d8f8e2e39b0a24613c03d61355d1f23a481664 Author: Jeremy Harris Date: Tue May 14 12:28:36 2024 +0100 Debug: typo Broken-by: 1d2868b2d90c diff --git a/src/src/deliver.c b/src/src/deliver.c index f3c9203e4..a8376e58c 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -941,7 +941,7 @@ deliver_host = save_host; deliver_localpart = save_local; deliver_domain = save_domain; router_name = save_rn; -router_name = save_tn; +transport_name = save_tn; } #endif /*DISABLE_EVENT*/