-/* $Cambridge: exim/src/src/receive.c,v 1.12 2005/03/08 15:32:02 tom Exp $ */
+/* $Cambridge: exim/src/src/receive.c,v 1.34 2007/02/16 22:23:35 magnus Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2007 */
/* See the file NOTICE for conditions of use and distribution. */
/* Code for receiving a message and setting up spool files. */
/* Now close the file if it is open, either as a fd or a stream. */
-if (data_file != NULL) fclose(data_file);
- else if (data_fd >= 0) close(data_fd);
+if (data_file != NULL) (void)fclose(data_file);
+ else if (data_fd >= 0) (void)close(data_fd);
/* Attempt to close down an SMTP connection tidily. */
msg = US"SMTP incoming data timeout";
log_write(L_lost_incoming_connection,
LOG_MAIN, "SMTP data timeout (message abandoned) on connection "
- "from %s",
- (sender_fullhost != NULL)? sender_fullhost : US"local process");
+ "from %s F=<%s>",
+ (sender_fullhost != NULL)? sender_fullhost : US"local process",
+ sender_address);
}
else
{
{
if ((--recipients_count - count) > 0)
memmove(recipients_list + count, recipients_list + count + 1,
- (recipients_count - count)*sizeof(recipient_item));
+ (recipients_count - count)*sizeof(recipient_item));
return TRUE;
}
}
error_rc = EXIT_FAILURE;
}
else fprintf(stderr, "exim: %s%s\n", text2, text1); /* Sic */
-fclose(f);
+(void)fclose(f);
exim_exit(error_rc);
}
header_line *h, *next;
header_line *last_received = NULL;
-if (acl_warn_headers == NULL) return;
+if (acl_added_headers == NULL) return;
DEBUG(D_receive|D_acl) debug_printf(">>Headers added by %s ACL:\n", acl_name);
-for (h = acl_warn_headers; h != NULL; h = next)
+for (h = acl_added_headers; h != NULL; h = next)
{
next = h->next;
DEBUG(D_receive|D_acl) debug_printf(" %s", header_last->text);
}
-acl_warn_headers = NULL;
+acl_added_headers = NULL;
DEBUG(D_receive|D_acl) debug_printf(">>\n");
}
+#ifdef WITH_CONTENT_SCAN
+
+/*************************************************
+* Run the MIME ACL on a message *
+*************************************************/
+
+/* This code is in a subroutine so that it can be used for both SMTP
+and non-SMTP messages. It is called with a non-NULL ACL pointer.
+
+Arguments:
+ acl The ACL to run (acl_smtp_mime or acl_not_smtp_mime)
+ smtp_yield_ptr Set FALSE to kill messages after dropped connection
+ smtp_reply_ptr Where SMTP reply is being built
+ blackholed_by_ptr Where "blackholed by" message is being built
+
+Returns: TRUE to carry on; FALSE to abandon the message
+*/
+
+static BOOL
+run_mime_acl(uschar *acl, BOOL *smtp_yield_ptr, uschar **smtp_reply_ptr,
+ uschar **blackholed_by_ptr)
+{
+FILE *mbox_file;
+uschar rfc822_file_path[2048];
+unsigned long mbox_size;
+header_line *my_headerlist;
+uschar *user_msg, *log_msg;
+int mime_part_count_buffer = -1;
+int rc;
+
+memset(CS rfc822_file_path,0,2048);
+
+/* check if it is a MIME message */
+my_headerlist = header_list;
+while (my_headerlist != NULL)
+ {
+ /* skip deleted headers */
+ if (my_headerlist->type == '*')
+ {
+ my_headerlist = my_headerlist->next;
+ continue;
+ }
+ if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0)
+ {
+ DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n");
+ goto DO_MIME_ACL;
+ }
+ my_headerlist = my_headerlist->next;
+ }
+
+DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
+return TRUE;
+
+DO_MIME_ACL:
+/* make sure the eml mbox file is spooled up */
+mbox_file = spool_mbox(&mbox_size);
+if (mbox_file == NULL) {
+ /* error while spooling */
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected.");
+ Uunlink(spool_name);
+ unspool_mbox();
+ smtp_respond(US"451", 3, TRUE, US"temporary local problem");
+ message_id[0] = 0; /* Indicate no message accepted */
+ *smtp_reply_ptr = US""; /* Indicate reply already sent */
+ return FALSE; /* Indicate skip to end of receive function */
+};
+
+mime_is_rfc822 = 0;
+
+MIME_ACL_CHECK:
+mime_part_count = -1;
+rc = mime_acl_check(acl, mbox_file, NULL, &user_msg, &log_msg);
+(void)fclose(mbox_file);
+
+if (Ustrlen(rfc822_file_path) > 0)
+ {
+ mime_part_count = mime_part_count_buffer;
+
+ if (unlink(CS rfc822_file_path) == -1)
+ {
+ log_write(0, LOG_PANIC,
+ "acl_smtp_mime: can't unlink RFC822 spool file, skipping.");
+ goto END_MIME_ACL;
+ }
+ }
+
+/* check if we must check any message/rfc822 attachments */
+if (rc == OK)
+ {
+ uschar temp_path[1024];
+ int n;
+ struct dirent *entry;
+ DIR *tempdir;
+
+ (void)string_format(temp_path, 1024, "%s/scan/%s", spool_directory,
+ message_id);
+
+ tempdir = opendir(CS temp_path);
+ n = 0;
+ do
+ {
+ entry = readdir(tempdir);
+ if (entry == NULL) break;
+ if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0)
+ {
+ (void)string_format(rfc822_file_path, 2048,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name);
+ debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path);
+ break;
+ }
+ } while (1);
+ closedir(tempdir);
+
+ if (entry != NULL)
+ {
+ mbox_file = Ufopen(rfc822_file_path,"rb");
+ if (mbox_file == NULL)
+ {
+ log_write(0, LOG_PANIC,
+ "acl_smtp_mime: can't open RFC822 spool file, skipping.");
+ unlink(CS rfc822_file_path);
+ goto END_MIME_ACL;
+ }
+ /* set RFC822 expansion variable */
+ mime_is_rfc822 = 1;
+ mime_part_count_buffer = mime_part_count;
+ goto MIME_ACL_CHECK;
+ }
+ }
+
+END_MIME_ACL:
+add_acl_headers(US"MIME");
+if (rc == DISCARD)
+ {
+ recipients_count = 0;
+ *blackholed_by_ptr = US"MIME ACL";
+ }
+else if (rc != OK)
+ {
+ Uunlink(spool_name);
+ unspool_mbox();
+ if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0)
+ *smtp_yield_ptr = FALSE; /* No more messsages after dropped connection */
+ *smtp_reply_ptr = US""; /* Indicate reply already sent */
+ message_id[0] = 0; /* Indicate no message accepted */
+ return FALSE; /* Cause skip to end of receive function */
+ }
+
+return TRUE;
+}
+
+#endif /* WITH_CONTENT_SCAN */
+
/*************************************************
* Receive message *
Either a non-null list of recipients, or the extract flag will be true, or
both. The flag sender_local is true for locally generated messages. The flag
submission_mode is true if an ACL has obeyed "control = submission". The flag
-smtp_input is true if the message is to be handled using SMTP conventions about
-termination and lines starting with dots. For non-SMTP messages, dot_ends is
-true for dot-terminated messages.
+suppress_local_fixups is true if an ACL has obeyed "control =
+suppress_local_fixups". The flag smtp_input is true if the message is to be
+handled using SMTP conventions about termination and lines starting with dots.
+For non-SMTP messages, dot_ends is true for dot-terminated messages.
If a message was successfully read, message_id[0] will be non-zero.
uschar *errmsg, *s;
struct stat statbuf;
-/* Final message to give to SMTP caller */
+/* Final message to give to SMTP caller, and messages from ACLs */
uschar *smtp_reply = NULL;
+uschar *user_msg, *log_msg;
/* Working header pointers */
header_line *h, *next;
-/* Flags for noting the existence of certain headers */
-
-/**** No longer check for these (Nov 2003)
-BOOL to_or_cc_header_exists = FALSE;
-BOOL bcc_header_exists = FALSE;
-****/
+/* Flags for noting the existence of certain headers (only one left) */
BOOL date_header_exists = FALSE;
if (thismessage_size_limit <= 0) thismessage_size_limit = INT_MAX;
-/* While reading the message, body_linecount and body_zerocount is computed.
-The full message_ linecount is set up only when the headers are read back in
-from the spool for delivery. */
+/* While reading the message, the following counts are computed. */
-body_linecount = body_zerocount = 0;
+message_linecount = body_linecount = body_zerocount = 0;
#ifdef EXPERIMENTAL_DOMAINKEYS
/* Call into DK to set up the context. Check if DK is to be run are carried out
/* End of header line reached */
EOL:
- receive_linecount++; /* For BSMTP errors */
+
+ /* Keep track of lines for BSMTP errors and overall message_linecount. */
+
+ receive_linecount++;
+ message_linecount++;
/* Now put in the terminating newline. There is always space for
at least two more characters. */
switch (header_checkname(h, is_resent))
{
- /* "Bcc:" gets flagged, and its existence noted, whether it's resent- or
- not. */
-
case htype_bcc:
- h->type = htype_bcc;
- /****
- bcc_header_exists = TRUE;
- ****/
+ h->type = htype_bcc; /* Both Bcc: and Resent-Bcc: */
break;
- /* "Cc:" gets flagged, and the existence of a recipient header is noted,
- whether it's resent- or not. */
-
case htype_cc:
- h->type = htype_cc;
- /****
- to_or_cc_header_exists = TRUE;
- ****/
+ h->type = htype_cc; /* Both Cc: and Resent-Cc: */
break;
/* Record whether a Date: or Resent-Date: header exists, as appropriate. */
break;
/* If there is a "Sender:" header and the message is locally originated,
- and from an untrusted caller, or if we are in submission mode for a remote
- message, mark it "old" so that it will not be transmitted with the message,
- unless active_local_sender_retain is set. (This can only be true if
- active_local_from_check is false.) If there are any resent- headers in the
- message, apply this rule to Resent-Sender: instead of Sender:. Messages
- with multiple resent- header sets cannot be tidily handled. (For this
- reason, at least one MUA - Pine - turns old resent- headers into X-resent-
- headers when resending, leaving just one set.) */
+ and from an untrusted caller and suppress_local_fixups is not set, or if we
+ are in submission mode for a remote message, mark it "old" so that it will
+ not be transmitted with the message, unless active_local_sender_retain is
+ set. (This can only be true if active_local_from_check is false.) If there
+ are any resent- headers in the message, apply this rule to Resent-Sender:
+ instead of Sender:. Messages with multiple resent- header sets cannot be
+ tidily handled. (For this reason, at least one MUA - Pine - turns old
+ resent- headers into X-resent- headers when resending, leaving just one
+ set.) */
case htype_sender:
h->type = ((!active_local_sender_retain &&
- ((sender_local && !trusted_caller) || submission_mode)
+ (
+ (sender_local && !trusted_caller && !suppress_local_fixups)
+ || submission_mode
+ )
) &&
(!resents_exist||is_resent))?
htype_old : htype_sender;
recipients_count = recipients_list_max = 0;
}
- parse_allow_group = TRUE; /* Allow address group syntax */
-
/* Now scan the headers */
for (h = header_list->next; h != NULL; h = h->next)
uschar *s = Ustrchr(h->text, ':') + 1;
while (isspace(*s)) s++;
+ parse_allow_group = TRUE; /* Allow address group syntax */
+
while (*s != 0)
{
uschar *ss = parse_find_address_end(s, FALSE);
s = ss + (*ss? 1:0);
while (isspace(*s)) s++;
- }
+ } /* Next address */
+
+ parse_allow_group = FALSE; /* Reset group syntax flags */
+ parse_found_group = FALSE;
/* If this was the bcc: header, mark it "old", which means it
will be kept on the spool, but not transmitted as part of the
message. */
- if (h->type == htype_bcc)
- {
- h->type = htype_old;
- /****
- bcc_header_exists = FALSE;
- ****/
- }
+ if (h->type == htype_bcc) h->type = htype_old;
} /* For appropriate header line */
} /* For each header line */
- parse_allow_group = FALSE; /* Reset group syntax flags */
- parse_found_group = FALSE;
}
/* Now build the unique message id. This has changed several times over the
message_subdir[0] = split_spool_directory? message_id[5] : 0;
/* Now that we have the message-id, if there is no message-id: header, generate
-one, but only for local or submission mode messages. This can be
-user-configured if required, but we had better flatten any illegal characters
-therein. */
+one, but only for local (without suppress_local_fixups) or submission mode
+messages. This can be user-configured if required, but we had better flatten
+any illegal characters therein. */
-if (msgid_header == NULL && (sender_host_address == NULL || submission_mode))
+if (msgid_header == NULL &&
+ ((sender_host_address == NULL && !suppress_local_fixups)
+ || submission_mode))
{
uschar *p;
uschar *id_text = US"";
rewrite_address(recipients_list[i].address, TRUE, TRUE,
global_rewrite_rules, rewrite_existflags);
-/* If there is no From: header, generate one for local or submission_mode
-messages. If there is no sender address, but the sender is local or this is a
-local delivery error, use the originator login. This shouldn't happen for
-genuine bounces, but might happen for autoreplies. The addition of From: must
-be done *before* checking for the possible addition of a Sender: header,
-because untrusted_set_sender allows an untrusted user to set anything in the
-envelope (which might then get info From:) but we still want to ensure a valid
-Sender: if it is required. */
-
-if (from_header == NULL && (sender_host_address == NULL || submission_mode))
+/* If there is no From: header, generate one for local (without
+suppress_local_fixups) or submission_mode messages. If there is no sender
+address, but the sender is local or this is a local delivery error, use the
+originator login. This shouldn't happen for genuine bounces, but might happen
+for autoreplies. The addition of From: must be done *before* checking for the
+possible addition of a Sender: header, because untrusted_set_sender allows an
+untrusted user to set anything in the envelope (which might then get info
+From:) but we still want to ensure a valid Sender: if it is required. */
+
+if (from_header == NULL &&
+ ((sender_host_address == NULL && !suppress_local_fixups)
+ || submission_mode))
{
+ uschar *oname = US"";
+
+ /* Use the originator_name if this is a locally submitted message and the
+ caller is not trusted. For trusted callers, use it only if -F was used to
+ force its value or if we have a non-SMTP message for which -f was not used
+ to set the sender. */
+
+ if (sender_host_address == NULL)
+ {
+ if (!trusted_caller || sender_name_forced ||
+ (!smtp_input && !sender_address_forced))
+ oname = originator_name;
+ }
+
+ /* For non-locally submitted messages, the only time we use the originator
+ name is when it was forced by the /name= option on control=submission. */
+
+ else
+ {
+ if (submission_name != NULL) oname = submission_name;
+ }
+
/* Envelope sender is empty */
if (sender_address[0] == 0)
{
+ uschar *fromstart, *fromend;
+
+ fromstart = string_sprintf("%sFrom: %s%s", resent_prefix,
+ oname, (oname[0] == 0)? "" : " <");
+ fromend = (oname[0] == 0)? US"" : US">";
+
if (sender_local || local_error_message)
{
- header_add(htype_from, "%sFrom: %s%s%s@%s%s\n", resent_prefix,
- originator_name,
- (originator_name[0] == 0)? "" : " <",
- local_part_quote(originator_login),
- qualify_domain_sender,
- (originator_name[0] == 0)? "" : ">");
+ header_add(htype_from, "%s%s@%s%s\n", fromstart,
+ local_part_quote(originator_login), qualify_domain_sender,
+ fromend);
}
else if (submission_mode && authenticated_id != NULL)
{
if (submission_domain == NULL)
{
- header_add(htype_from, "%sFrom: %s@%s\n", resent_prefix,
- local_part_quote(authenticated_id), qualify_domain_sender);
+ header_add(htype_from, "%s%s@%s%s\n", fromstart,
+ local_part_quote(authenticated_id), qualify_domain_sender,
+ fromend);
}
else if (submission_domain[0] == 0) /* empty => whole address set */
{
- header_add(htype_from, "%sFrom: %s\n", resent_prefix,
- authenticated_id);
+ header_add(htype_from, "%s%s%s\n", fromstart, authenticated_id,
+ fromend);
}
else
{
- header_add(htype_from, "%sFrom: %s@%s\n", resent_prefix,
- local_part_quote(authenticated_id), submission_domain);
+ header_add(htype_from, "%s%s@%s%s\n", fromstart,
+ local_part_quote(authenticated_id), submission_domain,
+ fromend);
}
from_header = header_last; /* To get it checked for Sender: */
}
else
{
- if (!smtp_input || sender_local)
- header_add(htype_from, "%sFrom: %s%s%s%s\n",
- resent_prefix, originator_name,
- (originator_name[0] == 0)? "" : " <",
- (sender_address_unrewritten == NULL)?
- sender_address : sender_address_unrewritten,
- (originator_name[0] == 0)? "" : ">");
- else
- header_add(htype_from, "%sFrom: %s\n", resent_prefix, sender_address);
+ header_add(htype_from, "%sFrom: %s%s%s%s\n", resent_prefix,
+ oname,
+ (oname[0] == 0)? "" : " <",
+ (sender_address_unrewritten == NULL)?
+ sender_address : sender_address_unrewritten,
+ (oname[0] == 0)? "" : ">");
from_header = header_last; /* To get it checked for Sender: */
}
}
-/* If the sender is local, or if we are in submission mode and there is an
-authenticated_id, check that an existing From: is correct, and if not, generate
-a Sender: header, unless disabled. Any previously-existing Sender: header was
-removed above. Note that sender_local, as well as being TRUE if the caller of
-exim is not trusted, is also true if a trusted caller did not supply a -f
-argument for non-smtp input. To allow trusted callers to forge From: without
-supplying -f, we have to test explicitly here. If the From: header contains
-more than one address, then the call to parse_extract_address fails, and a
-Sender: header is inserted, as required. */
+/* If the sender is local (without suppress_local_fixups), or if we are in
+submission mode and there is an authenticated_id, check that an existing From:
+is correct, and if not, generate a Sender: header, unless disabled. Any
+previously-existing Sender: header was removed above. Note that sender_local,
+as well as being TRUE if the caller of exim is not trusted, is also true if a
+trusted caller did not supply a -f argument for non-smtp input. To allow
+trusted callers to forge From: without supplying -f, we have to test explicitly
+here. If the From: header contains more than one address, then the call to
+parse_extract_address fails, and a Sender: header is inserted, as required. */
if (from_header != NULL &&
(active_local_from_check &&
- ((sender_local && !trusted_caller) ||
+ ((sender_local && !trusted_caller && !suppress_local_fixups) ||
(submission_mode && authenticated_id != NULL))
))
{
if (make_sender)
{
- if (submission_mode)
+ if (submission_mode && submission_name == NULL)
header_add(htype_sender, "%sSender: %s\n", resent_prefix,
generated_sender_address);
else
header_add(htype_sender, "%sSender: %s <%s>\n",
- resent_prefix, originator_name, generated_sender_address);
+ resent_prefix,
+ submission_mode? submission_name : originator_name,
+ generated_sender_address);
+ }
+
+ /* Ensure that a non-null envelope sender address corresponds to the
+ submission mode sender address. */
+
+ if (submission_mode && sender_address[0] != 0)
+ {
+ if (sender_address_unrewritten == NULL)
+ sender_address_unrewritten = sender_address;
+ sender_address = generated_sender_address;
+ log_write(L_address_rewrite, LOG_MAIN,
+ "\"%s\" from env-from rewritten as \"%s\" by submission mode",
+ sender_address_unrewritten, generated_sender_address);
}
}
/* An RFC 822 (sic) message is not legal unless it has at least one of "to",
-"cc", or "bcc". Note that although the minimal examples in RFC822 show just
+"cc", or "bcc". Note that although the minimal examples in RFC 822 show just
"to" or "bcc", the full syntax spec allows "cc" as well. If any resent- header
exists, this applies to the set of resent- headers rather than the normal set.
-The requirement for a recipient header has been removed in RFC 2822. Earlier
-versions of Exim added a To: header for locally submitted messages, and an
-empty Bcc: header for others or when always_bcc was set. In the light of the
-changes in RFC 2822, we now always add Bcc: just in case there are still MTAs
-out there that insist on the RFC 822 syntax.
-
-November 2003: While generally revising what Exim does to fix up headers, it
-seems like a good time to remove this altogether. */
+The requirement for a recipient header has been removed in RFC 2822. At this
+point in the code, earlier versions of Exim added a To: header for locally
+submitted messages, and an empty Bcc: header for others. In the light of the
+changes in RFC 2822, this was dropped in November 2003. */
-/******
-if (!to_or_cc_header_exists && !bcc_header_exists)
- header_add(htype_bcc, "Bcc:\n");
-******/
/* If there is no date header, generate one if the message originates locally
-(i.e. not over TCP/IP) or the submission mode flag is set. Messages without
-Date: are not valid, but it seems to be more confusing if Exim adds one to
-all remotely-originated messages. */
+(i.e. not over TCP/IP) and suppress_local_fixups is not set, or if the
+submission mode flag is set. Messages without Date: are not valid, but it seems
+to be more confusing if Exim adds one to all remotely-originated messages. */
-if (!date_header_exists && (sender_host_address == NULL || submission_mode))
+if (!date_header_exists &&
+ ((sender_host_address == NULL && !suppress_local_fixups)
+ || submission_mode))
header_add(htype_other, "%sDate: %s\n", resent_prefix, tod_stamp(tod_full));
search_tidyup(); /* Free any cached resources */
/* Make sure the file's group is the Exim gid, and double-check the mode
because the group setting doesn't always get set automatically. */
-fchown(data_fd, exim_uid, exim_gid);
-fchmod(data_fd, SPOOL_MODE);
+(void)fchown(data_fd, exim_uid, exim_gid);
+(void)fchmod(data_fd, SPOOL_MODE);
/* We now have data file open. Build a stream for it and lock it. We lock only
the first line of the file (containing the message ID) because otherwise there
{
uschar *s = next->text;
int len = next->slen;
- fwrite(s, 1, len, data_file);
+ (void)fwrite(s, 1, len, data_file);
body_linecount++; /* Assumes only 1 line */
}
else message_ended = read_message_data(data_file);
receive_linecount += body_linecount; /* For BSMTP errors mainly */
+ message_linecount += body_linecount;
/* Handle premature termination of SMTP */
anything until the terminating dot line is sent. */
if (fflush(data_file) == EOF || ferror(data_file) ||
- fsync(fileno(data_file)) < 0 || (receive_ferror)())
+ EXIMfsync(fileno(data_file)) < 0 || (receive_ferror)())
{
uschar *msg_errno = US strerror(errno);
BOOL input_error = (receive_ferror)() != 0;
if (recipients_count == 0 || error_handling == ERRORS_STDERR)
{
Uunlink(spool_name);
- fclose(data_file);
+ (void)fclose(data_file);
exim_exit(error_rc);
}
}
*/
deliver_datafile = data_fd;
+user_msg = NULL;
+
+enable_dollar_recipients = TRUE;
if (recipients_count == 0)
{
}
else
{
- enable_dollar_recipients = TRUE;
-
/* Handle interactive SMTP messages */
if (smtp_input && !smtp_batched_input)
#endif
#ifdef WITH_CONTENT_SCAN
- /* MIME ACL hook */
- if (acl_smtp_mime != NULL && recipients_count > 0)
- {
- FILE *mbox_file;
- uschar rfc822_file_path[2048];
- unsigned long mbox_size;
- header_line *my_headerlist;
- uschar *user_msg, *log_msg;
- int mime_part_count_buffer = -1;
-
- memset(CS rfc822_file_path,0,2048);
-
- /* check if it is a MIME message */
- my_headerlist = header_list;
- while (my_headerlist != NULL) {
- /* skip deleted headers */
- if (my_headerlist->type == '*') {
- my_headerlist = my_headerlist->next;
- continue;
- };
- if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0) {
- DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n");
- goto DO_MIME_ACL;
- };
- my_headerlist = my_headerlist->next;
- };
-
- DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
- goto NO_MIME_ACL;
-
- DO_MIME_ACL:
- /* make sure the eml mbox file is spooled up */
- mbox_file = spool_mbox(&mbox_size);
- if (mbox_file == NULL) {
- /* error while spooling */
- log_write(0, LOG_MAIN|LOG_PANIC,
- "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected.");
- Uunlink(spool_name);
- unspool_mbox();
- smtp_respond(451, TRUE, US"temporary local problem");
- message_id[0] = 0; /* Indicate no message accepted */
- smtp_reply = US""; /* Indicate reply already sent */
- goto TIDYUP; /* Skip to end of function */
- };
-
- mime_is_rfc822 = 0;
-
- MIME_ACL_CHECK:
- mime_part_count = -1;
- rc = mime_acl_check(mbox_file, NULL, &user_msg, &log_msg);
- fclose(mbox_file);
-
- if (Ustrlen(rfc822_file_path) > 0) {
- mime_part_count = mime_part_count_buffer;
-
- if (unlink(CS rfc822_file_path) == -1) {
- log_write(0, LOG_PANIC,
- "acl_smtp_mime: can't unlink RFC822 spool file, skipping.");
- goto END_MIME_ACL;
- };
- };
-
- /* check if we must check any message/rfc822 attachments */
- if (rc == OK) {
- uschar temp_path[1024];
- int n;
- struct dirent *entry;
- DIR *tempdir;
-
- snprintf(CS temp_path, 1024, "%s/scan/%s", spool_directory, message_id);
-
- tempdir = opendir(CS temp_path);
- n = 0;
- do {
- entry = readdir(tempdir);
- if (entry == NULL) break;
- if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0) {
- snprintf(CS rfc822_file_path, 2048,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name);
- debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path);
- break;
- };
- } while (1);
- closedir(tempdir);
-
- if (entry != NULL) {
- mbox_file = Ufopen(rfc822_file_path,"r");
- if (mbox_file == NULL) {
- log_write(0, LOG_PANIC,
- "acl_smtp_mime: can't open RFC822 spool file, skipping.");
- unlink(CS rfc822_file_path);
- goto END_MIME_ACL;
- };
- /* set RFC822 expansion variable */
- mime_is_rfc822 = 1;
- mime_part_count_buffer = mime_part_count;
- goto MIME_ACL_CHECK;
- };
- };
-
- END_MIME_ACL:
- add_acl_headers(US"MIME");
- if (rc == DISCARD)
- {
- recipients_count = 0;
- blackholed_by = US"MIME ACL";
- }
- else if (rc != OK)
- {
- Uunlink(spool_name);
- unspool_mbox();
- if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0)
- smtp_yield = FALSE; /* No more messsages after dropped connection */
- smtp_reply = US""; /* Indicate reply already sent */
- message_id[0] = 0; /* Indicate no message accepted */
- goto TIDYUP; /* Skip to end of function */
- };
- }
-
- NO_MIME_ACL:
+ if (acl_smtp_mime != NULL &&
+ !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by))
+ goto TIDYUP;
#endif /* WITH_CONTENT_SCAN */
+ /* Check the recipients count again, as the MIME ACL might have changed
+ them. */
if (acl_smtp_data != NULL && recipients_count > 0)
{
- uschar *user_msg, *log_msg;
rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg);
add_acl_headers(US"DATA");
if (rc == DISCARD)
/* Handle non-SMTP and batch SMTP (i.e. non-interactive) messages. Note that
we cannot take different actions for permanent and temporary rejections. */
- else if (acl_not_smtp != NULL)
+ else
{
- uschar *user_msg, *log_msg;
- rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg);
- if (rc == DISCARD)
- {
- recipients_count = 0;
- blackholed_by = US"non-SMTP ACL";
- if (log_msg != NULL) blackhole_log_msg = string_sprintf(": %s", log_msg);
- }
- else if (rc != OK)
+
+#ifdef WITH_CONTENT_SCAN
+ if (acl_not_smtp_mime != NULL &&
+ !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply,
+ &blackholed_by))
+ goto TIDYUP;
+#endif /* WITH_CONTENT_SCAN */
+
+ if (acl_not_smtp != NULL)
{
- Uunlink(spool_name);
- log_write(0, LOG_MAIN|LOG_REJECT, "F=<%s> rejected by non-SMTP ACL: %s",
- sender_address, log_msg);
- if (user_msg == NULL) user_msg = US"local configuration problem";
- if (smtp_batched_input)
+ uschar *user_msg, *log_msg;
+ rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg);
+ if (rc == DISCARD)
{
- moan_smtp_batch(NULL, "%d %s", 550, user_msg);
- /* Does not return */
+ recipients_count = 0;
+ blackholed_by = US"non-SMTP ACL";
+ if (log_msg != NULL)
+ blackhole_log_msg = string_sprintf(": %s", log_msg);
}
- else
+ else if (rc != OK)
{
- fseek(data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
- give_local_error(ERRMESS_LOCAL_ACL, user_msg,
- US"message rejected by non-SMTP ACL: ", error_rc, data_file,
- header_list);
- /* Does not return */
+ Uunlink(spool_name);
+#ifdef WITH_CONTENT_SCAN
+ unspool_mbox();
+#endif
+ /* The ACL can specify where rejections are to be logged, possibly
+ nowhere. The default is main and reject logs. */
+
+ if (log_reject_target != 0)
+ log_write(0, log_reject_target, "F=<%s> rejected by non-SMTP ACL: %s",
+ sender_address, log_msg);
+
+ if (user_msg == NULL) user_msg = US"local configuration problem";
+ if (smtp_batched_input)
+ {
+ moan_smtp_batch(NULL, "%d %s", 550, user_msg);
+ /* Does not return */
+ }
+ else
+ {
+ fseek(data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
+ give_local_error(ERRMESS_LOCAL_ACL, user_msg,
+ US"message rejected by non-SMTP ACL: ", error_rc, data_file,
+ header_list);
+ /* Does not return */
+ }
}
+ add_acl_headers(US"non-SMTP");
}
- add_acl_headers(US"non-SMTP");
}
+ /* The applicable ACLs have been run */
+
if (deliver_freeze) frozen_by = US"ACL"; /* for later logging */
if (queue_only_policy) queued_by = US"ACL";
-
- enable_dollar_recipients = FALSE;
}
#ifdef WITH_CONTENT_SCAN
alarm(0);
os_non_restarting_signal(SIGALRM, sigalrm_handler);
+enable_dollar_recipients = FALSE;
+
store_pool = POOL_MAIN; /* In case changed */
DEBUG(D_receive) debug_printf("local_scan() returned %d %s\n", rc,
local_scan_data);
{
uschar *istemp = US"";
uschar *s = NULL;
+ uschar *smtp_code;
int size = 0;
int sptr = 0;
- int code;
errmsg = local_scan_data;
/* Fall through */
case LOCAL_SCAN_REJECT:
- code = 550;
+ smtp_code = US"550";
if (errmsg == NULL) errmsg = US"Administrative prohibition";
break;
case LOCAL_SCAN_TEMPREJECT:
TEMPREJECT:
- code = 451;
+ smtp_code = US"451";
if (errmsg == NULL) errmsg = US"Temporary local problem";
istemp = US"temporarily ";
break;
{
if (!smtp_batched_input)
{
- smtp_respond(code, TRUE, errmsg);
+ smtp_respond(smtp_code, 3, TRUE, errmsg);
message_id[0] = 0; /* Indicate no message accepted */
smtp_reply = US""; /* Indicate reply already sent */
goto TIDYUP; /* Skip to end of function */
}
else
{
- moan_smtp_batch(NULL, "%d %s", code, errmsg);
+ moan_smtp_batch(NULL, "%s %s", smtp_code, errmsg);
/* Does not return */
}
}
{
log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't fdopen message log %s: %s",
spool_name, strerror(errno));
- close(fd);
+ (void)close(fd);
}
else
{
frozen_by);
if (queue_only_policy) fprintf(message_log,
"%s no immediate delivery: queued by %s\n", now, queued_by);
- fclose(message_log);
+ (void)fclose(message_log);
}
}
}
if this happens? */
TIDYUP:
-process_info[process_info_len] = 0; /* Remove message id */
-if (data_file != NULL) fclose(data_file); /* Frees the lock */
+process_info[process_info_len] = 0; /* Remove message id */
+if (data_file != NULL) (void)fclose(data_file); /* Frees the lock */
/* Now reset signal handlers to their defaults */
{
if (smtp_reply == NULL)
{
- if (fake_reject)
- smtp_respond(550,TRUE,fake_reject_text);
+ if (fake_response != OK)
+ smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE,
+ fake_response_text);
+
+ /* An OK response is required; use "message" text if present. */
+
+ else if (user_msg != NULL)
+ {
+ uschar *code = US"250";
+ int len = 3;
+ smtp_message_code(&code, &len, &user_msg, NULL);
+ smtp_respond(code, len, TRUE, user_msg);
+ }
+
+ /* Default OK response */
+
else
smtp_printf("250 OK id=%s\r\n", message_id);
if (host_checking)
fprintf(stdout,
"\n**** SMTP testing: that is not a real message id!\n\n");
}
+
+ /* smtp_reply was previously set */
+
else if (smtp_reply[0] != 0)
{
- if (fake_reject && (smtp_reply[0] == '2'))
- smtp_respond(550,TRUE,fake_reject_text);
+ if (fake_response != OK && (smtp_reply[0] == '2'))
+ smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE,
+ fake_response_text);
else
smtp_printf("%.1024s\r\n", smtp_reply);
}