X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fsmtp_in.c;h=f534d1ca7809c9e18f5cf2993b249548610396e5;hb=493e0e6648552c0dce6c5225c8438d2829f1ac11;hp=d4b3e565a982fd598aed510ceefff1baadfe2a76;hpb=7e3ce68e68ab9b8906a637d352993abf361554e2;p=exim.git diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index d4b3e565a..f534d1ca7 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -73,7 +73,6 @@ enum { ETRN_CMD, /* This by analogy with TURN from the RFC */ STARTTLS_CMD, /* Required by the STARTTLS RFC */ TLS_AUTH_CMD, /* auto-command at start of SSL */ - BDAT_CMD, /* Implied by RFC3030 "After all MAIL and..." */ /* This is a dummy to identify the non-sync commands when pipelining */ @@ -83,6 +82,15 @@ enum { MAIL_CMD, RCPT_CMD, RSET_CMD, + /* RFC3030 section 2: "After all MAIL and RCPT responses are collected and + processed the message is sent using a series of BDAT commands" + implies that BDAT should be synchronized. However, we see Google, at least, + sending MAIL,RCPT,BDAT-LAST in a single packet, clearly not waiting for + processing of the RPCT response(s). We shall do the same, and not require + synch for BDAT. */ + + BDAT_CMD, + /* This is a dummy to identify the non-sync commands when not pipelining */ NON_SYNC_CMD_NON_PIPELINING, @@ -317,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); @@ -344,6 +353,15 @@ if (smtp_inptr >= smtp_inend) return *smtp_inptr++; } +void +smtp_get_cache(void) +{ +#ifndef DISABLE_DKIM +int n = smtp_inend - smtp_inptr; +if (n > 0) + dkim_exim_verify_feed(smtp_inptr, n); +#endif +} /* Get a byte from the smtp input, in CHUNKING mode. Handle ack of the @@ -378,10 +396,14 @@ for(;;) /* If not the last, ack the received chunk. The last response is delayed until after the data ACL decides on it */ - /*XXX find that "last response" and append the chunk size */ if (chunking_state == CHUNKING_LAST) + { +#ifndef DISABLE_DKIM + dkim_exim_verify_feed(NULL, 0); /* notify EOD */ +#endif return EOD; + } chunking_state = CHUNKING_OFFERED; smtp_printf("250 %u byte chunk received\r\n", chunking_datasize); @@ -455,6 +477,20 @@ next_cmd: } } +static void +bdat_flush_data(void) +{ +while (chunking_data_left-- > 0) + if (lwr_receive_getc() < 0) + break; + +receive_getc = lwr_receive_getc; +receive_ungetc = lwr_receive_ungetc; + +if (chunking_state != CHUNKING_LAST) + chunking_state = CHUNKING_OFFERED; +} + @@ -1308,26 +1344,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; } } @@ -2014,10 +2047,10 @@ acl_var_c = NULL; /* Allow for trailing 0 in the command and data buffers. */ -smtp_cmd_buffer = (uschar *)malloc(2*smtp_cmd_buffer_size + 2); -if (smtp_cmd_buffer == NULL) +if (!(smtp_cmd_buffer = US malloc(2*smtp_cmd_buffer_size + 2))) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "malloc() failed for SMTP command buffer"); + smtp_cmd_buffer[0] = 0; smtp_data_buffer = smtp_cmd_buffer + smtp_cmd_buffer_size + 1; @@ -2026,7 +2059,7 @@ command line by a trusted caller. */ if (smtp_batched_input) { - if (received_protocol == NULL) received_protocol = US"local-bsmtp"; + if (!received_protocol) received_protocol = US"local-bsmtp"; } /* For non-batched SMTP input, the protocol setting is forced here. It will be @@ -2039,10 +2072,11 @@ else /* Set up the buffer for inputting using direct read() calls, and arrange to call the local functions instead of the standard C ones. */ -smtp_inbuffer = (uschar *)malloc(in_buffer_size); -if (smtp_inbuffer == NULL) +if (!(smtp_inbuffer = (uschar *)malloc(in_buffer_size))) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "malloc() failed for SMTP input buffer"); + receive_getc = smtp_getc; +receive_get_cache = smtp_get_cache; receive_ungetc = smtp_ungetc; receive_feof = smtp_feof; receive_ferror = smtp_ferror; @@ -2439,7 +2473,6 @@ if (smtp_batched_input) return TRUE; proxy_session = FALSE; proxy_session_failed = FALSE; if (check_proxy_protocol_host()) - { if (setup_proxy_protocol_host() == FALSE) { proxy_session_failed = TRUE; @@ -2452,20 +2485,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; } } @@ -2831,16 +2862,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; @@ -2917,16 +2948,16 @@ 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 rc was FAIL_DROP we drop the connection and yield 2. */ -if (rc == FAIL) smtp_respond(smtp_code, codelen, TRUE, (user_msg == NULL)? - US"Administrative prohibition" : user_msg); +if (rc == FAIL) + smtp_respond(smtp_code, codelen, TRUE, + user_msg ? user_msg : US"Administrative prohibition"); /* Send temporary failure response to the command. Don't give any details, unless acl_temp_details is set. This is TRUE for a callout defer, a "defer" @@ -2937,21 +2968,19 @@ interactions between temp_details and return_error_details. One day it should be re-implemented in a tidier fashion. */ else - { - if (acl_temp_details && user_msg != NULL) + if (acl_temp_details && user_msg) { - if (smtp_return_error_details && - sender_verified_failed != NULL && - sender_verified_failed->message != NULL) - { + if ( smtp_return_error_details + && sender_verified_failed + && sender_verified_failed->message + ) smtp_respond(smtp_code, codelen, FALSE, sender_verified_failed->message); - } + smtp_respond(smtp_code, codelen, TRUE, user_msg); } else smtp_respond(smtp_code, codelen, TRUE, US"Temporary local problem - please try later"); - } /* Log the incident to the logs that are specified by log_reject_target (default main, reject). This can be empty to suppress logging of rejections. If @@ -2966,7 +2995,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, @@ -3035,12 +3065,11 @@ smtp_exit_function_called = TRUE; /* Call the not-QUIT ACL, if there is one, unless no reason is given. */ -if (acl_smtp_notquit != NULL && reason != NULL) +if (acl_smtp_notquit && reason) { smtp_notquit_reason = reason; - rc = acl_check(ACL_WHERE_NOTQUIT, NULL, acl_smtp_notquit, &user_msg, - &log_msg); - if (rc == ERROR) + if ((rc = acl_check(ACL_WHERE_NOTQUIT, NULL, acl_smtp_notquit, &user_msg, + &log_msg)) == ERROR) log_write(0, LOG_MAIN|LOG_PANIC, "ACL for not-QUIT returned ERROR: %s", log_msg); } @@ -3050,9 +3079,11 @@ responses are all internal, they should always fit in the buffer, but code a warning, just in case. Note that string_vformat() still leaves a complete string, even if it is incomplete. */ -if (code != NULL && defaultrespond != NULL) +if (code && defaultrespond) { - if (user_msg == NULL) + if (user_msg) + smtp_respond(code, 3, TRUE, user_msg); + else { uschar buffer[128]; va_list ap; @@ -3062,8 +3093,6 @@ if (code != NULL && defaultrespond != NULL) smtp_printf("%s %s\r\n", code, buffer); va_end(ap); } - else - smtp_respond(code, 3, TRUE, user_msg); mac_smtp_fflush(); } } @@ -3369,7 +3398,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) @@ -4754,6 +4783,9 @@ while (done <= 0) smtp_connection_had[smtp_ch_index-1] == SCH_DATA ? US"valid RCPT command must precede DATA" : US"valid RCPT command must precede BDAT"); + + if (chunking_state > CHUNKING_OFFERED) + bdat_flush_data(); break; } @@ -4989,45 +5021,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;