- if (sender_host_address != NULL)
- {
- s = string_cat(s, &size, &ptr, US" [", 2);
- s = string_cat(s, &size, &ptr, sender_host_address,
- Ustrlen(sender_host_address));
- s = string_cat(s, &size, &ptr, US"]", 1);
- }
- }
-
- /* A user-supplied EHLO greeting may not contain more than one line. Note
- that the code returned by smtp_message_code() includes the terminating
- whitespace character. */
-
- else
- {
- char *ss;
- int codelen = 4;
- smtp_message_code(&smtp_code, &codelen, &user_msg, NULL);
- s = string_sprintf("%.*s%s", codelen, smtp_code, user_msg);
- if ((ss = strpbrk(CS s, "\r\n")) != NULL)
- {
- log_write(0, LOG_MAIN|LOG_PANIC, "EHLO/HELO response must not contain "
- "newlines: message truncated: %s", string_printing(s));
- *ss = 0;
- }
- ptr = Ustrlen(s);
- size = ptr + 1;
- }
-
- s = string_cat(s, &size, &ptr, US"\r\n", 2);
-
- /* If we received EHLO, we must create a multiline response which includes
- the functions supported. */
-
- if (esmtp)
- {
- s[3] = '-';
-
- /* I'm not entirely happy with this, as an MTA is supposed to check
- that it has enough room to accept a message of maximum size before
- it sends this. However, there seems little point in not sending it.
- The actual size check happens later at MAIL FROM time. By postponing it
- till then, VRFY and EXPN can be used after EHLO when space is short. */
-
- if (thismessage_size_limit > 0)
- {
- sprintf(CS big_buffer, "%.3s-SIZE %d\r\n", smtp_code,
- thismessage_size_limit);
- s = string_cat(s, &size, &ptr, big_buffer, Ustrlen(big_buffer));
- }
- else
- {
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US"-SIZE\r\n", 7);
- }
-
- /* 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.
- However, some users want this option simply in order to stop MUAs
- mangling messages that contain top-bit-set characters. It is therefore
- provided as an option. */
-
- if (accept_8bitmime)
- {
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US"-8BITMIME\r\n", 11);
- }
-
- /* Advertise ETRN if there's an ACL checking whether a host is
- permitted to issue it; a check is made when any host actually tries. */
-
- if (acl_smtp_etrn != NULL)
- {
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US"-ETRN\r\n", 7);
- }
-
- /* Advertise EXPN if there's an ACL checking whether a host is
- permitted to issue it; a check is made when any host actually tries. */
-
- if (acl_smtp_expn != NULL)
- {
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US"-EXPN\r\n", 7);
- }
-
- /* Exim is quite happy with pipelining, so let the other end know that
- it is safe to use it, unless advertising is disabled. */
-
- if (pipelining_enable &&
- verify_check_host(&pipelining_advertise_hosts) == OK)
- {
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US"-PIPELINING\r\n", 13);
- sync_cmd_limit = NON_SYNC_CMD_PIPELINING;
- pipelining_advertised = TRUE;
- }
-
-
- /* If any server authentication mechanisms are configured, advertise
- them if the current host is in auth_advertise_hosts. The problem with
- advertising always is that some clients then require users to
- authenticate (and aren't configurable otherwise) even though it may not
- be necessary (e.g. if the host is in host_accept_relay).
-
- RFC 2222 states that SASL mechanism names contain only upper case
- letters, so output the names in upper case, though we actually recognize
- them in either case in the AUTH command. */
-
- if (auths != NULL)
- {
- if (verify_check_host(&auth_advertise_hosts) == OK)
- {
- auth_instance *au;
- BOOL first = TRUE;
- for (au = auths; au != NULL; au = au->next)
- {
- if (au->server && (au->advertise_condition == NULL ||
- expand_check_condition(au->advertise_condition, au->name,
- US"authenticator")))
- {
- int saveptr;
- if (first)
- {
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US"-AUTH", 5);
- first = FALSE;
- auth_advertised = TRUE;
- }
- saveptr = ptr;
- s = string_cat(s, &size, &ptr, US" ", 1);
- s = string_cat(s, &size, &ptr, au->public_name,
- Ustrlen(au->public_name));
- while (++saveptr < ptr) s[saveptr] = toupper(s[saveptr]);
- au->advertised = TRUE;
- }
- else au->advertised = FALSE;
- }
- if (!first) s = string_cat(s, &size, &ptr, US"\r\n", 2);
- }
- }
-
- /* Advertise TLS (Transport Level Security) aka SSL (Secure Socket Layer)
- if it has been included in the binary, and the host matches
- tls_advertise_hosts. We must *not* advertise if we are already in a
- secure connection. */
-
- #ifdef SUPPORT_TLS
- if (tls_in.active < 0 &&
- verify_check_host(&tls_advertise_hosts) != FAIL)
- {
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US"-STARTTLS\r\n", 11);
- tls_advertised = TRUE;
- }
- #endif
-
- #ifdef EXPERIMENTAL_PRDR
- /* Per Recipient Data Response, draft by Eric A. Hall extending RFC */
- if (prdr_enable) {
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US"-PRDR\r\n", 7);
- }
- #endif
-
- /* Finish off the multiline reply with one that is always available. */
-
- s = string_cat(s, &size, &ptr, smtp_code, 3);
- s = string_cat(s, &size, &ptr, US" HELP\r\n", 7);
- }
-
- /* Terminate the string (for debug), write it, and note that HELO/EHLO
- has been seen. */
-
- s[ptr] = 0;
-
- #ifdef SUPPORT_TLS
- if (tls_in.active >= 0) (void)tls_write(TRUE, s, ptr); else
- #endif
-
- {
- int i = fwrite(s, 1, ptr, smtp_out); i = i; /* compiler quietening */
- }
- DEBUG(D_receive)
- {
- uschar *cr;
- while ((cr = Ustrchr(s, '\r')) != NULL) /* lose CRs */
- memmove(cr, cr + 1, (ptr--) - (cr - s));
- debug_printf("SMTP>> %s", s);
- }
- helo_seen = TRUE;
-
- /* Reset the protocol and the state, abandoning any previous message. */
-
- received_protocol = (esmtp?
- protocols[pextend +
- ((sender_host_authenticated != NULL)? pauthed : 0) +
- ((tls_in.active >= 0)? pcrpted : 0)]
- :
- protocols[pnormal + ((tls_in.active >= 0)? pcrpted : 0)])
- +
- ((sender_host_address != NULL)? pnlocal : 0);
-
- smtp_reset(reset_point);
- toomany = FALSE;
- break; /* HELO/EHLO */
-
-
- /* The MAIL command requires an address as an operand. All we do
- here is to parse it for syntactic correctness. The form "<>" is
- a special case which converts into an empty string. The start/end
- pointers in the original are not used further for this address, as
- it is the canonical extracted address which is all that is kept. */
-
- case MAIL_CMD:
- HAD(SCH_MAIL);
- smtp_mailcmd_count++; /* Count for limit and ratelimit */
- was_rej_mail = TRUE; /* Reset if accepted */
- env_mail_type_t * mail_args; /* Sanity check & validate args */
-
- if (helo_required && !helo_seen)
- {
- smtp_printf("503 HELO or EHLO required\r\n");
- log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no "
- "HELO/EHLO given", host_and_ident(FALSE));
- break;
- }
-
- if (sender_address != NULL)
- {
- done = synprot_error(L_smtp_protocol_error, 503, NULL,
- US"sender already given");
- break;
- }
-
- if (smtp_cmd_data[0] == 0)
- {
- done = synprot_error(L_smtp_protocol_error, 501, NULL,
- US"MAIL must have an address operand");
- break;
- }
-
- /* 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)
- {
- smtp_printf("421 too many messages in this connection\r\n");
- log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many "
- "messages in one connection", host_and_ident(TRUE));
- break;
- }
-
- /* Reset for start of message - even if this is going to fail, we
- obviously need to throw away any previous data. */
-
- smtp_reset(reset_point);
- toomany = FALSE;
- sender_data = recipient_data = NULL;
-
- /* Loop, checking for ESMTP additions to the MAIL FROM command. */
-
- if (esmtp) for(;;)
- {
- uschar *name, *value, *end;
- unsigned long int size;
- BOOL arg_error = FALSE;
-
- if (!extract_option(&name, &value)) break;
-
- for (mail_args = env_mail_type_list;
- (char *)mail_args < (char *)env_mail_type_list + sizeof(env_mail_type_list);
- mail_args++
- )
- {
- if (strcmpic(name, mail_args->name) == 0)
- break;
- }
- if (mail_args->need_value && strcmpic(value, US"") == 0)
- break;
-
- switch(mail_args->value)
- {
- /* Handle SIZE= by reading the value. We don't do the check till later,
- in order to be able to log the sender address on failure. */
- case ENV_MAIL_OPT_SIZE:
- if (((size = Ustrtoul(value, &end, 10)), *end == 0))
- {
- if ((size == ULONG_MAX && errno == ERANGE) || size > INT_MAX)
- size = INT_MAX;
- message_size = (int)size;
- }
- else
- arg_error = TRUE;
- break;
-
- /* If this session was initiated with EHLO and accept_8bitmime is set,
- Exim will have indicated that it supports the BODY=8BITMIME option. In
- fact, it does not support this according to the RFCs, in that it does not
- take any special action for forwarding messages containing 8-bit
- characters. That is why accept_8bitmime is not the default setting, but
- some sites want the action that is provided. We recognize both "8BITMIME"
- and "7BIT" as body types, but take no action. */
- case ENV_MAIL_OPT_BODY:
- if (accept_8bitmime) {
- if (strcmpic(value, US"8BITMIME") == 0) {
- body_8bitmime = 8;
- } else if (strcmpic(value, US"7BIT") == 0) {
- body_8bitmime = 7;
- } else {
- body_8bitmime = 0;
- done = synprot_error(L_smtp_syntax_error, 501, NULL,
- US"invalid data for BODY");
- goto COMMAND_LOOP;
- }
- DEBUG(D_receive) debug_printf("8BITMIME: %d\n", body_8bitmime);
- break;
- }
- arg_error = TRUE;
- break;
-
- /* Handle the AUTH extension. If the value given is not "<>" and either
- the ACL says "yes" or there is no ACL but the sending host is
- authenticated, we set it up as the authenticated sender. However, if the
- authenticator set a condition to be tested, we ignore AUTH on MAIL unless
- the condition is met. The value of AUTH is an xtext, which means that +,
- = and cntrl chars are coded in hex; however "<>" is unaffected by this
- coding. */
- case ENV_MAIL_OPT_AUTH:
- if (Ustrcmp(value, "<>") != 0)
- {
- int rc;
- uschar *ignore_msg;
-
- if (auth_xtextdecode(value, &authenticated_sender) < 0)
- {
- /* Put back terminator overrides for error message */
- value[-1] = '=';
- name[-1] = ' ';
- done = synprot_error(L_smtp_syntax_error, 501, NULL,
- US"invalid data for AUTH");
- goto COMMAND_LOOP;
- }
- if (acl_smtp_mailauth == NULL)
- {
- ignore_msg = US"client not authenticated";
- rc = (sender_host_authenticated != NULL)? OK : FAIL;
- }
- else
- {
- ignore_msg = US"rejected by ACL";
- rc = acl_check(ACL_WHERE_MAILAUTH, NULL, acl_smtp_mailauth,
- &user_msg, &log_msg);
- }
-
- switch (rc)
- {
- case OK:
- if (authenticated_by == NULL ||
- authenticated_by->mail_auth_condition == NULL ||
- expand_check_condition(authenticated_by->mail_auth_condition,
- authenticated_by->name, US"authenticator"))
- break; /* Accept the AUTH */
-
- ignore_msg = US"server_mail_auth_condition failed";
- if (authenticated_id != NULL)
- ignore_msg = string_sprintf("%s: authenticated ID=\"%s\"",
- ignore_msg, authenticated_id);
-
- /* Fall through */
-
- case FAIL:
- authenticated_sender = NULL;
- log_write(0, LOG_MAIN, "ignoring AUTH=%s from %s (%s)",
- value, host_and_ident(TRUE), ignore_msg);
- break;
-
- /* Should only get DEFER or ERROR here. Put back terminator
- overrides for error message */
-
- default:
- value[-1] = '=';
- name[-1] = ' ';
- (void)smtp_handle_acl_fail(ACL_WHERE_MAILAUTH, rc, user_msg,
- log_msg);
- goto COMMAND_LOOP;
- }
- }
- break;
-
-#ifdef EXPERIMENTAL_PRDR
- case ENV_MAIL_OPT_PRDR:
- if ( prdr_enable )
- prdr_requested = TRUE;
- break;
-#endif
-
- /* Unknown option. Stick back the terminator characters and break
- the loop. Do the name-terminator second as extract_option sets
- value==name when it found no equal-sign.
- An error for a malformed address will occur. */
- default:
- value[-1] = '=';
- name[-1] = ' ';
- arg_error = TRUE;
- break;
- }
- /* Break out of for loop if switch() had bad argument or
- when start of the email address is reached */
- if (arg_error) 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 (smtp_mailcmd_count > smtp_rlm_threshold &&
- verify_check_host(&smtp_ratelimit_hosts) == OK)
- {
- DEBUG(D_receive) debug_printf("rate limit MAIL: delay %.3g sec\n",
- smtp_delay_mail/1000.0);
- millisleep((int)smtp_delay_mail);
- smtp_delay_mail *= smtp_rlm_factor;
- if (smtp_delay_mail > (double)smtp_rlm_limit)
- smtp_delay_mail = (double)smtp_rlm_limit;
- }
-
- /* Now extract the address, first applying any SMTP-time rewriting. The
- TRUE flag allows "<>" as a sender address. */
-
- raw_sender = ((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 */
- raw_sender =
- parse_extract_address(raw_sender, &errmess, &start, &end, &sender_domain,
- TRUE);
- /* rfc821_domains = FALSE; << no longer needed */
-
- if (raw_sender == NULL)
- {
- done = synprot_error(L_smtp_syntax_error, 501, smtp_cmd_data, errmess);
- break;
- }
-
- sender_address = raw_sender;
-
- /* If there is a configured size limit for mail, check that this message
- doesn't exceed it. The check is postponed to this point so that the sender
- can be logged. */
-
- if (thismessage_size_limit > 0 && message_size > thismessage_size_limit)
- {
- smtp_printf("552 Message size exceeds maximum permitted\r\n");
- log_write(L_size_reject,
- LOG_MAIN|LOG_REJECT, "rejected MAIL FROM:<%s> %s: "
- "message too big: size%s=%d max=%d",
- sender_address,
- host_and_ident(TRUE),
- (message_size == INT_MAX)? ">" : "",
- message_size,
- thismessage_size_limit);
- sender_address = NULL;
- break;
- }
-
- /* Check there is enough space on the disk unless configured not to.
- When smtp_check_spool_space is set, the check is for thismessage_size_limit
- plus the current message - i.e. we accept the message only if it won't
- reduce the space below the threshold. Add 5000 to the size to allow for
- overheads such as the Received: line and storing of recipients, etc.
- By putting the check here, even when SIZE is not given, it allow VRFY
- and EXPN etc. to be used when space is short. */
-
- if (!receive_check_fs(
- (smtp_check_spool_space && message_size >= 0)?
- message_size + 5000 : 0))
- {
- smtp_printf("452 Space shortage, please try later\r\n");
- sender_address = NULL;
- break;
- }
-
- /* If sender_address is unqualified, reject it, unless this is a locally
- generated message, or the sending host or net is permitted to send
- unqualified addresses - typically local machines behaving as MUAs -
- in which case just qualify the address. The flag is set above at the start
- of the SMTP connection. */
-
- if (sender_domain == 0 && sender_address[0] != 0)
- {
- if (allow_unqualified_sender)
- {
- sender_domain = Ustrlen(sender_address) + 1;
- sender_address = rewrite_address_qualify(sender_address, FALSE);
- DEBUG(D_receive) debug_printf("unqualified address %s accepted\n",
- raw_sender);
- }
- else
- {
- smtp_printf("501 %s: sender address must contain a domain\r\n",
- smtp_cmd_data);
- log_write(L_smtp_syntax_error,
- LOG_MAIN|LOG_REJECT,
- "unqualified sender rejected: <%s> %s%s",
- raw_sender,
- host_and_ident(TRUE),
- host_lookup_msg);
- sender_address = NULL;
- break;
- }
- }
-
- /* Apply an ACL check if one is defined, before responding. Afterwards,
- when pipelining is not advertised, do another sync check in case the ACL
- delayed and the client started sending in the meantime. */
-
- if (acl_smtp_mail == NULL) rc = OK; else
- {
- rc = acl_check(ACL_WHERE_MAIL, NULL, acl_smtp_mail, &user_msg, &log_msg);
- if (rc == OK && !pipelining_advertised && !check_sync())
- goto SYNC_FAILURE;
- }
-
- if (rc == OK || rc == DISCARD)
- {
- if (user_msg == NULL)
- smtp_printf("%s%s%s", US"250 OK",
- #ifdef EXPERIMENTAL_PRDR
- prdr_requested == TRUE ? US", PRDR Requested" :
- #endif
- US"",
- US"\r\n");
- else
- {
- #ifdef EXPERIMENTAL_PRDR
- if ( prdr_requested == TRUE )
- user_msg = string_sprintf("%s%s", user_msg, US", PRDR Requested");
- #endif
- smtp_user_msg(US"250",user_msg);
- }
- smtp_delay_rcpt = smtp_rlr_base;
- recipients_discarded = (rc == DISCARD);
- was_rej_mail = FALSE;
- }
- else
- {
- done = smtp_handle_acl_fail(ACL_WHERE_MAIL, rc, user_msg, log_msg);
- sender_address = NULL;
- }
- break;
-
-
- /* The RCPT command requires an address as an operand. There may be any
- number of RCPT commands, specifying multiple recipients. We build them all
- into a data structure. The start/end values given by parse_extract_address
- are not used, as we keep only the extracted address. */
-
- case RCPT_CMD:
- HAD(SCH_RCPT);
- rcpt_count++;
- was_rcpt = rcpt_in_progress = TRUE;
-
- /* There must be a sender address; if the sender was rejected and
- pipelining was advertised, we assume the client was pipelining, and do not
- count this as a protocol error. Reset was_rej_mail so that further RCPTs
- get the same treatment. */
-
- if (sender_address == NULL)
- {
- if (pipelining_advertised && last_was_rej_mail)
- {
- smtp_printf("503 sender not yet given\r\n");
- was_rej_mail = TRUE;
- }
- else
- {
- done = synprot_error(L_smtp_protocol_error, 503, NULL,
- US"sender not yet given");
- was_rcpt = FALSE; /* Not a valid RCPT */
- }
- rcpt_fail_count++;
- break;
- }
-
- /* Check for an operand */
-
- if (smtp_cmd_data[0] == 0)
- {
- done = synprot_error(L_smtp_syntax_error, 501, NULL,
- 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. To handle cutthrough delivery enforce a dummy call
- to get the DATA command sent. */
-
- if (acl_smtp_predata == NULL && cutthrough_fd < 0) rc = OK; else
- {
- uschar * acl= acl_smtp_predata ? acl_smtp_predata : US"accept";
- enable_dollar_recipients = TRUE;
- rc = acl_check(ACL_WHERE_PREDATA, NULL, acl, &user_msg,
- &log_msg);
- enable_dollar_recipients = FALSE;
- if (rc == OK && !check_sync()) goto SYNC_FAILURE;
- }
-
- if (rc == OK)
- {
- uschar * code;
- code = US"354";
- if (user_msg == NULL)
- smtp_printf("%s Enter message, ending with \".\" on a line by itself\r\n", code);
- else smtp_user_msg(code, 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_in.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)) == 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_in.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 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 != 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, 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, TRUE);
- #endif
-
- done = 2;
- log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
- smtp_get_connection_info());
- break;