"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/moan.c" between
exim-4.91.tar.xz and exim-4.92.tar.xz

About: Exim is a message transfer agent (MTA).

moan.c  (exim-4.91.tar.xz):moan.c  (exim-4.92.tar.xz)
skipping to change at line 29 skipping to change at line 29
for the option is used. for the option is used.
Argument: the FILE to write to Argument: the FILE to write to
Returns: nothing Returns: nothing
*/ */
void void
moan_write_from(FILE *f) moan_write_from(FILE *f)
{ {
uschar *s = expand_string(dsn_from); uschar *s = expand_string(dsn_from);
if (s == NULL) if (!s)
{ {
log_write(0, LOG_MAIN|LOG_PANIC, log_write(0, LOG_MAIN|LOG_PANIC,
"Failed to expand dsn_from (using default): %s", expand_string_message); "Failed to expand dsn_from (using default): %s", expand_string_message);
s = expand_string(US DEFAULT_DSN_FROM); s = expand_string(US DEFAULT_DSN_FROM);
} }
fprintf(f, "From: %s\n", s); fprintf(f, "From: %s\n", s);
} }
/************************************************* /*************************************************
* Send error message * * Send error message *
skipping to change at line 59 skipping to change at line 59
ident identifies the type of error ident identifies the type of error
eblock chain of error_blocks containing data about the error eblock chain of error_blocks containing data about the error
headers the message's headers headers the message's headers
message_file FILE containing the body of the message message_file FILE containing the body of the message
firstline contains first line of file, if it was read to check for firstline contains first line of file, if it was read to check for
"From ", but it turned out not to be "From ", but it turned out not to be
Returns: TRUE if message successfully sent Returns: TRUE if message successfully sent
*/ */
static BOOL BOOL
moan_send_message(uschar *recipient, int ident, error_block *eblock, moan_send_message(uschar *recipient, int ident, error_block *eblock,
header_line *headers, FILE *message_file, uschar *firstline) header_line *headers, FILE *message_file, uschar *firstline)
{ {
int written = 0; int written = 0;
int fd; int fd;
int status; int status;
int count = 0; int count = 0;
int size_limit = bounce_return_size_limit; int size_limit = bounce_return_size_limit;
FILE *f; FILE * fp;
int pid = child_open_exim(&fd); int pid;
#ifdef EXPERIMENTAL_DMARC
uschar * s, * s2;
/* Creation of child failed */ /* For DMARC if there is a specific sender set, expand the variable for the
header From: and grab the address from that for the envelope FROM. */
if ( ident == ERRMESS_DMARC_FORENSIC
&& dmarc_forensic_sender
&& (s = expand_string(dmarc_forensic_sender))
&& *s
&& (s2 = expand_string(string_sprintf("${address:%s}", s)))
&& *s2
)
pid = child_open_exim2(&fd, s2, bounce_sender_authentication);
else
{
s = NULL;
pid = child_open_exim(&fd);
}
#else
pid = child_open_exim(&fd);
#endif
if (pid < 0) if (pid < 0)
{ {
DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n", DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n",
strerror(errno)); strerror(errno));
return FALSE; return FALSE;
} }
else DEBUG(D_any) debug_printf("Child process %d for sending message\n", pid); else DEBUG(D_any) debug_printf("Child process %d for sending message\n", pid);
/* Creation of child succeeded */ /* Creation of child succeeded */
f = fdopen(fd, "wb"); fp = fdopen(fd, "wb");
if (errors_reply_to) fprintf(f, "Reply-To: %s\n", errors_reply_to); if (errors_reply_to) fprintf(fp, "Reply-To: %s\n", errors_reply_to);
fprintf(f, "Auto-Submitted: auto-replied\n"); fprintf(fp, "Auto-Submitted: auto-replied\n");
moan_write_from(f);
fprintf(f, "To: %s\n", recipient); #ifdef EXPERIMENTAL_DMARC
if (s)
fprintf(fp, "From: %s\n", s);
else
#endif
moan_write_from(fp);
fprintf(fp, "To: %s\n", recipient);
switch(ident) switch(ident)
{ {
case ERRMESS_BADARGADDRESS: case ERRMESS_BADARGADDRESS:
fprintf(f, fprintf(fp,
"Subject: Mail failure - malformed recipient address\n\n"); "Subject: Mail failure - malformed recipient address\n\n");
fprintf(f, fprintf(fp,
"A message that you sent contained a recipient address that was incorrectl y\n" "A message that you sent contained a recipient address that was incorrectl y\n"
"constructed:\n\n"); "constructed:\n\n");
fprintf(f, " %s %s\n", eblock->text1, eblock->text2); fprintf(fp, " %s %s\n", eblock->text1, eblock->text2);
count = Ustrlen(eblock->text1); count = Ustrlen(eblock->text1);
if (count > 0 && eblock->text1[count-1] == '.') if (count > 0 && eblock->text1[count-1] == '.')
fprintf(f, fprintf(fp,
"\nRecipient addresses must not end with a '.' character.\n"); "\nRecipient addresses must not end with a '.' character.\n");
fprintf(f, fprintf(fp,
"\nThe message has not been delivered to any recipients.\n"); "\nThe message has not been delivered to any recipients.\n");
break; break;
case ERRMESS_BADNOADDRESS: case ERRMESS_BADNOADDRESS:
case ERRMESS_BADADDRESS: case ERRMESS_BADADDRESS:
fprintf(f, fprintf(fp,
"Subject: Mail failure - malformed recipient address\n\n"); "Subject: Mail failure - malformed recipient address\n\n");
fprintf(f, fprintf(fp,
"A message that you sent contained one or more recipient addresses that we re\n" "A message that you sent contained one or more recipient addresses that we re\n"
"incorrectly constructed:\n\n"); "incorrectly constructed:\n\n");
while (eblock != NULL) while (eblock != NULL)
{ {
fprintf(f, " %s: %s\n", eblock->text1, eblock->text2); fprintf(fp, " %s: %s\n", eblock->text1, eblock->text2);
count++; count++;
eblock = eblock->next; eblock = eblock->next;
} }
fprintf(f, (count == 1)? "\nThis address has been ignored. " : fprintf(fp, (count == 1)? "\nThis address has been ignored. " :
"\nThese addresses have been ignored. "); "\nThese addresses have been ignored. ");
fprintf(f, (ident == ERRMESS_BADADDRESS)? fprintf(fp, (ident == ERRMESS_BADADDRESS)?
"The other addresses in the message were\n" "The other addresses in the message were\n"
"syntactically valid and have been passed on for an attempt at delivery.\n " : "syntactically valid and have been passed on for an attempt at delivery.\n " :
"There were no other addresses in your\n" "There were no other addresses in your\n"
"message, and so no attempt at delivery was possible.\n"); "message, and so no attempt at delivery was possible.\n");
break; break;
case ERRMESS_IGADDRESS: case ERRMESS_IGADDRESS:
fprintf(f, "Subject: Mail failure - no recipient addresses\n\n"); fprintf(fp, "Subject: Mail failure - no recipient addresses\n\n");
fprintf(f, fprintf(fp,
"A message that you sent using the -t command line option contained no\n" "A message that you sent using the -t command line option contained no\n"
"addresses that were not also on the command line, and were therefore\n" "addresses that were not also on the command line, and were therefore\n"
"suppressed. This left no recipient addresses, and so no delivery could\n" "suppressed. This left no recipient addresses, and so no delivery could\n"
"be attempted.\n"); "be attempted.\n");
break; break;
case ERRMESS_NOADDRESS: case ERRMESS_NOADDRESS:
fprintf(f, "Subject: Mail failure - no recipient addresses\n\n"); fprintf(fp, "Subject: Mail failure - no recipient addresses\n\n");
fprintf(f, fprintf(fp,
"A message that you sent contained no recipient addresses, and therefore n o\n" "A message that you sent contained no recipient addresses, and therefore n o\n"
"delivery could be attempted.\n"); "delivery could be attempted.\n");
break; break;
case ERRMESS_IOERR: case ERRMESS_IOERR:
fprintf(f, "Subject: Mail failure - system failure\n\n"); fprintf(fp, "Subject: Mail failure - system failure\n\n");
fprintf(f, fprintf(fp,
"A system failure was encountered while processing a message that you sent ,\n" "A system failure was encountered while processing a message that you sent ,\n"
"so it has not been possible to deliver it. The error was:\n\n%s\n", "so it has not been possible to deliver it. The error was:\n\n%s\n",
eblock->text1); eblock->text1);
break; break;
case ERRMESS_VLONGHEADER: case ERRMESS_VLONGHEADER:
fprintf(f, "Subject: Mail failure - overlong header section\n\n"); fprintf(fp, "Subject: Mail failure - overlong header section\n\n");
fprintf(f, fprintf(fp,
"A message that you sent contained a header section that was excessively\n " "A message that you sent contained a header section that was excessively\n "
"long and could not be handled by the mail transmission software. The\n" "long and could not be handled by the mail transmission software. The\n"
"message has not been delivered to any recipients.\n"); "message has not been delivered to any recipients.\n");
break; break;
case ERRMESS_VLONGHDRLINE: case ERRMESS_VLONGHDRLINE:
fprintf(f, "Subject: Mail failure - overlong header line\n\n"); fprintf(fp, "Subject: Mail failure - overlong header line\n\n");
fprintf(f, fprintf(fp,
"A message that you sent contained a header line that was excessively\n" "A message that you sent contained a header line that was excessively\n"
"long and could not be handled by the mail transmission software. The\n" "long and could not be handled by the mail transmission software. The\n"
"message has not been delivered to any recipients.\n"); "message has not been delivered to any recipients.\n");
break; break;
case ERRMESS_TOOBIG: case ERRMESS_TOOBIG:
fprintf(f, "Subject: Mail failure - message too big\n\n"); fprintf(fp, "Subject: Mail failure - message too big\n\n");
fprintf(f, fprintf(fp,
"A message that you sent was longer than the maximum size allowed on this\ n" "A message that you sent was longer than the maximum size allowed on this\ n"
"system. It was not delivered to any recipients.\n"); "system. It was not delivered to any recipients.\n");
break; break;
case ERRMESS_TOOMANYRECIP: case ERRMESS_TOOMANYRECIP:
fprintf(f, "Subject: Mail failure - too many recipients\n\n"); fprintf(fp, "Subject: Mail failure - too many recipients\n\n");
fprintf(f, fprintf(fp,
"A message that you sent contained more recipients than allowed on this\n" "A message that you sent contained more recipients than allowed on this\n"
"system. It was not delivered to any recipients.\n"); "system. It was not delivered to any recipients.\n");
break; break;
case ERRMESS_LOCAL_SCAN: case ERRMESS_LOCAL_SCAN:
case ERRMESS_LOCAL_ACL: case ERRMESS_LOCAL_ACL:
fprintf(f, "Subject: Mail failure - rejected by local scanning code\n\n"); fprintf(fp, "Subject: Mail failure - rejected by local scanning code\n\n");
fprintf(f, fprintf(fp,
"A message that you sent was rejected by the local scanning code that\n" "A message that you sent was rejected by the local scanning code that\n"
"checks incoming messages on this system."); "checks incoming messages on this system.");
if (eblock->text1) if (eblock->text1)
fprintf(f, " The following error was given:\n\n %s", eblock->text1); fprintf(fp, " The following error was given:\n\n %s", eblock->text1);
fprintf(f, "\n"); fprintf(fp, "\n");
break; break;
#ifdef EXPERIMENTAL_DMARC #ifdef EXPERIMENTAL_DMARC
case ERRMESS_DMARC_FORENSIC: case ERRMESS_DMARC_FORENSIC:
bounce_return_message = TRUE; bounce_return_message = TRUE;
bounce_return_body = FALSE; bounce_return_body = FALSE;
fprintf(f, fprintf(fp, "Subject: DMARC Forensic Report for %s from IP %s\n\n",
"Subject: DMARC Forensic Report for %s from IP %s\n\n", eblock ? eblock->text2 : US"Unknown",
((eblock == NULL) ? US"Unknown" : eblock->text2),
sender_host_address); sender_host_address);
fprintf(f, fprintf(fp,
"A message claiming to be from you has failed the published DMARC\n" "A message claiming to be from you has failed the published DMARC\n"
"policy for your domain.\n\n"); "policy for your domain.\n\n");
while (eblock != NULL) while (eblock)
{ {
fprintf(f, " %s: %s\n", eblock->text1, eblock->text2); fprintf(fp, " %s: %s\n", eblock->text1, eblock->text2);
count++; count++;
eblock = eblock->next; eblock = eblock->next;
} }
break; break;
#endif #endif
default: default:
fprintf(f, "Subject: Mail failure\n\n"); fprintf(fp, "Subject: Mail failure\n\n");
fprintf(f, fprintf(fp,
"A message that you sent has caused the error routine to be entered with\n " "A message that you sent has caused the error routine to be entered with\n "
"an unknown error number (%d).\n", ident); "an unknown error number (%d).\n", ident);
break; break;
} }
/* Now, if configured, copy the message; first the headers and then the rest of /* Now, if configured, copy the message; first the headers and then the rest of
the input if available, up to the configured limit, if the option for including the input if available, up to the configured limit, if the option for including
message bodies in bounces is set. */ message bodies in bounces is set. */
if (bounce_return_message) if (bounce_return_message)
{ {
if (bounce_return_body) if (bounce_return_body)
{ {
fprintf(f, "\n" fprintf(fp, "\n"
"------ This is a copy of your message, including all the headers."); "------ This is a copy of your message, including all the headers.");
if (size_limit == 0 || size_limit > thismessage_size_limit) if (size_limit == 0 || size_limit > thismessage_size_limit)
size_limit = thismessage_size_limit; size_limit = thismessage_size_limit;
if (size_limit > 0 && size_limit < message_size) if (size_limit > 0 && size_limit < message_size)
{ {
int x = size_limit; int x = size_limit;
uschar *k = US""; uschar *k = US"";
if ((x & 1023) == 0) if ((x & 1023) == 0)
{ {
k = US"K"; k = US"K";
x >>= 10; x >>= 10;
} }
fprintf(f, "\n" fprintf(fp, "\n"
"------ No more than %d%s characters of the body are included.\n\n", "------ No more than %d%s characters of the body are included.\n\n",
x, k); x, k);
} }
else fprintf(f, " ------\n\n"); else fprintf(fp, " ------\n\n");
} }
else else
{ {
fprintf(f, "\n" fprintf(fp, "\n"
"------ This is a copy of the headers that were received before the " "------ This is a copy of the headers that were received before the "
"error\n was detected.\n\n"); "error\n was detected.\n\n");
} }
/* If the error occurred before the Received: header was created, its text /* If the error occurred before the Received: header was created, its text
field will still be NULL; just omit such a header line. */ field will still be NULL; just omit such a header line. */
while (headers) while (headers)
{ {
if (headers->text != NULL) fprintf(f, "%s", CS headers->text); if (headers->text != NULL) fprintf(fp, "%s", CS headers->text);
headers = headers->next; headers = headers->next;
} }
if (ident != ERRMESS_VLONGHEADER && ident != ERRMESS_VLONGHDRLINE) if (ident != ERRMESS_VLONGHEADER && ident != ERRMESS_VLONGHDRLINE)
fputc('\n', f); fputc('\n', fp);
/* After early detection of an error, the message file may be STDIN, /* After early detection of an error, the message file may be STDIN,
in which case we might have to terminate on a line containing just "." in which case we might have to terminate on a line containing just "."
as well as on EOF. We may already have the first line in memory. */ as well as on EOF. We may already have the first line in memory. */
if (bounce_return_body && message_file) if (bounce_return_body && message_file)
{ {
BOOL enddot = dot_ends && message_file == stdin; BOOL enddot = f.dot_ends && message_file == stdin;
uschar * buf = store_get(bounce_return_linesize_limit+2); uschar * buf = store_get(bounce_return_linesize_limit+2);
if (firstline) fprintf(f, "%s", CS firstline); if (firstline) fprintf(fp, "%s", CS firstline);
while (fgets(CS buf, bounce_return_linesize_limit+2, message_file)) while (fgets(CS buf, bounce_return_linesize_limit+2, message_file))
{ {
int len; int len;
if (enddot && *buf == '.' && buf[1] == '\n') if (enddot && *buf == '.' && buf[1] == '\n')
{ {
fputc('.', f); fputc('.', fp);
break; break;
} }
len = Ustrlen(buf); len = Ustrlen(buf);
if (buf[len-1] != '\n') if (buf[len-1] != '\n')
{ /* eat rest of partial line */ { /* eat rest of partial line */
int ch; int ch;
while ((ch = fgetc(message_file)) != EOF && ch != '\n') ; while ((ch = fgetc(message_file)) != EOF && ch != '\n') ;
} }
if (size_limit > 0 && len > size_limit - written) if (size_limit > 0 && len > size_limit - written)
{ {
buf[size_limit - written] = '\0'; buf[size_limit - written] = '\0';
fputs(CS buf, f); fputs(CS buf, fp);
break; break;
} }
fputs(CS buf, f); fputs(CS buf, fp);
} }
} }
#ifdef EXPERIMENTAL_DMARC #ifdef EXPERIMENTAL_DMARC
/* Overkill, but use exact test in case future code gets inserted */ /* Overkill, but use exact test in case future code gets inserted */
else if (bounce_return_body && message_file == NULL) else if (bounce_return_body && message_file == NULL)
{ {
/*XXX limit line length here? */ /*XXX limit line length here? */
/* This doesn't print newlines, disable until can parse and fix /* This doesn't print newlines, disable until can parse and fix
* output to be legible. */ * output to be legible. */
fprintf(f, "%s", expand_string(US"$message_body")); fprintf(fp, "%s", expand_string(US"$message_body"));
} }
#endif #endif
} }
/* Close the file, which should send an EOF to the child process /* Close the file, which should send an EOF to the child process
that is receiving the message. Wait for it to finish, without a timeout. */ that is receiving the message. Wait for it to finish, without a timeout. */
(void)fclose(f); (void)fclose(fp);
status = child_close(pid, 0); /* Waits for child to close */ status = child_close(pid, 0); /* Waits for child to close */
if (status != 0) if (status != 0)
{ {
uschar *msg = US"Child mail process returned status"; uschar *msg = US"Child mail process returned status";
if (status == -257) if (status == -257)
log_write(0, LOG_MAIN, "%s %d: errno=%d: %s", msg, status, errno, log_write(0, LOG_MAIN, "%s %d: errno=%d: %s", msg, status, errno,
strerror(errno)); strerror(errno));
else else
log_write(0, LOG_MAIN, "%s %d", msg, status); log_write(0, LOG_MAIN, "%s %d", msg, status);
return FALSE; return FALSE;
skipping to change at line 378 skipping to change at line 406
FILE *message_file, BOOL check_sender) FILE *message_file, BOOL check_sender)
{ {
uschar *firstline = NULL; uschar *firstline = NULL;
uschar *msg = US"Error while reading message with no usable sender address"; uschar *msg = US"Error while reading message with no usable sender address";
if (message_reference) if (message_reference)
msg = string_sprintf("%s (R=%s)", msg, message_reference); msg = string_sprintf("%s (R=%s)", msg, message_reference);
/* Find the sender from a From line if permitted and possible */ /* Find the sender from a From line if permitted and possible */
if (check_sender && message_file && trusted_caller && if (check_sender && message_file && f.trusted_caller &&
Ufgets(big_buffer, BIG_BUFFER_SIZE, message_file) != NULL) Ufgets(big_buffer, BIG_BUFFER_SIZE, message_file) != NULL)
{ {
uschar *new_sender = NULL; uschar *new_sender = NULL;
if (regex_match_and_setup(regex_From, big_buffer, 0, -1)) if (regex_match_and_setup(regex_From, big_buffer, 0, -1))
new_sender = expand_string(uucp_from_sender); new_sender = expand_string(uucp_from_sender);
if (new_sender) sender_address = new_sender; if (new_sender) sender_address = new_sender;
else firstline = big_buffer; else firstline = big_buffer;
} }
/* If viable sender address, send a message */ /* If viable sender address, send a message */
if (sender_address && sender_address[0] && !local_error_message) if (sender_address && sender_address[0] && !f.local_error_message)
return moan_send_message(sender_address, ident, eblock, headers, return moan_send_message(sender_address, ident, eblock, headers,
message_file, firstline); message_file, firstline);
/* Otherwise, we can only log */ /* Otherwise, we can only log */
switch(ident) switch(ident)
{ {
case ERRMESS_BADARGADDRESS: case ERRMESS_BADARGADDRESS:
case ERRMESS_BADNOADDRESS: case ERRMESS_BADNOADDRESS:
case ERRMESS_BADADDRESS: case ERRMESS_BADADDRESS:
 End of changes. 44 change blocks. 
61 lines changed or deleted 89 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)