- US"RCPT must have an address operand");
- rcpt_fail_count++;
- break;
- }
-
- /* Apply SMTP rewriting then extract the working address. Don't allow "<>"
- as a recipient address */
-
- recipient = ((rewrite_existflags & rewrite_smtp) != 0)?
- rewrite_one(smtp_cmd_data, rewrite_smtp, NULL, FALSE, US"",
- global_rewrite_rules) : smtp_cmd_data;
-
- /* rfc821_domains = TRUE; << no longer needed */
- recipient = parse_extract_address(recipient, &errmess, &start, &end,
- &recipient_domain, FALSE);
- /* rfc821_domains = FALSE; << no longer needed */
-
- if (recipient == NULL)
- {
- done = synprot_error(L_smtp_syntax_error, 501, smtp_cmd_data, errmess);
- rcpt_fail_count++;
- break;
- }
-
- /* If the recipient address is unqualified, reject it, unless this is a
- locally generated message. However, unqualified addresses are permitted
- from a configured list of hosts and nets - typically when behaving as
- MUAs rather than MTAs. Sad that SMTP is used for both types of traffic,
- really. The flag is set at the start of the SMTP connection.
-
- RFC 1123 talks about supporting "the reserved mailbox postmaster"; I always
- assumed this meant "reserved local part", but the revision of RFC 821 and
- friends now makes it absolutely clear that it means *mailbox*. Consequently
- we must always qualify this address, regardless. */
-
- if (recipient_domain == 0)
- {
- if (allow_unqualified_recipient ||
- strcmpic(recipient, US"postmaster") == 0)
- {
- DEBUG(D_receive) debug_printf("unqualified address %s accepted\n",
- recipient);
- recipient_domain = Ustrlen(recipient) + 1;
- recipient = rewrite_address_qualify(recipient, TRUE);
- }
- else
- {
- rcpt_fail_count++;
- smtp_printf("501 %s: recipient address must contain a domain\r\n",
- smtp_cmd_data);
- log_write(L_smtp_syntax_error,
- LOG_MAIN|LOG_REJECT, "unqualified recipient rejected: "
- "<%s> %s%s", recipient, host_and_ident(TRUE),
- host_lookup_msg);
- break;
- }
- }
-
- /* Check maximum allowed */
-
- if (rcpt_count > recipients_max && recipients_max > 0)
- {
- if (recipients_max_reject)
- {
- rcpt_fail_count++;
- smtp_printf("552 too many recipients\r\n");
- if (!toomany)
- log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: message "
- "rejected: sender=<%s> %s", sender_address, host_and_ident(TRUE));
- }
- else
- {
- rcpt_defer_count++;
- smtp_printf("452 too many recipients\r\n");
- if (!toomany)
- log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: excess "
- "temporarily rejected: sender=<%s> %s", sender_address,
- host_and_ident(TRUE));
- }
-
- toomany = TRUE;
- break;
- }
-
- /* If we have passed the threshold for rate limiting, apply the current
- delay, and update it for next time, provided this is a limited host. */
-
- if (rcpt_count > smtp_rlr_threshold &&
- verify_check_host(&smtp_ratelimit_hosts) == OK)
- {
- DEBUG(D_receive) debug_printf("rate limit RCPT: delay %.3g sec\n",
- smtp_delay_rcpt/1000.0);
- millisleep((int)smtp_delay_rcpt);
- smtp_delay_rcpt *= smtp_rlr_factor;
- if (smtp_delay_rcpt > (double)smtp_rlr_limit)
- smtp_delay_rcpt = (double)smtp_rlr_limit;
- }
-
- /* If the MAIL ACL discarded all the recipients, we bypass ACL checking
- for them. Otherwise, check the access control list for this recipient. As
- 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())
- 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);
- receive_add_recipient(recipient, -1);
- }
-
- /* The recipient was discarded */
-
- else if (rc == DISCARD)
- {
- if (user_msg == NULL) smtp_printf("250 Accepted\r\n");
- else smtp_user_msg(US"250", user_msg);
- rcpt_fail_count++;
- discarded = TRUE;
- log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> rejected RCPT %s: "
- "discarded by %s ACL%s%s", host_and_ident(TRUE),
- (sender_address_unrewritten != NULL)?
- sender_address_unrewritten : sender_address,
- smtp_cmd_argument, recipients_discarded? "MAIL" : "RCPT",
- (log_msg == NULL)? US"" : US": ",
- (log_msg == NULL)? US"" : log_msg);
- }
-
- /* Either the ACL failed the address, or it was deferred. */
-
- else
- {
- if (rc == FAIL) rcpt_fail_count++; else rcpt_defer_count++;
- done = smtp_handle_acl_fail(ACL_WHERE_RCPT, rc, user_msg, log_msg);
- }
- break;
-
-
- /* The DATA command is legal only if it follows successful MAIL FROM
- and RCPT TO commands. However, if pipelining is advertised, a bad DATA is
- not counted as a protocol error if it follows RCPT (which must have been
- rejected if there are no recipients.) This function is complete when a
- valid DATA command is encountered.
-
- Note concerning the code used: RFC 2821 says this:
-
- - If there was no MAIL, or no RCPT, command, or all such commands
- were rejected, the server MAY return a "command out of sequence"
- (503) or "no valid recipients" (554) reply in response to the
- DATA command.
-
- The example in the pipelining RFC 2920 uses 554, but I use 503 here
- because it is the same whether pipelining is in use or not.
-
- If all the RCPT commands that precede DATA provoked the same error message
- (often indicating some kind of system error), it is helpful to include it
- with the DATA rejection (an idea suggested by Tony Finch). */
-
- case DATA_CMD:
- HAD(SCH_DATA);
- if (!discarded && recipients_count <= 0)
- {
- if (rcpt_smtp_response_same && rcpt_smtp_response != NULL)
- {
- uschar *code = US"503";
- int len = Ustrlen(rcpt_smtp_response);
- smtp_respond(code, 3, FALSE, US"All RCPT commands were rejected with "
- "this error:");
- /* Responses from smtp_printf() will have \r\n on the end */
- if (len > 2 && rcpt_smtp_response[len-2] == '\r')
- rcpt_smtp_response[len-2] = 0;
- smtp_respond(code, 3, FALSE, rcpt_smtp_response);
- }
- if (pipelining_advertised && last_was_rcpt)
- smtp_printf("503 Valid RCPT command must precede DATA\r\n");
- else
- done = synprot_error(L_smtp_protocol_error, 503, NULL,
- US"valid RCPT command must precede DATA");
- break;
- }
-
- if (toomany && recipients_max_reject)
- {
- sender_address = NULL; /* This will allow a new MAIL without RSET */
- sender_address_unrewritten = NULL;
- smtp_printf("554 Too many recipients\r\n");
- break;
- }
-
- /* If there is an ACL, re-check the synchronization afterwards, since the
- ACL may have delayed. */
-
- if (acl_smtp_predata == NULL) rc = OK; else
- {
- enable_dollar_recipients = TRUE;
- rc = acl_check(ACL_WHERE_PREDATA, NULL, acl_smtp_predata, &user_msg,
- &log_msg);
- enable_dollar_recipients = FALSE;
- if (rc == OK && !check_sync()) goto SYNC_FAILURE;
- }
-
- if (rc == OK)
- {
- if (user_msg == NULL)
- smtp_printf("354 Enter message, ending with \".\" on a line by itself\r\n");
- else smtp_user_msg(US"354", user_msg);
- done = 3;
- message_ended = END_NOTENDED; /* Indicate in middle of data */
- }
-
- /* Either the ACL failed the address, or it was deferred. */
-
- else
- done = smtp_handle_acl_fail(ACL_WHERE_PREDATA, rc, user_msg, log_msg);
- break;
-
-
- case VRFY_CMD:
- HAD(SCH_VRFY);
- rc = acl_check(ACL_WHERE_VRFY, NULL, acl_smtp_vrfy, &user_msg, &log_msg);
- if (rc != OK)
- done = smtp_handle_acl_fail(ACL_WHERE_VRFY, rc, user_msg, log_msg);
- else
- {
- uschar *address;
- uschar *s = NULL;
-
- /* rfc821_domains = TRUE; << no longer needed */
- address = parse_extract_address(smtp_cmd_data, &errmess, &start, &end,
- &recipient_domain, FALSE);
- /* rfc821_domains = FALSE; << no longer needed */
-
- if (address == NULL)
- s = string_sprintf("501 %s", errmess);
- else
- {
- address_item *addr = deliver_make_addr(address, FALSE);
- switch(verify_address(addr, NULL, vopt_is_recipient | vopt_qualify, -1,
- -1, -1, NULL, NULL, NULL))
- {
- case OK:
- s = string_sprintf("250 <%s> is deliverable", address);
- break;
-
- case DEFER:
- s = (addr->user_message != NULL)?
- string_sprintf("451 <%s> %s", address, addr->user_message) :
- string_sprintf("451 Cannot resolve <%s> at this time", address);
- break;
-
- case FAIL:
- s = (addr->user_message != NULL)?
- string_sprintf("550 <%s> %s", address, addr->user_message) :
- string_sprintf("550 <%s> is not deliverable", address);
- log_write(0, LOG_MAIN, "VRFY failed for %s %s",
- smtp_cmd_argument, host_and_ident(TRUE));
- break;
- }
- }
-
- smtp_printf("%s\r\n", s);
- }
- break;
-
-
- case EXPN_CMD:
- HAD(SCH_EXPN);
- rc = acl_check(ACL_WHERE_EXPN, NULL, acl_smtp_expn, &user_msg, &log_msg);
- if (rc != OK)
- done = smtp_handle_acl_fail(ACL_WHERE_EXPN, rc, user_msg, log_msg);
- else
- {
- BOOL save_log_testing_mode = log_testing_mode;
- address_test_mode = log_testing_mode = TRUE;
- (void) verify_address(deliver_make_addr(smtp_cmd_data, FALSE),
- smtp_out, vopt_is_recipient | vopt_qualify | vopt_expn, -1, -1, -1,
- NULL, NULL, NULL);
- address_test_mode = FALSE;
- log_testing_mode = save_log_testing_mode; /* true for -bh */
- }
- break;
-
-
- #ifdef SUPPORT_TLS
-
- case STARTTLS_CMD:
- HAD(SCH_STARTTLS);
- if (!tls_advertised)
- {
- done = synprot_error(L_smtp_protocol_error, 503, NULL,
- US"STARTTLS command used when not advertised");
- break;
- }
-
- /* Apply an ACL check if one is defined */
-
- if (acl_smtp_starttls != NULL)
- {
- rc = acl_check(ACL_WHERE_STARTTLS, NULL, acl_smtp_starttls, &user_msg,
- &log_msg);
- if (rc != OK)
- {
- done = smtp_handle_acl_fail(ACL_WHERE_STARTTLS, rc, user_msg, log_msg);
- break;
- }
- }
-
- /* RFC 2487 is not clear on when this command may be sent, though it
- does state that all information previously obtained from the client
- must be discarded if a TLS session is started. It seems reasonble to
- do an implied RSET when STARTTLS is received. */
-
- incomplete_transaction_log(US"STARTTLS");
- smtp_reset(reset_point);
- toomany = FALSE;
- cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = FALSE;
-
- /* There's an attack where more data is read in past the STARTTLS command
- before TLS is negotiated, then assumed to be part of the secure session
- when used afterwards; we use segregated input buffers, so are not
- vulnerable, but we want to note when it happens and, for sheer paranoia,
- ensure that the buffer is "wiped".
- Pipelining sync checks will normally have protected us too, unless disabled
- by configuration. */
-
- if (receive_smtp_buffered())
- {
- DEBUG(D_any)
- debug_printf("Non-empty input buffer after STARTTLS; naive attack?");
- if (tls_active < 0)
- smtp_inend = smtp_inptr = smtp_inbuffer;
- /* and if TLS is already active, tls_server_start() should fail */
- }
-
- /* There is nothing we value in the input buffer and if TLS is succesfully
- negotiated, we won't use this buffer again; if TLS fails, we'll just read
- fresh content into it. The buffer contains arbitrary content from an
- untrusted remote source; eg: NOOP <shellcode>\r\nSTARTTLS\r\n
- It seems safest to just wipe away the content rather than leave it as a
- target to jump to. */
-
- memset(smtp_inbuffer, 0, in_buffer_size);
-
- /* Attempt to start up a TLS session, and if successful, discard all
- knowledge that was obtained previously. At least, that's what the RFC says,
- and that's what happens by default. However, in order to work round YAEB,
- there is an option to remember the esmtp state. Sigh.
-
- We must allow for an extra EHLO command and an extra AUTH command after
- STARTTLS that don't add to the nonmail command count. */
-
- if ((rc = tls_server_start(tls_require_ciphers, gnutls_require_mac,
- gnutls_require_kx, gnutls_require_proto)) == OK)
- {
- if (!tls_remember_esmtp)
- helo_seen = esmtp = auth_advertised = pipelining_advertised = FALSE;
- cmd_list[CMD_LIST_EHLO].is_mail_cmd = TRUE;
- cmd_list[CMD_LIST_AUTH].is_mail_cmd = TRUE;
- if (sender_helo_name != NULL)
- {
- store_free(sender_helo_name);
- sender_helo_name = NULL;
- host_build_sender_fullhost(); /* Rebuild */
- set_process_info("handling incoming TLS connection from %s",
- host_and_ident(FALSE));
- }
- received_protocol = (esmtp?
- protocols[pextend + pcrpted +
- ((sender_host_authenticated != NULL)? pauthed : 0)]
- :
- protocols[pnormal + pcrpted])
- +
- ((sender_host_address != NULL)? pnlocal : 0);
-
- sender_host_authenticated = NULL;
- authenticated_id = NULL;
- sync_cmd_limit = NON_SYNC_CMD_NON_PIPELINING;
- DEBUG(D_tls) debug_printf("TLS active\n");
- break; /* Successful STARTTLS */
- }
-
- /* Some local configuration problem was discovered before actually trying
- to do a TLS handshake; give a temporary error. */
-
- else if (rc == DEFER)
- {
- smtp_printf("454 TLS currently unavailable\r\n");
- break;
- }
-
- /* Hard failure. Reject everything except QUIT or closed connection. One
- cause for failure is a nested STARTTLS, in which case tls_active remains
- set, but we must still reject all incoming commands. */
-
- DEBUG(D_tls) debug_printf("TLS failed to start\n");
- while (done <= 0)
- {
- 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 situtation 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 != 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;
-
- default:
- smtp_printf("554 Security failure\r\n");
- break;
- }
- }
- tls_close(TRUE);
- break;
- #endif
-
-
- /* The ACL for QUIT is provided for gathering statistical information or
- similar; it does not affect the response code, but it can supply a custom
- message. */
-
- case QUIT_CMD:
- HAD(SCH_QUIT);
- incomplete_transaction_log(US"QUIT");
- 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);
-
- #ifdef SUPPORT_TLS
- tls_close(TRUE);
- #endif
-
- done = 2;
- log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
- smtp_get_connection_info());
- break;
-
-
- case RSET_CMD:
- HAD(SCH_RSET);
- incomplete_transaction_log(US"RSET");
- smtp_reset(reset_point);
- toomany = FALSE;
- smtp_printf("250 Reset OK\r\n");
- cmd_list[CMD_LIST_RSET].is_mail_cmd = FALSE;
- break;
-
-
- case NOOP_CMD:
- HAD(SCH_NOOP);
- smtp_printf("250 OK\r\n");
- break;
-
-
- /* Show ETRN/EXPN/VRFY if there's an ACL for checking hosts; if actually
- used, a check will be done for permitted hosts. Show STARTTLS only if not
- already in a TLS session and if it would be advertised in the EHLO
- response. */
-
- case HELP_CMD:
- HAD(SCH_HELP);
- smtp_printf("214-Commands supported:\r\n");
- {
- uschar buffer[256];
- buffer[0] = 0;
- Ustrcat(buffer, " AUTH");
- #ifdef SUPPORT_TLS
- if (tls_active < 0 &&
- verify_check_host(&tls_advertise_hosts) != FAIL)
- Ustrcat(buffer, " STARTTLS");
- #endif
- Ustrcat(buffer, " HELO EHLO MAIL RCPT DATA");
- Ustrcat(buffer, " NOOP QUIT RSET HELP");
- if (acl_smtp_etrn != NULL) Ustrcat(buffer, " ETRN");
- if (acl_smtp_expn != NULL) Ustrcat(buffer, " EXPN");
- if (acl_smtp_vrfy != NULL) Ustrcat(buffer, " VRFY");
- smtp_printf("214%s\r\n", buffer);
- }
- break;
-
-
- case EOF_CMD:
- incomplete_transaction_log(US"connection lost");
- smtp_notquit_exit(US"connection-lost", US"421",
- US"%s lost input connection", smtp_active_hostname);
-
- /* Don't log by default unless in the middle of a message, as some mailers
- just drop the call rather than sending QUIT, and it clutters up the logs.
- */
-
- if (sender_address != NULL || recipients_count > 0)
- log_write(L_lost_incoming_connection,
- LOG_MAIN,
- "unexpected %s while reading SMTP command from %s%s",
- sender_host_unknown? "EOF" : "disconnection",
- host_and_ident(FALSE), smtp_read_error);
-
- else log_write(L_smtp_connection, LOG_MAIN, "%s lost%s",
- smtp_get_connection_info(), smtp_read_error);
-
- done = 1;
- break;
-
-
- case ETRN_CMD:
- HAD(SCH_ETRN);
- if (sender_address != NULL)
- {
- done = synprot_error(L_smtp_protocol_error, 503, NULL,
- US"ETRN is not permitted inside a transaction");