X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/dec766a1977250758eb7a3e127e079a9271afd89..74f1a42304ce056cf979d22fb970faae161e3ab2:/src/src/smtp_in.c diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index c45e7e26f..0afb97ca6 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -340,7 +340,7 @@ fd_set fds; struct timeval tzero; #ifdef SUPPORT_TLS -if (tls_in.active >= 0) +if (tls_in.active.sock >= 0) return !tls_could_read(); #endif @@ -359,16 +359,13 @@ rc = smtp_getc(GETC_BUFFER_UNLIMITED); if (rc < 0) return TRUE; /* End of file or error */ smtp_ungetc(rc); -rc = smtp_inend - smtp_inptr; -if (rc > 150) rc = 150; -smtp_inptr[rc] = 0; return FALSE; } static BOOL check_sync(void) { -if (!smtp_enforce_sync || sender_host_address == NULL || sender_host_notsocket) +if (!smtp_enforce_sync || !sender_host_address || sender_host_notsocket) return TRUE; return wouldblock_reading(); @@ -427,6 +424,53 @@ log_write(L_smtp_incomplete_transaction, LOG_MAIN|LOG_SENDER|LOG_RECIPIENTS, +void +smtp_command_timeout_exit(void) +{ +log_write(L_lost_incoming_connection, + LOG_MAIN, "SMTP command timeout on%s connection from %s", + tls_in.active.sock >= 0 ? " TLS" : "", host_and_ident(FALSE)); +if (smtp_batched_input) + moan_smtp_batch(NULL, "421 SMTP command timeout"); /* Does not return */ +smtp_notquit_exit(US"command-timeout", US"421", + US"%s: SMTP command timeout - closing connection", + smtp_active_hostname); +exim_exit(EXIT_FAILURE, US"receiving"); +} + +void +smtp_command_sigterm_exit(void) +{ +log_write(0, LOG_MAIN, "%s closed after SIGTERM", smtp_get_connection_info()); +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"); +} + +void +smtp_data_timeout_exit(void) +{ +log_write(L_lost_incoming_connection, + LOG_MAIN, "SMTP data timeout (message abandoned) on connection from %s F=<%s>", + sender_fullhost ? sender_fullhost : US"local process", sender_address); +receive_bomb_out(US"data-timeout", US"SMTP incoming data timeout"); +/* Does not return */ +} + +void +smtp_data_sigint_exit(void) +{ +log_write(0, LOG_MAIN, "%s closed after %s", + smtp_get_connection_info(), had_data_sigint == SIGTERM ? "SIGTERM":"SIGINT"); +receive_bomb_out(US"signal-exit", + US"Service not available - SIGTERM or SIGINT received"); +/* Does not return */ +} + + + /* Refill the buffer, and notify DKIM verification code. Return false for error or EOF. */ @@ -439,22 +483,33 @@ if (!smtp_out) return FALSE; fflush(smtp_out); if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout); -/* Limit amount read, so non-message data is not fed to DKIM */ +/* Limit amount read, so non-message data is not fed to DKIM. +Take care to not touch the safety NUL at the end of the buffer. */ -rc = read(fileno(smtp_in), smtp_inbuffer, MIN(IN_BUFFER_SIZE, lim)); +rc = read(fileno(smtp_in), smtp_inbuffer, MIN(IN_BUFFER_SIZE-1, lim)); save_errno = errno; -alarm(0); +if (smtp_receive_timeout > 0) alarm(0); if (rc <= 0) { /* Must put the error text in fixed store, because this might be during header reading, where it releases unused store above the header. */ if (rc < 0) { + if (had_command_timeout) /* set by signal handler */ + smtp_command_timeout_exit(); /* does not return */ + if (had_command_sigterm) + smtp_command_sigterm_exit(); + if (had_data_timeout) + smtp_data_timeout_exit(); + if (had_data_sigint) + smtp_data_sigint_exit(); + smtp_had_error = save_errno; smtp_read_error = string_copy_malloc( string_sprintf(" (error: %s)", strerror(save_errno))); } - else smtp_had_eof = 1; + else + smtp_had_eof = 1; return FALSE; } #ifndef DISABLE_DKIM @@ -540,7 +595,7 @@ uschar * log_msg; for(;;) { #ifndef DISABLE_DKIM - BOOL dkim_save; + unsigned dkim_save; #endif if (chunking_data_left > 0) @@ -551,7 +606,7 @@ for(;;) receive_ungetc = lwr_receive_ungetc; #ifndef DISABLE_DKIM dkim_save = dkim_collect_input; - dkim_collect_input = FALSE; + dkim_collect_input = 0; #endif /* Unless PIPELINING was offered, there should be no next command @@ -653,7 +708,7 @@ next_cmd: } receive_getc = bdat_getc; - receive_getbuf = bdat_getbuf; + receive_getbuf = bdat_getbuf; /* r~getbuf is never actually used */ receive_ungetc = bdat_ungetc; #ifndef DISABLE_DKIM dkim_collect_input = dkim_save; @@ -684,7 +739,7 @@ bdat_flush_data(void) while (chunking_data_left) { unsigned n = chunking_data_left; - (void) bdat_getbuf(&n); + if (!bdat_getbuf(&n)) break; } receive_getc = lwr_receive_getc; @@ -867,9 +922,9 @@ if (rcpt_in_progress) /* Now write the string */ #ifdef SUPPORT_TLS -if (tls_in.active >= 0) +if (tls_in.active.sock >= 0) { - if (tls_write(TRUE, big_buffer, Ustrlen(big_buffer), more) < 0) + if (tls_write(NULL, big_buffer, Ustrlen(big_buffer), more) < 0) smtp_write_error = -1; } else @@ -896,7 +951,7 @@ Returns: 0 for no error; -1 after an error int smtp_fflush(void) { -if (tls_in.active < 0 && fflush(smtp_out) != 0) smtp_write_error = -1; +if (tls_in.active.sock < 0 && fflush(smtp_out) != 0) smtp_write_error = -1; return smtp_write_error; } @@ -916,16 +971,7 @@ Returns: nothing static void command_timeout_handler(int sig) { -sig = sig; /* Keep picky compilers happy */ -log_write(L_lost_incoming_connection, - LOG_MAIN, "SMTP command timeout on%s connection from %s", - (tls_in.active >= 0)? " TLS" : "", - host_and_ident(FALSE)); -if (smtp_batched_input) - moan_smtp_batch(NULL, "421 SMTP command timeout"); /* Does not return */ -smtp_notquit_exit(US"command-timeout", US"421", - US"%s: SMTP command timeout - closing connection", smtp_active_hostname); -exim_exit(EXIT_FAILURE, US"receiving"); +had_command_timeout = sig; } @@ -943,13 +989,7 @@ Returns: nothing static void command_sigterm_handler(int sig) { -sig = sig; /* Keep picky compilers happy */ -log_write(0, LOG_MAIN, "%s closed after SIGTERM", smtp_get_connection_info()); -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"); +had_command_sigterm = sig; } @@ -1509,6 +1549,7 @@ int ptr = 0; smtp_cmd_list *p; BOOL hadnull = FALSE; +had_command_timeout = 0; os_non_restarting_signal(SIGALRM, command_timeout_handler); while ((c = (receive_getc)(buffer_lim)) != '\n' && c != EOF) @@ -1614,11 +1655,11 @@ if (proxy_session && proxy_session_failed) /* Enforce synchronization for unknown commands */ -if (smtp_inptr < smtp_inend && /* Outstanding input */ - check_sync && /* Local flag set */ - smtp_enforce_sync && /* Global flag set */ - sender_host_address != NULL && /* Not local input */ - !sender_host_notsocket) /* Really is a socket */ +if ( smtp_inptr < smtp_inend /* Outstanding input */ + && check_sync /* Local flag set */ + && smtp_enforce_sync /* Global flag set */ + && sender_host_address /* Not local input */ + && !sender_host_notsocket) /* Really is a socket */ return BADSYN_CMD; return OTHER_CMD; @@ -1947,13 +1988,13 @@ return TRUE; *************************************************/ /* This function is called whenever the SMTP session is reset from -within either of the setup functions. +within either of the setup functions; also from the daemon loop. Argument: the stacking pool storage reset point Returns: nothing */ -static void +void smtp_reset(void *reset_point) { recipients_list = NULL; @@ -1980,8 +2021,8 @@ active_local_sender_retain = local_sender_retain; /* Can be set by ACL */ sending_ip_address = NULL; return_path = sender_address = NULL; sender_data = NULL; /* Can be set by ACL */ -deliver_localpart_orig = NULL; -deliver_domain_orig = NULL; +deliver_localpart_parent = deliver_localpart_orig = NULL; +deliver_domain_parent = deliver_domain_orig = NULL; callout_address = NULL; submission_name = NULL; /* Can be set by ACL */ raw_sender = NULL; /* After SMTP rewrite, before qualifying */ @@ -1996,10 +2037,27 @@ bmi_run = 0; bmi_verdicts = NULL; #endif dnslist_domain = dnslist_matched = NULL; +#ifdef SUPPORT_SPF +spf_header_comment = spf_received = spf_result = spf_smtp_comment = NULL; +spf_result_guessed = FALSE; +#endif #ifndef DISABLE_DKIM -dkim_signers = NULL; +dkim_cur_signer = dkim_signers = +dkim_signing_domain = dkim_signing_selector = dkim_signatures = NULL; +dkim_cur_signer = dkim_signers = dkim_signing_domain = dkim_signing_selector = NULL; dkim_disable_verify = FALSE; -dkim_collect_input = FALSE; +dkim_collect_input = 0; +dkim_verify_overall = dkim_verify_status = dkim_verify_reason = NULL; +dkim_key_length = 0; +dkim_verify_signers = US"$dkim_signers"; +#endif +#ifdef EXPERIMENTAL_DMARC +dmarc_has_been_checked = dmarc_disable_verify = 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; #endif dsn_ret = 0; dsn_envid = NULL; @@ -2007,12 +2065,6 @@ deliver_host = deliver_host_address = NULL; /* Can be set by ACL */ #ifndef DISABLE_PRDR prdr_requested = FALSE; #endif -#ifdef SUPPORT_SPF -spf_header_comment = NULL; -spf_received = NULL; -spf_result = NULL; -spf_smtp_comment = NULL; -#endif #ifdef SUPPORT_I18N message_smtputf8 = FALSE; #endif @@ -2375,7 +2427,8 @@ smtp_exit_function_called = FALSE; /* For avoiding loop in not-quit exit */ /* If receiving by -bs from a trusted user, or testing with -bh, we allow authentication settings from -oMaa to remain in force. */ -if (!host_checking && !sender_host_notsocket) sender_host_authenticated = NULL; +if (!host_checking && !sender_host_notsocket) + sender_host_auth_pubname = sender_host_authenticated = NULL; authenticated_by = NULL; #ifdef SUPPORT_TLS @@ -2419,10 +2472,12 @@ else (sender_host_address ? protocols : protocols_local) [pnormal]; /* Set up the buffer for inputting using direct read() calls, and arrange to -call the local functions instead of the standard C ones. */ +call the local functions instead of the standard C ones. Place a NUL at the +end of the buffer to safety-stop C-string reads from it. */ if (!(smtp_inbuffer = US malloc(IN_BUFFER_SIZE))) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "malloc() failed for SMTP input buffer"); +smtp_inbuffer[IN_BUFFER_SIZE-1] = '\0'; receive_getc = smtp_getc; receive_getbuf = smtp_getbuf; @@ -3625,12 +3680,13 @@ switch(rc) { if (set_id) authenticated_id = string_copy_malloc(set_id); 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 >= 0 ? pcrpted:0)]; + [pextend + pauthed + (tls_in.active.sock >= 0 ? pcrpted:0)]; *s = *ss = US"235 Authentication succeeded"; authenticated_by = au; break; @@ -3724,7 +3780,7 @@ else smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname); #ifdef SUPPORT_TLS -tls_close(TRUE, TLS_SHUTDOWN_NOWAIT); +tls_close(NULL, TLS_SHUTDOWN_NOWAIT); #endif log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT", @@ -3800,6 +3856,7 @@ cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = TRUE; /* Set the local signal handler for SIGTERM - it tries to end off tidily */ +had_command_sigterm = 0; os_non_restarting_signal(SIGTERM, command_sigterm_handler); /* Batched SMTP is handled in a different function. */ @@ -3834,7 +3891,7 @@ while (done <= 0) #ifdef AUTH_TLS /* Check once per STARTTLS or SSL-on-connect for a TLS AUTH */ - if ( tls_in.active >= 0 + if ( tls_in.active.sock >= 0 && tls_in.peercert && tls_in.certificate_verified && cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd @@ -4051,7 +4108,7 @@ while (done <= 0) host_build_sender_fullhost(); /* Rebuild */ set_process_info("handling%s incoming connection from %s", - (tls_in.active >= 0)? " TLS" : "", host_and_ident(FALSE)); + (tls_in.active.sock >= 0)? " TLS" : "", host_and_ident(FALSE)); /* Verify if configured. This doesn't give much security, but it does make some people happy to be able to do it. If helo_required is set, @@ -4307,7 +4364,7 @@ while (done <= 0) secure connection. */ #ifdef SUPPORT_TLS - if (tls_in.active < 0 && + if (tls_in.active.sock < 0 && verify_check_host(&tls_advertise_hosts) != FAIL) { g = string_catn(g, smtp_code, 3); @@ -4345,7 +4402,7 @@ while (done <= 0) has been seen. */ #ifdef SUPPORT_TLS - if (tls_in.active >= 0) (void)tls_write(TRUE, g->s, g->ptr, FALSE); else + if (tls_in.active.sock >= 0) (void)tls_write(NULL, g->s, g->ptr, FALSE); else #endif { @@ -4368,7 +4425,7 @@ while (done <= 0) [ (esmtp ? pextend + (sender_host_authenticated ? pauthed : 0) : pnormal) - + (tls_in.active >= 0 ? pcrpted : 0) + + (tls_in.active.sock >= 0 ? pcrpted : 0) ]; cancel_cutthrough_connection(TRUE, US"sent EHLO response"); smtp_reset(reset_point); @@ -4556,10 +4613,10 @@ while (done <= 0) US"invalid data for AUTH"); goto COMMAND_LOOP; } - if (acl_smtp_mailauth == NULL) + if (!acl_smtp_mailauth) { ignore_msg = US"client not authenticated"; - rc = (sender_host_authenticated != NULL)? OK : FAIL; + rc = sender_host_authenticated ? OK : FAIL; } else { @@ -5156,7 +5213,7 @@ while (done <= 0) ACL may have delayed. To handle cutthrough delivery enforce a dummy call to get the DATA command sent. */ - if (acl_smtp_predata == NULL && cutthrough.fd < 0) + if (acl_smtp_predata == NULL && cutthrough.cctx.sock < 0) rc = OK; else { @@ -5310,7 +5367,7 @@ while (done <= 0) { DEBUG(D_any) debug_printf("Non-empty input buffer after STARTTLS; naive attack?\n"); - if (tls_in.active < 0) + if (tls_in.active.sock < 0) smtp_inend = smtp_inptr = smtp_inbuffer; /* and if TLS is already active, tls_server_start() should fail */ } @@ -5353,10 +5410,10 @@ while (done <= 0) [ (esmtp ? pextend + (sender_host_authenticated ? pauthed : 0) : pnormal) - + (tls_in.active >= 0 ? pcrpted : 0) + + (tls_in.active.sock >= 0 ? pcrpted : 0) ]; - sender_host_authenticated = NULL; + sender_host_auth_pubname = sender_host_authenticated = NULL; authenticated_id = NULL; sync_cmd_limit = NON_SYNC_CMD_NON_PIPELINING; DEBUG(D_tls) debug_printf("TLS active\n"); @@ -5413,7 +5470,7 @@ while (done <= 0) smtp_printf("554 Security failure\r\n", FALSE); break; } - tls_close(TRUE, TLS_SHUTDOWN_NOWAIT); + tls_close(NULL, TLS_SHUTDOWN_NOWAIT); break; #endif @@ -5455,7 +5512,7 @@ while (done <= 0) buffer[0] = 0; Ustrcat(buffer, " AUTH"); #ifdef SUPPORT_TLS - if (tls_in.active < 0 && + if (tls_in.active.sock < 0 && verify_check_host(&tls_advertise_hosts) != FAIL) Ustrcat(buffer, " STARTTLS"); #endif @@ -5668,8 +5725,8 @@ while (done <= 0) case BADCHAR_CMD: done = synprot_error(L_smtp_syntax_error, 0, NULL, /* Just logs */ - US"NULL character(s) present (shown as '?')"); - smtp_printf("501 NULL characters are not allowed in SMTP commands\r\n", FALSE); + US"NUL character(s) present (shown as '?')"); + smtp_printf("501 NUL characters are not allowed in SMTP commands\r\n", FALSE); break; @@ -5678,7 +5735,7 @@ while (done <= 0) if (smtp_inend >= smtp_inbuffer + IN_BUFFER_SIZE) smtp_inend = smtp_inbuffer + IN_BUFFER_SIZE - 1; c = smtp_inend - smtp_inptr; - if (c > 150) c = 150; + if (c > 150) c = 150; /* limit logged amount */ smtp_inptr[c] = 0; incomplete_transaction_log(US"sync failure"); log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error " @@ -5751,8 +5808,15 @@ authres_smtpauth(gstring * g) if (!sender_host_authenticated) return g; -g = string_append(g, 4, US";\n\tauth=pass" - " (", sender_host_authenticated, US") smtp.auth=", authenticated_id); +g = string_append(g, 2, US";\n\tauth=pass (", sender_host_auth_pubname); + +if (Ustrcmp(sender_host_auth_pubname, "tls") != 0) + g = string_append(g, 2, US") smtp.auth=", authenticated_id); +else if (authenticated_id) + g = string_append(g, 2, US") x509.auth=", authenticated_id); +else + g = string_catn(g, US") reason=x509.auth", 17); + if (authenticated_sender) g = string_append(g, 2, US" smtp.mailfrom=", authenticated_sender); return g;