X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/db889856a56c1da9d18fc2f676b4aad2d45dc585..a1108b5118d32e969c5fe91b2110944f7483a7cb:/src/src/smtp_in.c diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 69eae3cb4..d60e7d5c5 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -347,7 +347,7 @@ wouldblock_reading(void) { int fd, rc; fd_set fds; -struct timeval tzero; +struct timeval tzero = {.tv_sec = 0, .tv_usec = 0}; #ifndef DISABLE_TLS if (tls_in.active.sock >= 0) @@ -360,8 +360,6 @@ if (smtp_inptr < smtp_inend) fd = fileno(smtp_in); FD_ZERO(&fds); FD_SET(fd, &fds); -tzero.tv_sec = 0; -tzero.tv_usec = 0; rc = select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tzero); if (rc <= 0) return TRUE; /* Not ready to read */ @@ -587,6 +585,8 @@ smtp_get_cache(void) { #ifndef DISABLE_DKIM int n = smtp_inend - smtp_inptr; +if (chunking_state == CHUNKING_LAST && chunking_data_left < n) + n = chunking_data_left; if (n > 0) dkim_exim_verify_feed(smtp_inptr, n); #endif @@ -1213,13 +1213,11 @@ int size, ret; int fd = fileno(smtp_in); const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"; uschar * iptype; /* To display debug info */ -struct timeval tv; -struct timeval tvtmp; socklen_t vslen = sizeof(struct timeval); BOOL yield = FALSE; os_non_restarting_signal(SIGALRM, command_timeout_handler); -ALARM(PROXY_NEGOTIATION_TIMEOUT_SEC); +ALARM(proxy_protocol_timeout); do { @@ -2111,7 +2109,11 @@ while (acl_warn_logged) acl_warn_logged = acl_warn_logged->next; store_free(this); } + +message_tidyup(); store_reset(reset_point); + +message_start(); return store_mark(); } @@ -2188,7 +2190,7 @@ while (done <= 0) case MAIL_CMD: smtp_mailcmd_count++; /* Count for no-mail log */ - if (sender_address != NULL) + if (sender_address) /* The function moan_smtp_batch() does not return. */ moan_smtp_batch(smtp_cmd_buffer, "503 Sender already given"); @@ -2895,7 +2897,7 @@ if (!f.sender_host_unknown) if (smtp_batched_input) return TRUE; /* If valid Proxy Protocol source is connecting, set up session. - * Failure will not allow any SMTP function other than QUIT. */ +Failure will not allow any SMTP function other than QUIT. */ #ifdef SUPPORT_PROXY proxy_session = FALSE; @@ -2904,16 +2906,16 @@ if (check_proxy_protocol_host()) setup_proxy_protocol_host(); #endif - /* Start up TLS if tls_on_connect is set. This is for supporting the legacy - smtps port for use with older style SSL MTAs. */ +/* Start up TLS if tls_on_connect is set. This is for supporting the legacy +smtps port for use with older style SSL MTAs. */ #ifndef DISABLE_TLS - if (tls_in.on_connect) - { - if (tls_server_start(&user_msg) != OK) - return smtp_log_tls_fail(user_msg); - cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE; - } +if (tls_in.on_connect) + { + if (tls_server_start(&user_msg) != OK) + return smtp_log_tls_fail(user_msg); + cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE; + } #endif /* Run the connect ACL if it exists */ @@ -3281,18 +3283,7 @@ int codelen = 3; uschar *smtp_code; uschar *lognl; uschar *sender_info = US""; -uschar *what = -#ifdef WITH_CONTENT_SCAN - where == ACL_WHERE_MIME ? US"during MIME ACL checks" : -#endif - where == ACL_WHERE_PREDATA ? US"DATA" : - where == ACL_WHERE_DATA ? US"after DATA" : -#ifndef DISABLE_PRDR - where == ACL_WHERE_PRDR ? US"after DATA PRDR" : -#endif - smtp_cmd_data ? - string_sprintf("%s %s", acl_wherenames[where], smtp_cmd_data) : - string_sprintf("%s in \"connect\" ACL", acl_wherenames[where]); +uschar *what; if (drop) rc = FAIL; @@ -3308,19 +3299,45 @@ fixed, sender_address at this point became the rewritten address. I'm not sure this is what should be logged, so I've changed to logging the unrewritten address to retain backward compatibility. */ -#ifndef WITH_CONTENT_SCAN -if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA) -#else -if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA || where == ACL_WHERE_MIME) +switch (where) + { +#ifdef WITH_CONTENT_SCAN + case ACL_WHERE_MIME: what = US"during MIME ACL checks"; break; +#endif + case ACL_WHERE_PREDATA: what = US"DATA"; break; + case ACL_WHERE_DATA: what = US"after DATA"; break; +#ifndef DISABLE_PRDR + case ACL_WHERE_PRDR: what = US"after DATA PRDR"; break; #endif + default: + { + uschar * place = smtp_cmd_data ? smtp_cmd_data : US"in \"connect\" ACL"; + int lim = 100; + + if (where == ACL_WHERE_AUTH) /* avoid logging auth creds */ + { + uschar * s; + for (s = smtp_cmd_data; *s && !isspace(*s); ) s++; + lim = s - smtp_cmd_data; /* atop after method */ + } + what = string_sprintf("%s %.*s", acl_wherenames[where], lim, place); + } + } +switch (where) { - sender_info = string_sprintf("F=<%s>%s%s%s%s ", - sender_address_unrewritten ? sender_address_unrewritten : sender_address, - sender_host_authenticated ? US" A=" : US"", - sender_host_authenticated ? sender_host_authenticated : US"", - sender_host_authenticated && authenticated_id ? US":" : US"", - sender_host_authenticated && authenticated_id ? authenticated_id : US"" - ); + case ACL_WHERE_RCPT: + case ACL_WHERE_DATA: +#ifdef WITH_CONTENT_SCAN + case ACL_WHERE_MIME: +#endif + sender_info = string_sprintf("F=<%s>%s%s%s%s ", + sender_address_unrewritten ? sender_address_unrewritten : sender_address, + sender_host_authenticated ? US" A=" : US"", + sender_host_authenticated ? sender_host_authenticated : US"", + sender_host_authenticated && authenticated_id ? US":" : US"", + sender_host_authenticated && authenticated_id ? authenticated_id : US"" + ); + break; } /* If there's been a sender verification failure with a specific message, and @@ -3821,8 +3838,8 @@ if ( acl_smtp_quit log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s", *log_msgp); -#ifdef TCP_CORK -(void) setsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_CORK, US &on, sizeof(on)); +#ifdef EXIM_TCP_CORK +(void) setsockopt(fileno(smtp_out), IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on)); #endif if (*user_msgp) @@ -3830,12 +3847,35 @@ if (*user_msgp) else smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname); -#ifndef DISABLE_TLS +#ifdef SERVERSIDE_CLOSE_NOWAIT +# ifndef DISABLE_TLS tls_close(NULL, TLS_SHUTDOWN_NOWAIT); -#endif +# endif + +log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT", + smtp_get_connection_info()); +#else + +# ifndef DISABLE_TLS +tls_close(NULL, TLS_SHUTDOWN_WAIT); +# endif log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT", smtp_get_connection_info()); + +/* Pause, hoping client will FIN first so that they get the TIME_WAIT. +The socket should become readble (though with no data) */ + + { + int fd = fileno(smtp_in); + fd_set fds; + struct timeval t_limit = {.tv_sec = 0, .tv_usec = 200*1000}; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + (void) select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &t_limit); + } +#endif /*!DAEMON_CLOSE_NOWAIT*/ } @@ -3849,6 +3889,13 @@ cmd_list[CMD_LIST_RSET].is_mail_cmd = FALSE; } +static int +expand_mailmax(const uschar * s) +{ +if (!(s = expand_cstring(s))) + log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand smtp_accept_max_per_connection"); +return *s ? Uatoi(s) : 0; +} /************************************************* * Initialize for SMTP incoming message * @@ -3879,6 +3926,7 @@ int smtp_setup_msg(void) { int done = 0; +int mailmax = -1; BOOL toomany = FALSE; BOOL discarded = FALSE; BOOL last_was_rej_mail = FALSE; @@ -3914,6 +3962,12 @@ os_non_restarting_signal(SIGTERM, command_sigterm_handler); if (smtp_batched_input) return smtp_setup_batch_msg(); +#ifdef TCP_QUICKACK +if (smtp_in) /* Avoid pure-ACKs while in cmd pingpong phase */ + (void) setsockopt(fileno(smtp_in), IPPROTO_TCP, TCP_QUICKACK, + US &off, sizeof(off)); +#endif + /* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE value. The values are 2 larger than the required yield of the function. */ @@ -3971,12 +4025,6 @@ while (done <= 0) } #endif -#ifdef TCP_QUICKACK - if (smtp_in) /* Avoid pure-ACKs while in cmd pingpong phase */ - (void) setsockopt(fileno(smtp_in), IPPROTO_TCP, TCP_QUICKACK, - US &off, sizeof(off)); -#endif - switch(smtp_read_command( #ifndef DISABLE_PIPE_CONNECT !fl.pipe_connect_acceptable, @@ -4037,21 +4085,18 @@ while (done <= 0) /* Find the name of the requested authentication mechanism. */ s = smtp_cmd_data; - while ((c = *smtp_cmd_data) != 0 && !isspace(c)) - { + for (; (c = *smtp_cmd_data) && !isspace(c); smtp_cmd_data++) if (!isalnum(c) && c != '-' && c != '_') { done = synprot_error(L_smtp_syntax_error, 501, NULL, US"invalid character in authentication mechanism name"); goto COMMAND_LOOP; } - smtp_cmd_data++; - } /* If not at the end of the line, we must be at white space. Terminate the name and move the pointer on to any data that may be present. */ - if (*smtp_cmd_data != 0) + if (*smtp_cmd_data) { *smtp_cmd_data++ = 0; while (isspace(*smtp_cmd_data)) smtp_cmd_data++; @@ -4239,6 +4284,9 @@ while (done <= 0) fl.smtputf8_advertised = FALSE; #endif + /* Expand the per-connection message count limit option */ + mailmax = expand_mailmax(smtp_accept_max_per_connection); + smtp_code = US"250 "; /* Default response code plus space*/ if (!user_msg) { @@ -4298,6 +4346,19 @@ while (done <= 0) g = string_catn(g, US"-SIZE\r\n", 7); } +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if ( (mailmax > 0 || recipients_max) + && verify_check_host(&limits_advertise_hosts) == OK) + { + g = string_fmt_append(g, "%.3s-LIMITS", smtp_code); + if (mailmax > 0) + g = string_fmt_append(g, " MAILMAX=%d", mailmax); + if (recipients_max) + g = string_fmt_append(g, " RCPTMAX=%d", recipients_max); + g = string_catn(g, US"\r\n", 2); + } +#endif + /* Exim does not do protocol conversion or data conversion. It is 8-bit clean; if it has an 8-bit character in its hand, it just sends it. It cannot therefore specify 8BITMIME and remain consistent with the RFCs. @@ -4510,16 +4571,20 @@ while (done <= 0) case MAIL_CMD: HAD(SCH_MAIL); smtp_mailcmd_count++; /* Count for limit and ratelimit */ + message_start(); was_rej_mail = TRUE; /* Reset if accepted */ env_mail_type_t * mail_args; /* Sanity check & validate args */ - if (fl.helo_required && !fl.helo_seen) - { - smtp_printf("503 HELO or EHLO required\r\n", FALSE); - log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no " - "HELO/EHLO given", host_and_ident(FALSE)); - break; - } + if (!fl.helo_seen) + if (fl.helo_required) + { + smtp_printf("503 HELO or EHLO required\r\n", FALSE); + log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no " + "HELO/EHLO given", host_and_ident(FALSE)); + break; + } + else if (mailmax < 0) + mailmax = expand_mailmax(smtp_accept_max_per_connection); if (sender_address) { @@ -4538,8 +4603,7 @@ while (done <= 0) /* Check to see if the limit for messages per connection would be exceeded by accepting further messages. */ - if (smtp_accept_max_per_connection > 0 && - smtp_mailcmd_count > smtp_accept_max_per_connection) + if (mailmax > 0 && smtp_mailcmd_count > mailmax) { smtp_printf("421 too many messages in this connection\r\n", FALSE); log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many " @@ -5894,12 +5958,14 @@ if (!sender_host_authenticated) 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); +if (Ustrcmp(sender_host_auth_pubname, "tls") == 0) + g = authenticated_id + ? string_append(g, 2, US") x509.auth=", authenticated_id) + : string_cat(g, US") reason=x509.auth"); else - g = string_catn(g, US") reason=x509.auth", 17); + g = authenticated_id + ? string_append(g, 2, US") smtp.auth=", authenticated_id) + : string_cat(g, US", no id saved)"); if (authenticated_sender) g = string_append(g, 2, US" smtp.mailfrom=", authenticated_sender);