X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/40c90bca9f7e2952bd64faebceb53538f80805a7..0929ce9ca518b6987b63cf8659338ca434e07d9b:/src/src/smtp_in.c diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 3b631ea10..148486161 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -325,6 +325,7 @@ smtp_getc(void) if (smtp_inptr >= smtp_inend) { int rc, save_errno; + if (!smtp_out) return EOF; fflush(smtp_out); if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout); rc = read(fileno(smtp_in), smtp_inbuffer, in_buffer_size); @@ -760,10 +761,10 @@ Arguments: fd - File descriptor for input Returns: none */ static void -restore_socket_timeout(int fd, int get_ok, struct timeval tvtmp, socklen_t vslen) +restore_socket_timeout(int fd, int get_ok, struct timeval * tvtmp, socklen_t vslen) { if (get_ok == 0) - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvtmp, vslen); + (void) setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS tvtmp, vslen); } /************************************************* @@ -804,7 +805,7 @@ so exit with an error if do not find the exact required pieces. This includes an incorrect number of spaces separating args. Arguments: none -Returns: int +Returns: Boolean success */ static BOOL @@ -848,27 +849,23 @@ char tmpip6[INET6_ADDRSTRLEN]; struct sockaddr_in6 tmpaddr6; int get_ok = 0; -int size, ret, fd; +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; -socklen_t vslen = 0; struct timeval tvtmp; - -vslen = sizeof(struct timeval); - -fd = fileno(smtp_in); +socklen_t vslen = sizeof(struct timeval); /* Save current socket timeout values */ -get_ok = getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvtmp, - &vslen); +get_ok = getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS &tvtmp, &vslen); /* Proxy Protocol host must send header within a short time (default 3 seconds) or it's considered invalid */ tv.tv_sec = PROXY_NEGOTIATION_TIMEOUT_SEC; tv.tv_usec = PROXY_NEGOTIATION_TIMEOUT_USEC; -setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, - sizeof(struct timeval)); +if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS &tv, sizeof(tv)) < 0) + return FALSE; do { @@ -879,10 +876,7 @@ do while (ret == -1 && errno == EINTR); if (ret == -1) - { - restore_socket_timeout(fd, get_ok, tvtmp, vslen); - return (errno == EAGAIN) ? 0 : ERRNO_PROXYFAIL; - } + goto proxyfail; if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0) @@ -922,7 +916,7 @@ if (ret >= 16 && if (!string_is_ip_address(US tmpip,NULL)) { DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype); - return ERRNO_PROXYFAIL; + goto proxyfail; } proxy_local_address = sender_host_address; sender_host_address = string_copy(US tmpip); @@ -935,7 +929,7 @@ if (ret >= 16 && if (!string_is_ip_address(US tmpip,NULL)) { DEBUG(D_receive) debug_printf("Invalid %s dest port\n", iptype); - return ERRNO_PROXYFAIL; + goto proxyfail; } proxy_external_address = string_copy(US tmpip); tmpport = ntohs(hdr.v2.addr.ip4.dst_port); @@ -948,7 +942,7 @@ if (ret >= 16 && if (!string_is_ip_address(US tmpip6,NULL)) { DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype); - return ERRNO_PROXYFAIL; + goto proxyfail; } proxy_local_address = sender_host_address; sender_host_address = string_copy(US tmpip6); @@ -961,7 +955,7 @@ if (ret >= 16 && if (!string_is_ip_address(US tmpip6,NULL)) { DEBUG(D_receive) debug_printf("Invalid %s dest port\n", iptype); - return ERRNO_PROXYFAIL; + goto proxyfail; } proxy_external_address = string_copy(US tmpip6); tmpport = ntohs(hdr.v2.addr.ip6.dst_port); @@ -1102,13 +1096,13 @@ else } proxyfail: -restore_socket_timeout(fd, get_ok, tvtmp, vslen); +restore_socket_timeout(fd, get_ok, &tvtmp, vslen); /* Don't flush any potential buffer contents. Any input should cause a synchronization failure */ return FALSE; done: -restore_socket_timeout(fd, get_ok, tvtmp, vslen); +restore_socket_timeout(fd, get_ok, &tvtmp, vslen); DEBUG(D_receive) debug_printf("Valid %s sender from Proxy Protocol header\n", iptype); return proxy_session; @@ -1343,26 +1337,23 @@ if (smtp_in == NULL || smtp_batched_input) return; receive_swallow_smtp(); smtp_printf("421 %s\r\n", message); -for (;;) +for (;;) switch(smtp_read_command(FALSE)) { - switch(smtp_read_command(FALSE)) - { - case EOF_CMD: - return; + case EOF_CMD: + return; - case QUIT_CMD: - smtp_printf("221 %s closing connection\r\n", smtp_active_hostname); - mac_smtp_fflush(); - return; + case QUIT_CMD: + smtp_printf("221 %s closing connection\r\n", smtp_active_hostname); + mac_smtp_fflush(); + return; - case RSET_CMD: - smtp_printf("250 Reset OK\r\n"); - break; + case RSET_CMD: + smtp_printf("250 Reset OK\r\n"); + break; - default: - smtp_printf("421 %s\r\n", message); - break; - } + default: + smtp_printf("421 %s\r\n", message); + break; } } @@ -1385,8 +1376,8 @@ Returns: a string describing the connection uschar * smtp_get_connection_info(void) { -uschar *hostname = (sender_fullhost == NULL)? - sender_host_address : sender_fullhost; +const uschar * hostname = sender_fullhost + ? sender_fullhost : sender_host_address; if (host_checking) return string_sprintf("SMTP connection from %s", hostname); @@ -2475,8 +2466,7 @@ if (smtp_batched_input) return TRUE; proxy_session = FALSE; proxy_session_failed = FALSE; if (check_proxy_protocol_host()) - { - if (setup_proxy_protocol_host() == FALSE) + if (!setup_proxy_protocol_host()) { proxy_session_failed = TRUE; DEBUG(D_receive) @@ -2488,20 +2478,18 @@ if (check_proxy_protocol_host()) (void)host_name_lookup(); host_build_sender_fullhost(); } - } #endif /* Run the ACL if it exists */ user_msg = NULL; -if (acl_smtp_connect != NULL) +if (acl_smtp_connect) { int rc; - rc = acl_check(ACL_WHERE_CONNECT, NULL, acl_smtp_connect, &user_msg, - &log_msg); - if (rc != OK) + if ((rc = acl_check(ACL_WHERE_CONNECT, NULL, acl_smtp_connect, &user_msg, + &log_msg)) != OK) { - (void)smtp_handle_acl_fail(ACL_WHERE_CONNECT, rc, user_msg, log_msg); + (void) smtp_handle_acl_fail(ACL_WHERE_CONNECT, rc, user_msg, log_msg); return FALSE; } } @@ -2867,16 +2855,16 @@ uschar *lognl; uschar *sender_info = US""; uschar *what = #ifdef WITH_CONTENT_SCAN - (where == ACL_WHERE_MIME)? US"during MIME ACL checks" : + where == ACL_WHERE_MIME ? US"during MIME ACL checks" : #endif - (where == ACL_WHERE_PREDATA)? US"DATA" : - (where == ACL_WHERE_DATA)? US"after DATA" : + where == ACL_WHERE_PREDATA ? US"DATA" : + where == ACL_WHERE_DATA ? US"after DATA" : #ifndef DISABLE_PRDR - (where == ACL_WHERE_PRDR)? US"after DATA PRDR" : + where == ACL_WHERE_PRDR ? US"after DATA PRDR" : #endif - (smtp_cmd_data == NULL)? - string_sprintf("%s in \"connect\" ACL", acl_wherenames[where]) : - string_sprintf("%s %s", acl_wherenames[where], smtp_cmd_data); + smtp_cmd_data ? + string_sprintf("%s %s", acl_wherenames[where], smtp_cmd_data) : + string_sprintf("%s in \"connect\" ACL", acl_wherenames[where]); if (drop) rc = FAIL; @@ -2953,9 +2941,8 @@ if (sender_verified_failed != NULL && /* Sort out text for logging */ -log_msg = (log_msg == NULL)? US"" : string_sprintf(": %s", log_msg); -lognl = Ustrchr(log_msg, '\n'); -if (lognl != NULL) *lognl = 0; +log_msg = log_msg ? string_sprintf(": %s", log_msg) : US""; +if ((lognl = Ustrchr(log_msg, '\n'))) *lognl = 0; /* Send permanent failure response to the command, but the code used isn't always a 5xx one - see comments at the start of this function. If the original @@ -3001,7 +2988,8 @@ if (log_reject_target != 0) #else uschar * tls = US""; #endif - log_write(0, log_reject_target, "%s%s%s %s%srejected %s%s", + log_write(where == ACL_WHERE_CONNECT ? L_connection_reject : 0, + log_reject_target, "%s%s%s %s%srejected %s%s", LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", host_and_ident(TRUE), tls, @@ -3403,7 +3391,7 @@ smtp_quit_handler(uschar ** user_msgp, uschar ** log_msgp) { HAD(SCH_QUIT); incomplete_transaction_log(US"QUIT"); -if (acl_smtp_quit != NULL) +if (acl_smtp_quit) { int rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp); if (rc == ERROR) @@ -3524,7 +3512,7 @@ while (done <= 0) uschar *orcpt = NULL; int flags; -#if defined(SUPPORT_TLS) && defined(AUTH_TLS) +#ifdef AUTH_TLS /* Check once per STARTTLS or SSL-on-connect for a TLS AUTH */ if ( tls_in.active >= 0 && tls_in.peercert @@ -3556,6 +3544,12 @@ 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(TRUE)) { /* The AUTH command is not permitted to occur inside a transaction, and may @@ -3934,7 +3928,7 @@ while (done <= 0) them in either case in the AUTH command. */ if ( auths -#if defined(SUPPORT_TLS) && defined(AUTH_TLS) +#ifdef AUTH_TLS && !sender_host_authenticated #endif && verify_check_host(&auth_advertise_hosts) == OK @@ -4659,20 +4653,22 @@ while (done <= 0) there may be a delay in this, re-check for a synchronization error afterwards, unless pipelining was advertised. */ - if (recipients_discarded) rc = DISCARD; else - { - rc = acl_check(ACL_WHERE_RCPT, recipient, acl_smtp_rcpt, &user_msg, - &log_msg); - if (rc == OK && !pipelining_advertised && !check_sync()) + if (recipients_discarded) + rc = DISCARD; + else + if ( (rc = acl_check(ACL_WHERE_RCPT, recipient, acl_smtp_rcpt, &user_msg, + &log_msg)) == OK + && !pipelining_advertised && !check_sync()) goto SYNC_FAILURE; - } /* The ACL was happy */ if (rc == OK) { - if (user_msg == NULL) smtp_printf("250 Accepted\r\n"); - else smtp_user_msg(US"250", user_msg); + if (user_msg) + smtp_user_msg(US"250", user_msg); + else + smtp_printf("250 Accepted\r\n"); receive_add_recipient(recipient, -1); /* Set the dsn flags in the recipients_list */ @@ -4688,8 +4684,10 @@ while (done <= 0) else if (rc == DISCARD) { - if (user_msg == NULL) smtp_printf("250 Accepted\r\n"); - else smtp_user_msg(US"250", user_msg); + if (user_msg) + smtp_user_msg(US"250", user_msg); + else + smtp_printf("250 Accepted\r\n"); rcpt_fail_count++; discarded = TRUE; log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: " @@ -4803,9 +4801,7 @@ while (done <= 0) } if (chunking_state > CHUNKING_OFFERED) - { /* No predata ACL or go-ahead output for BDAT */ - rc = OK; - } + rc = OK; /* No predata ACL or go-ahead output for BDAT */ else { /* If there is an ACL, re-check the synchronization afterwards, since the @@ -4838,6 +4834,11 @@ while (done <= 0) "354 Enter message, ending with \".\" on a line by itself\r\n"); } +#ifdef TCP_QUICKACK + if (smtp_in) /* all ACKs needed to ramp window up for bulk data */ + (void) setsockopt(fileno(smtp_in), IPPROTO_TCP, TCP_QUICKACK, + US &on, sizeof(on)); +#endif done = 3; message_ended = END_NOTENDED; /* Indicate in middle of data */ @@ -5026,45 +5027,39 @@ while (done <= 0) set, but we must still reject all incoming commands. */ DEBUG(D_tls) debug_printf("TLS failed to start\n"); - while (done <= 0) + while (done <= 0) switch(smtp_read_command(FALSE)) { - switch(smtp_read_command(FALSE)) - { - case EOF_CMD: - log_write(L_smtp_connection, LOG_MAIN, "%s closed by EOF", - smtp_get_connection_info()); - smtp_notquit_exit(US"tls-failed", NULL, NULL); - done = 2; - break; - - /* It is perhaps arguable as to which exit ACL should be called here, - but as it is probably a situation that almost never arises, it - probably doesn't matter. We choose to call the real QUIT ACL, which in - some sense is perhaps "right". */ + case EOF_CMD: + log_write(L_smtp_connection, LOG_MAIN, "%s closed by EOF", + smtp_get_connection_info()); + smtp_notquit_exit(US"tls-failed", NULL, NULL); + done = 2; + break; - case QUIT_CMD: - user_msg = NULL; - if (acl_smtp_quit != NULL) - { - rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg, - &log_msg); - if (rc == ERROR) - log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s", - log_msg); - } - if (user_msg == NULL) - smtp_printf("221 %s closing connection\r\n", smtp_active_hostname); - else - smtp_respond(US"221", 3, TRUE, user_msg); - log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT", - smtp_get_connection_info()); - done = 2; - break; + /* It is perhaps arguable as to which exit ACL should be called here, + but as it is probably a situation that almost never arises, it + probably doesn't matter. We choose to call the real QUIT ACL, which in + some sense is perhaps "right". */ + + case QUIT_CMD: + user_msg = NULL; + if ( acl_smtp_quit + && ((rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg, + &log_msg)) == ERROR)) + 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); + else + smtp_printf("221 %s closing connection\r\n", smtp_active_hostname); + log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT", + smtp_get_connection_info()); + done = 2; + break; - default: - smtp_printf("554 Security failure\r\n"); - break; - } + default: + smtp_printf("554 Security failure\r\n"); + break; } tls_close(TRUE, TRUE); break;