X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fsmtp_in.c;h=2c54a4ccfb1d7e1622f93862a4f40f5ea7e6ef51;hp=257c33de1dfd809b27f6a1bd0cf11579eaae0d4b;hb=ba74fb8d95d2e9af2122e0a95c4d5334b4f0466c;hpb=73ec116f6e17189e5a8b284ec9a4433a581adefc diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 257c33de1..2c54a4ccf 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -142,7 +142,7 @@ static struct { BOOL helo_verify :1; BOOL helo_seen :1; BOOL helo_accept_junk :1; -#ifdef SUPPORT_PIPE_CONNECT +#ifndef DISABLE_PIPE_CONNECT BOOL pipe_connect_acceptable :1; #endif BOOL rcpt_smtp_response_same :1; @@ -397,7 +397,7 @@ return TRUE; } -#ifdef SUPPORT_PIPE_CONNECT +#ifndef DISABLE_PIPE_CONNECT static BOOL pipeline_connect_sends(void) { @@ -457,7 +457,7 @@ if (smtp_batched_input) smtp_notquit_exit(US"command-timeout", US"421", US"%s: SMTP command timeout - closing connection", smtp_active_hostname); -exim_exit(EXIT_FAILURE, US"receiving"); +exim_exit(EXIT_FAILURE); } void @@ -468,7 +468,7 @@ if (smtp_batched_input) moan_smtp_batch(NULL, "421 SIGTERM received"); /* Does not return */ smtp_notquit_exit(US"signal-exit", US"421", US"%s: Service not available - closing connection", smtp_active_hostname); -exim_exit(EXIT_FAILURE, US"receiving"); +exim_exit(EXIT_FAILURE); } void @@ -877,6 +877,8 @@ flush for non-TLS connections. The smtp_fflush() function is available for checking that: for convenience, TLS output errors are remembered here so that they are also picked up later by smtp_fflush(). +This function is exposed to the local_scan API; do not change the signature. + Arguments: format format string more further data expected @@ -897,7 +899,10 @@ va_end(ap); /* This is split off so that verify.c:respond_printf() can, in effect, call smtp_printf(), bearing in mind that in C a vararg function can't directly -call another vararg function, only a function which accepts a va_list. */ +call another vararg function, only a function which accepts a va_list. + +This function is exposed to the local_scan API; do not change the signature. +*/ /*XXX consider passing caller-info in, for string_vformat-onward */ void @@ -926,7 +931,7 @@ if (!yield) { log_write(0, LOG_MAIN|LOG_PANIC, "string too large in smtp_printf()"); smtp_closedown(US"Unexpected error"); - exim_exit(EXIT_FAILURE, NULL); + exim_exit(EXIT_FAILURE); } /* If this is the first output for a (non-batch) RCPT command, see if all RCPTs @@ -947,16 +952,13 @@ if (fl.rcpt_in_progress) /* Now write the string */ +if ( #ifndef DISABLE_TLS -if (tls_in.active.sock >= 0) - { - if (tls_write(NULL, gs.s, gs.ptr, more) < 0) - smtp_write_error = -1; - } -else + tls_in.active.sock >= 0 ? (tls_write(NULL, gs.s, gs.ptr, more) < 0) : #endif - -if (fprintf(smtp_out, "%s", gs.s) < 0) smtp_write_error = -1; + (fwrite(gs.s, gs.ptr, 1, smtp_out) == 0) + ) + smtp_write_error = -1; } @@ -967,8 +969,7 @@ if (fprintf(smtp_out, "%s", gs.s) < 0) smtp_write_error = -1; /* This function isn't currently used within Exim (it detects errors when it tries to read the next SMTP input), but is available for use in local_scan(). -For non-TLS connections, it flushes the output and checks for errors. For -TLS-connections, it checks for a previously-detected TLS write error. +It flushes the output and checks for errors. Arguments: none Returns: 0 for no error; -1 after an error @@ -978,6 +979,15 @@ int smtp_fflush(void) { if (tls_in.active.sock < 0 && fflush(smtp_out) != 0) smtp_write_error = -1; + +if ( +#ifndef DISABLE_TLS + tls_in.active.sock >= 0 ? (tls_write(NULL, NULL, 0, FALSE) < 0) : +#endif + (fflush(smtp_out) != 0) + ) + smtp_write_error = -1; + return smtp_write_error; } @@ -2075,13 +2085,14 @@ dkim_collect_input = 0; dkim_verify_overall = dkim_verify_status = dkim_verify_reason = NULL; dkim_key_length = 0; #endif -#ifdef EXPERIMENTAL_DMARC +#ifdef SUPPORT_DMARC f.dmarc_has_been_checked = f.dmarc_disable_verify = f.dmarc_enable_forensic = FALSE; dmarc_domain_policy = dmarc_status = dmarc_status_text = dmarc_used_domain = NULL; #endif #ifdef EXPERIMENTAL_ARC arc_state = arc_state_reason = NULL; +arc_received_instance = 0; #endif dsn_ret = 0; dsn_envid = NULL; @@ -2395,24 +2406,47 @@ return FALSE; static void tfo_in_check(void) { -# ifdef TCP_INFO +# ifdef __FreeBSD__ +int is_fastopen; +socklen_t len = sizeof(is_fastopen); + +/* The tinfo TCPOPT_FAST_OPEN bit seems unreliable, and we don't see state +TCP_SYN_RCV (as of 12.1) so no idea about data-use. */ + +if (getsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_FASTOPEN, &is_fastopen, &len) == 0) + { + if (is_fastopen) + { + DEBUG(D_receive) + debug_printf("TFO mode connection (TCP_FASTOPEN getsockopt)\n"); + f.tcp_in_fastopen = TRUE; + } + } +else DEBUG(D_receive) + debug_printf("TCP_INFO getsockopt: %s\n", strerror(errno)); + +# elif defined(TCP_INFO) struct tcp_info tinfo; socklen_t len = sizeof(tinfo); if (getsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0) -#ifdef TCPI_OPT_SYN_DATA /* FreeBSD 11 does not seem to have this yet */ +# ifdef TCPI_OPT_SYN_DATA /* FreeBSD 11,12 do not seem to have this yet */ if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA) { - DEBUG(D_receive) debug_printf("TCP_FASTOPEN mode connection (ACKd data-on-SYN)\n"); + DEBUG(D_receive) + debug_printf("TFO mode connection (ACKd data-on-SYN)\n"); f.tcp_in_fastopen_data = f.tcp_in_fastopen = TRUE; } else -#endif - if (tinfo.tcpi_state == TCP_SYN_RECV) +# endif + if (tinfo.tcpi_state == TCP_SYN_RECV) /* Not seen on FreeBSD 12.1 */ { - DEBUG(D_receive) debug_printf("TCP_FASTOPEN mode connection (state TCP_SYN_RECV)\n"); + DEBUG(D_receive) + debug_printf("TFO mode connection (state TCP_SYN_RECV)\n"); f.tcp_in_fastopen = TRUE; } +else DEBUG(D_receive) + debug_printf("TCP_INFO getsockopt: %s\n", strerror(errno)); # endif } #endif @@ -2466,7 +2500,7 @@ if (!host_checking && !f.sender_host_notsocket) authenticated_by = NULL; #ifndef DISABLE_TLS -tls_in.cipher = tls_in.peerdn = NULL; +tls_in.ver = tls_in.cipher = tls_in.peerdn = NULL; tls_in.ourcert = tls_in.peercert = NULL; tls_in.sni = NULL; tls_in.ocsp = OCSP_NOT_REQ; @@ -2992,7 +3026,7 @@ while (*p); /* Before we write the banner, check that there is no input pending, unless this synchronisation check is disabled. */ -#ifdef SUPPORT_PIPE_CONNECT +#ifndef DISABLE_PIPE_CONNECT fl.pipe_connect_acceptable = sender_host_address && verify_check_host(&pipe_connect_advertise_hosts) == OK; @@ -3019,7 +3053,7 @@ if (!check_sync()) /*XXX the ehlo-resp code does its own tls/nontls bit. Maybe subroutine that? */ smtp_printf("%s", -#ifdef SUPPORT_PIPE_CONNECT +#ifndef DISABLE_PIPE_CONNECT fl.pipe_connect_acceptable && pipeline_connect_sends(), #else FALSE, @@ -3030,7 +3064,7 @@ smtp_printf("%s", handshake arrived. If so we must have managed a TFO. */ #ifdef TCP_FASTOPEN -tfo_in_check(); +if (sender_host_address && !f.sender_host_notsocket) tfo_in_check(); #endif return TRUE; @@ -3160,7 +3194,7 @@ for (;;) { smtp_printf("%.3s-%.*s%.*s\r\n", TRUE, code, esclen, esc, (int)(nl - msg), msg); msg = nl + 1; - while (isspace(*msg)) msg++; + Uskip_whitespace(&msg); } } } @@ -3714,60 +3748,60 @@ if (rc != OK) switch(rc) { case OK: - if (!au->set_id || set_id) /* Complete success */ - { - if (set_id) authenticated_id = string_copy_perm(set_id, TRUE); - sender_host_authenticated = au->name; - sender_host_auth_pubname = au->public_name; - authentication_failed = FALSE; - authenticated_fail_id = NULL; /* Impossible to already be set? */ - - received_protocol = - (sender_host_address ? protocols : protocols_local) - [pextend + pauthed + (tls_in.active.sock >= 0 ? pcrpted:0)]; - *s = *ss = US"235 Authentication succeeded"; - authenticated_by = au; - break; - } + if (!au->set_id || set_id) /* Complete success */ + { + if (set_id) authenticated_id = string_copy_perm(set_id, TRUE); + sender_host_authenticated = au->name; + sender_host_auth_pubname = au->public_name; + authentication_failed = FALSE; + authenticated_fail_id = NULL; /* Impossible to already be set? */ - /* Authentication succeeded, but we failed to expand the set_id string. - Treat this as a temporary error. */ + received_protocol = + (sender_host_address ? protocols : protocols_local) + [pextend + pauthed + (tls_in.active.sock >= 0 ? pcrpted:0)]; + *s = *ss = US"235 Authentication succeeded"; + authenticated_by = au; + break; + } - auth_defer_msg = expand_string_message; - /* Fall through */ + /* Authentication succeeded, but we failed to expand the set_id string. + Treat this as a temporary error. */ + + auth_defer_msg = expand_string_message; + /* Fall through */ case DEFER: - if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE); - *s = string_sprintf("435 Unable to authenticate at present%s", - auth_defer_user_msg); - *ss = string_sprintf("435 Unable to authenticate at present%s: %s", - set_id, auth_defer_msg); - break; + if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE); + *s = string_sprintf("435 Unable to authenticate at present%s", + auth_defer_user_msg); + *ss = string_sprintf("435 Unable to authenticate at present%s: %s", + set_id, auth_defer_msg); + break; case BAD64: - *s = *ss = US"501 Invalid base64 data"; - break; + *s = *ss = US"501 Invalid base64 data"; + break; case CANCELLED: - *s = *ss = US"501 Authentication cancelled"; - break; + *s = *ss = US"501 Authentication cancelled"; + break; case UNEXPECTED: - *s = *ss = US"553 Initial data not expected"; - break; + *s = *ss = US"553 Initial data not expected"; + break; case FAIL: - if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE); - *s = US"535 Incorrect authentication data"; - *ss = string_sprintf("535 Incorrect authentication data%s", set_id); - break; + if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE); + *s = US"535 Incorrect authentication data"; + *ss = string_sprintf("535 Incorrect authentication data%s", set_id); + break; default: - if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE); - *s = US"435 Internal error"; - *ss = string_sprintf("435 Internal error%s: return %d from authentication " - "check", set_id, rc); - break; + if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE); + *s = US"435 Internal error"; + *ss = string_sprintf("435 Internal error%s: return %d from authentication " + "check", set_id, rc); + break; } return rc; @@ -3970,7 +4004,7 @@ while (done <= 0) #endif switch(smtp_read_command( -#ifdef SUPPORT_PIPE_CONNECT +#ifndef DISABLE_PIPE_CONNECT !fl.pipe_connect_acceptable, #else TRUE, @@ -4206,7 +4240,7 @@ while (done <= 0) host_build_sender_fullhost(); /* Rebuild */ break; } -#ifdef SUPPORT_PIPE_CONNECT +#ifndef DISABLE_PIPE_CONNECT else if (!fl.pipe_connect_acceptable && !check_sync()) #else else if (!check_sync()) @@ -4339,7 +4373,7 @@ while (done <= 0) sync_cmd_limit = NON_SYNC_CMD_PIPELINING; f.smtp_in_pipelining_advertised = TRUE; -#ifdef SUPPORT_PIPE_CONNECT +#ifndef DISABLE_PIPE_CONNECT if (fl.pipe_connect_acceptable) { f.smtp_in_early_pipe_advertised = TRUE; @@ -4374,8 +4408,8 @@ while (done <= 0) if (au->server) { DEBUG(D_auth+D_expand) debug_printf_indent( - "Evaluating advertise_condition for %s athenticator\n", - au->public_name); + "Evaluating advertise_condition for %s %s athenticator\n", + au->name, au->public_name); if ( !au->advertise_condition || expand_check_condition(au->advertise_condition, au->name, US"authenticator") @@ -4457,7 +4491,7 @@ while (done <= 0) #ifndef DISABLE_TLS if (tls_in.active.sock >= 0) (void)tls_write(NULL, g->s, g->ptr, -# ifdef SUPPORT_PIPE_CONNECT +# ifndef DISABLE_PIPE_CONNECT fl.pipe_connect_acceptable && pipeline_connect_sends()); # else FALSE); @@ -5235,7 +5269,7 @@ while (done <= 0) f.dot_ends = TRUE; DATA_BDAT: /* Common code for DATA and BDAT */ -#ifdef SUPPORT_PIPE_CONNECT +#ifndef DISABLE_PIPE_CONNECT fl.pipe_connect_acceptable = FALSE; #endif if (!discarded && recipients_count <= 0) @@ -5725,7 +5759,7 @@ while (done <= 0) oldsignal = signal(SIGCHLD, SIG_IGN); - if ((pid = fork()) == 0) + if ((pid = exim_fork(US"etrn-command")) == 0) { smtp_input = FALSE; /* This process is not associated with the */ (void)fclose(smtp_in); /* SMTP call any more. */ @@ -5736,7 +5770,8 @@ while (done <= 0) /* If not serializing, do the exec right away. Otherwise, fork down into another process. */ - if (!smtp_etrn_serialize || (pid = fork()) == 0) + if ( !smtp_etrn_serialize + || (pid = exim_fork(US"etrn-serialised-command")) == 0) { DEBUG(D_exec) debug_print_argv(argv); exim_nullstd(); /* Ensure std{in,out,err} exist */