- {
- s = string_cat(s, &size, &ptr, US"250-SIZE\r\n", 10);
- }
-
- /* 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, US"250-8BITMIME\r\n", 14);
-
- /* 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, US"250-ETRN\r\n", 10);
- }
-
- /* 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, US"250-EXPN\r\n", 10);
- }
-
- /* Exim is quite happy with pipelining, so let the other end know that
- it is safe to use it, unless advertising is disabled. */
-
- if (verify_check_host(&pipelining_advertise_hosts) == OK)
- {
- s = string_cat(s, &size, &ptr, US"250-PIPELINING\r\n", 16);
- 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, US"250-AUTH", 8);
- 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_active < 0 &&
- verify_check_host(&tls_advertise_hosts) != FAIL)
- {
- s = string_cat(s, &size, &ptr, US"250-STARTTLS\r\n", 14);
- tls_advertised = TRUE;
- }
- #endif
-
- /* Finish off the multiline reply with one that is always available. */
-
- s = string_cat(s, &size, &ptr, US"250 HELP\r\n", 10);
- }
-
- /* Terminate the string (for debug), write it, and note that HELO/EHLO
- has been seen. */
-
- s[ptr] = 0;
-
- #ifdef SUPPORT_TLS
- if (tls_active >= 0) (void)tls_write(s, ptr); else
- #endif
-
- (void)fwrite(s, 1, ptr, smtp_out);
- 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;
- 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:
- smtp_mailcmd_count++; /* Count for limit and ratelimit */
- was_rej_mail = TRUE; /* Reset if accepted */
-
- 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_argument[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;
-
- if (!extract_option(&name, &value)) break;
-
- /* 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. */
-
- if (strcmpic(name, US"SIZE") == 0 &&
- ((size = (int)Ustrtoul(value, &end, 10)), *end == 0))
- {
- if ((size == ULONG_MAX && errno == ERANGE) || size > INT_MAX)
- size = INT_MAX;
- message_size = (int)size;
- }
-
- /* 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. */
-
- else if (accept_8bitmime && strcmpic(name, US"BODY") == 0 &&
- (strcmpic(value, US"8BITMIME") == 0 ||
- strcmpic(value, US"7BIT") == 0)) {}
-
- /* 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. */
-
- else if (strcmpic(name, US"AUTH") == 0)
- {
- if (Ustrcmp(value, "<>") != 0)
- {
- int rc;
- uschar *ignore_msg;
-
- if (auth_xtextdecode(value, &authenticated_sender) < 0)
- {
- /* Put back terminator overrides for error message */
- name[-1] = ' ';
- value[-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:
- name[-1] = ' ';
- value[-1] = '=';
- (void)smtp_handle_acl_fail(ACL_WHERE_MAILAUTH, rc, user_msg,
- log_msg);
- goto COMMAND_LOOP;
- }
- }
- }
-
- /* Unknown option. Stick back the terminator characters and break
- the loop. An error for a malformed address will occur. */
-
- else
- {
- name[-1] = ' ';
- value[-1] = '=';
- 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_argument, rewrite_smtp, NULL, FALSE, US"",
- global_rewrite_rules) : smtp_cmd_argument;
-
- /* 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_argument, 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_argument);
- 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 */
-
- rc = (acl_smtp_mail == NULL)? OK :
- acl_check(ACL_WHERE_MAIL, NULL, acl_smtp_mail, &user_msg, &log_msg);
-
- if (rc == OK || rc == DISCARD)
- {
- smtp_printf("250 OK\r\n");
- 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. All we do
- here is to parse it for syntactic correctness. There may be any number
- of RCPT commands, specifying multiple senders. We build them all into
- a data structure that is in argc/argv format. The start/end values
- given by parse_extract_address are not used, as we keep only the
- extracted address. */
-
- case RCPT_CMD:
- rcpt_count++;
- was_rcpt = 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 */