- 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;
- }
- }