Add forany/forall (Marcus Holmgren's patch, basically).
[exim.git] / src / src / moan.c
CommitLineData
184e8823 1/* $Cambridge: exim/src/src/moan.c,v 1.7 2007/01/08 10:50:18 ph10 Exp $ */
059ec3d9
PH
2
3/*************************************************
4* Exim - an Internet mail transport agent *
5*************************************************/
6
184e8823 7/* Copyright (c) University of Cambridge 1995 - 2007 */
059ec3d9
PH
8/* See the file NOTICE for conditions of use and distribution. */
9
10/* Functions for sending messages to sender or to mailmaster. */
11
12
13#include "exim.h"
14
15
16
17/*************************************************
18* Send error message *
19*************************************************/
20
21/* This function sends an error message by opening a pipe to a new process
22running Exim, and writing a message to it using the "-t" option. This is not
23used for delivery failures, which have their own code for handing failed
24addresses.
25
26Arguments:
27 recipient addressee for the message
28 ident identifies the type of error
29 eblock chain of error_blocks containing data about the error
30 headers the message's headers
31 message_file FILE containing the body of the message
32 firstline contains first line of file, if it was read to check for
33 "From ", but it turned out not to be
34
35Returns: TRUE if message successfully sent
36*/
37
38static BOOL
39moan_send_message(uschar *recipient, int ident, error_block *eblock,
40 header_line *headers, FILE *message_file, uschar *firstline)
41{
42int written = 0;
43int fd;
44int status;
45int count = 0;
46int size_limit = bounce_return_size_limit;
47FILE *f;
48int pid = child_open_exim(&fd);
49
50/* Creation of child failed */
51
52if (pid < 0)
53 {
54 DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n",
55 strerror(errno));
56 return FALSE;
57 }
58else DEBUG(D_any) debug_printf("Child process %d for sending message\n", pid);
59
60/* Creation of child succeeded */
61
62f = fdopen(fd, "wb");
63if (errors_reply_to != NULL) fprintf(f, "Reply-To: %s\n", errors_reply_to);
456682f5 64fprintf(f, "Auto-Submitted: auto-replied\n");
059ec3d9
PH
65fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
66 qualify_domain_sender);
67fprintf(f, "To: %s\n", recipient);
68
69switch(ident)
70 {
71 case ERRMESS_BADARGADDRESS:
72 fprintf(f,
73 "Subject: Mail failure - malformed recipient address\n\n");
74 fprintf(f,
75 "A message that you sent contained a recipient address that was incorrectly\n"
76 "constructed:\n\n");
77 fprintf(f, " %s %s\n", eblock->text1, eblock->text2);
78 count = Ustrlen(eblock->text1);
79 if (count > 0 && eblock->text1[count-1] == '.')
80 fprintf(f,
81 "\nRecipient addresses must not end with a '.' character.\n");
82 fprintf(f,
83 "\nThe message has not been delivered to any recipients.\n");
84 break;
85
86 case ERRMESS_BADNOADDRESS:
87 case ERRMESS_BADADDRESS:
88 fprintf(f,
89 "Subject: Mail failure - malformed recipient address\n\n");
90 fprintf(f,
91 "A message that you sent contained one or more recipient addresses that were\n"
92 "incorrectly constructed:\n\n");
93
94 while (eblock != NULL)
95 {
96 fprintf(f, " %s: %s\n", eblock->text1, eblock->text2);
97 count++;
98 eblock = eblock->next;
99 }
100
101 fprintf(f, (count == 1)? "\nThis address has been ignored. " :
102 "\nThese addresses have been ignored. ");
103
104 fprintf(f, (ident == ERRMESS_BADADDRESS)?
105 "The other addresses in the message were\n"
106 "syntactically valid and have been passed on for an attempt at delivery.\n" :
107
108 "There were no other addresses in your\n"
109 "message, and so no attempt at delivery was possible.\n");
110 break;
111
112 case ERRMESS_IGADDRESS:
113 fprintf(f, "Subject: Mail failure - no recipient addresses\n\n");
114 fprintf(f,
115 "A message that you sent using the -t command line option contained no\n"
116 "addresses that were not also on the command line, and were therefore\n"
117 "suppressed. This left no recipient addresses, and so no delivery could\n"
118 "be attempted.\n");
119 break;
120
121 case ERRMESS_NOADDRESS:
122 fprintf(f, "Subject: Mail failure - no recipient addresses\n\n");
123 fprintf(f,
124 "A message that you sent contained no recipient addresses, and therefore no\n"
125 "delivery could be attempted.\n");
126 break;
127
128 case ERRMESS_IOERR:
129 fprintf(f, "Subject: Mail failure - system failure\n\n");
130 fprintf(f,
131 "A system failure was encountered while processing a message that you sent,\n"
132 "so it has not been possible to deliver it. The error was:\n\n%s\n",
133 eblock->text1);
134 break;
135
136 case ERRMESS_VLONGHEADER:
137 fprintf(f, "Subject: Mail failure - overlong header section\n\n");
138 fprintf(f,
139 "A message that you sent contained a header section that was excessively\n"
140 "long and could not be handled by the mail transmission software. The\n"
141 "message has not been delivered to any recipients.\n");
142 break;
143
144 case ERRMESS_VLONGHDRLINE:
145 fprintf(f, "Subject: Mail failure - overlong header line\n\n");
146 fprintf(f,
147 "A message that you sent contained a header line that was excessively\n"
148 "long and could not be handled by the mail transmission software. The\n"
149 "message has not been delivered to any recipients.\n");
150 break;
151
152 case ERRMESS_TOOBIG:
153 fprintf(f, "Subject: Mail failure - message too big\n\n");
154 fprintf(f,
155 "A message that you sent was longer than the maximum size allowed on this\n"
156 "system. It was not delivered to any recipients.\n");
157 break;
158
159 case ERRMESS_TOOMANYRECIP:
160 fprintf(f, "Subject: Mail failure - too many recipients\n\n");
161 fprintf(f,
162 "A message that you sent contained more recipients than allowed on this\n"
163 "system. It was not delivered to any recipients.\n");
164 break;
165
166 case ERRMESS_LOCAL_SCAN:
167 case ERRMESS_LOCAL_ACL:
168 fprintf(f, "Subject: Mail failure - rejected by local scanning code\n\n");
169 fprintf(f,
170 "A message that you sent was rejected by the local scanning code that\n"
171 "checks incoming messages on this system.");
172 if (eblock->text1 != NULL)
173 {
174 fprintf(f,
175 " The following error was given:\n\n %s", eblock->text1);
176 }
177 fprintf(f, "\n");
178 break;
179
180 default:
181 fprintf(f, "Subject: Mail failure\n\n");
182 fprintf(f,
183 "A message that you sent has caused the error routine to be entered with\n"
184 "an unknown error number (%d).\n", ident);
185 break;
186 }
187
715ab376
PH
188/* Now, if configured, copy the message; first the headers and then the rest of
189the input if available, up to the configured limit, if the option for including
190message bodies in bounces is set. */
059ec3d9 191
715ab376 192if (bounce_return_message)
059ec3d9 193 {
715ab376
PH
194 if (bounce_return_body)
195 {
196 fprintf(f, "\n"
197 "------ This is a copy of your message, including all the headers.");
198 if (size_limit == 0 || size_limit > thismessage_size_limit)
199 size_limit = thismessage_size_limit;
200 if (size_limit > 0 && size_limit < message_size)
201 {
202 int x = size_limit;
203 uschar *k = US"";
204 if ((x & 1023) == 0)
205 {
206 k = US"K";
207 x >>= 10;
208 }
209 fprintf(f, "\n"
210 "------ No more than %d%s characters of the body are included.\n\n",
211 x, k);
212 }
213 else fprintf(f, " ------\n\n");
214 }
215 else
059ec3d9 216 {
715ab376
PH
217 fprintf(f, "\n"
218 "------ This is a copy of the headers that were received before the "
219 "error\n was detected.\n\n");
059ec3d9 220 }
059ec3d9 221
715ab376
PH
222 /* If the error occurred before the Received: header was created, its text
223 field will still be NULL; just omit such a header line. */
059ec3d9 224
715ab376
PH
225 while (headers != NULL)
226 {
227 if (headers->text != NULL) fprintf(f, "%s", CS headers->text);
228 headers = headers->next;
229 }
059ec3d9 230
715ab376
PH
231 if (ident != ERRMESS_VLONGHEADER && ident != ERRMESS_VLONGHDRLINE)
232 fputc('\n', f);
059ec3d9 233
715ab376
PH
234 /* After early detection of an error, the message file may be STDIN,
235 in which case we might have to terminate on a line containing just "."
236 as well as on EOF. We may already have the first line in memory. */
059ec3d9 237
715ab376 238 if (bounce_return_body && message_file != NULL)
059ec3d9 239 {
715ab376
PH
240 int ch;
241 int state = 1;
242 BOOL enddot = dot_ends && message_file == stdin;
243 if (firstline != NULL) fprintf(f, "%s", CS firstline);
244 while ((ch = fgetc(message_file)) != EOF)
059ec3d9 245 {
715ab376
PH
246 fputc(ch, f);
247 if (size_limit > 0 && ++written > size_limit) break;
248 if (enddot)
249 {
250 if (state == 0) { if (ch == '\n') state = 1; }
251 else if (state == 1)
252 { if (ch == '.') state = 2; else if (ch != '\n') state = 0; }
253 else
254 { if (ch == '\n') break; else state = 0; }
255 }
059ec3d9
PH
256 }
257 }
258 }
259
260/* Close the file, which should send an EOF to the child process
261that is receiving the message. Wait for it to finish, without a timeout. */
262
f1e894f3 263(void)fclose(f);
059ec3d9
PH
264status = child_close(pid, 0); /* Waits for child to close */
265if (status != 0)
266 {
267 uschar *msg = US"Child mail process returned status";
268 if (status == -257)
269 log_write(0, LOG_MAIN, "%s %d: errno=%d: %s", msg, status, errno,
270 strerror(errno));
271 else
272 log_write(0, LOG_MAIN, "%s %d", msg, status);
273 return FALSE;
274 }
275
276return TRUE;
277}
278
279
280
281/*************************************************
282* Send message to sender *
283*************************************************/
284
285/* This function is called when errors are detected during the receipt of a
286message. Delivery failures are handled separately in deliver.c.
287
288If there is a valid sender_address, and the failing message is not a local
289error message, then this function calls moan_send_message to send a message to
290that person. If the sender's address is null, then an error has occurred with a
291message that was generated by a mailer daemon. All we can do is to write
292information to log files. The same action is taken if local_error_message is
293set - this can happen for non null-senders in certain configurations where exim
294doesn't run setuid root.
295
296Arguments:
297 ident identifies the particular error
298 eblock chain of error_blocks containing data about the error
299 headers message's headers (chain)
300 message_file a FILE where the body of the message can be read
301 check_sender if TRUE, read the first line of the file for a possible
302 "From " sender (if a trusted caller)
303
304Returns: FALSE if there is no sender_address to send to;
305 else the return from moan_send_message()
306*/
307
308BOOL
309moan_to_sender(int ident, error_block *eblock, header_line *headers,
310 FILE *message_file, BOOL check_sender)
311{
312uschar *firstline = NULL;
313uschar *msg = US"Error while reading message with no usable sender address";
314
315if (message_reference != NULL)
316 msg = string_sprintf("%s (R=%s)", msg, message_reference);
317
318/* Find the sender from a From line if permitted and possible */
319
320if (check_sender && message_file != NULL && trusted_caller &&
321 Ufgets(big_buffer, BIG_BUFFER_SIZE, message_file) != NULL)
322 {
323 uschar *new_sender = NULL;
324 if (regex_match_and_setup(regex_From, big_buffer, 0, -1))
325 new_sender = expand_string(uucp_from_sender);
326 if (new_sender != NULL) sender_address = new_sender;
327 else firstline = big_buffer;
328 }
329
330/* If viable sender address, send a message */
331
332if (sender_address != NULL && sender_address[0] != 0 && !local_error_message)
333 return moan_send_message(sender_address, ident, eblock, headers,
334 message_file, firstline);
335
336/* Otherwise, we can only log */
337
338switch(ident)
339 {
340 case ERRMESS_BADARGADDRESS:
341 case ERRMESS_BADNOADDRESS:
342 case ERRMESS_BADADDRESS:
343 log_write(0, LOG_MAIN, "%s: at least one malformed recipient address: "
344 "%s - %s", msg, eblock->text1, eblock->text2);
345 break;
346
347 case ERRMESS_IGADDRESS:
348 case ERRMESS_NOADDRESS:
349 log_write(0, LOG_MAIN, "%s: no recipient addresses", msg);
350 break;
351
352 /* This error has already been logged. */
353 case ERRMESS_IOERR:
354 break;
355
356 case ERRMESS_VLONGHEADER:
357 log_write(0, LOG_MAIN, "%s: excessively long message header section read "
358 "(more than %d characters)", msg, header_maxsize);
359 break;
360
361 case ERRMESS_VLONGHDRLINE:
362 log_write(0, LOG_MAIN, "%s: excessively long message header line read "
363 "(more than %d characters)", msg, header_line_maxsize);
364 break;
365
366 case ERRMESS_TOOBIG:
367 log_write(0, LOG_MAIN, "%s: message too big (limit set to %d)", msg,
368 thismessage_size_limit);
369 break;
370
371 case ERRMESS_TOOMANYRECIP:
372 log_write(0, LOG_MAIN, "%s: too many recipients (max set to %d)", msg,
373 recipients_max);
374 break;
375
376 case ERRMESS_LOCAL_SCAN:
377 log_write(0, LOG_MAIN, "%s: rejected by local_scan: %s", msg, eblock->text1);
378 break;
379
380 case ERRMESS_LOCAL_ACL:
381 log_write(0, LOG_MAIN, "%s: rejected by non-SMTP ACL: %s", msg, eblock->text1);
382 break;
383
384 default:
385 log_write(0, LOG_MAIN|LOG_PANIC, "%s: unknown error number %d", msg,
386 ident);
387 break;
388 }
389
390return FALSE;
391}
392
393
394
395/*************************************************
396* Send message to someone *
397*************************************************/
398
399/* This is called when exim is configured to tell someone (often the
400mailmaster) about some incident.
401
402Arguments:
403 who address to send mail to
404 addr chain of deferred addresses whose details are to be included
405 subject subject text for the message
406 format a printf() format for the body of the message
407 ... arguments for the format
408
409Returns: nothing
410*/
411
412void
413moan_tell_someone(uschar *who, address_item *addr, uschar *subject,
414 char *format, ...)
415{
416FILE *f;
417va_list ap;
418int fd;
419int pid = child_open_exim(&fd);
420
421if (pid < 0)
422 {
423 DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n",
424 strerror(errno));
425 return;
426 }
427
428f = fdopen(fd, "wb");
456682f5 429fprintf(f, "Auto-Submitted: auto-replied\n");
059ec3d9
PH
430fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
431 qualify_domain_sender);
432fprintf(f, "To: %s\n", who);
433fprintf(f, "Subject: %s\n\n", subject);
434va_start(ap, format);
435vfprintf(f, format, ap);
436va_end(ap);
437
438if (addr != NULL)
439 {
440 fprintf(f, "\nThe following address(es) have yet to be delivered:\n");
441 for (; addr != NULL; addr = addr->next)
442 {
443 uschar *parent = (addr->parent == NULL)? NULL : addr->parent->address;
444 fprintf(f, " %s", addr->address);
445 if (parent != NULL) fprintf(f, " <%s>", parent);
446 if (addr->basic_errno > 0) fprintf(f, ": %s", strerror(addr->basic_errno));
447 if (addr->message != NULL) fprintf(f, ": %s", addr->message);
448 fprintf(f, "\n");
449 }
450 }
451
f1e894f3 452(void)fclose(f);
059ec3d9
PH
453child_close(pid, 0); /* Waits for child to close; no timeout */
454}
455
456
457
458/*************************************************
459* Handle SMTP batch error *
460*************************************************/
461
462/* This is called when something goes wrong in batched (-bS) SMTP input.
463Information is written to stdout and/or stderr, and Exim exits with a non-zero
464completion code. BSMTP is almost always called by some other program, so it is
465up to that program to interpret the return code and do something with the error
466information, and also to preserve the batch input file for human analysis.
467
468Formerly, Exim used to attempt to continue after some errors, but this strategy
469has been abandoned as it can lead to loss of messages.
470
471Arguments:
472 cmd_buffer the command causing the error, or NULL
473 format a printf() format
474 ... arguments for the format
475
476Returns: does not return; exits from the program
477 exit code = 1 if some messages were accepted
478 exit code = 2 if no messages were accepted
479*/
480
481void
482moan_smtp_batch(uschar *cmd_buffer, char *format, ...)
483{
484va_list ap;
485int yield = (receive_messagecount > 0)? 1 : 2;
486
487DEBUG(D_any) debug_printf("Handling error in batched SMTP input\n");
488
489/* On stdout, write stuff that a program could parse fairly easily. */
490
491va_start(ap, format);
492vfprintf(stdout, format, ap);
493va_end(ap);
494
495fprintf(stdout, "\nTransaction started in line %d\n",
496 bsmtp_transaction_linecount);
497fprintf(stdout, "Error detected in line %d\n", receive_linecount);
498if (cmd_buffer != NULL) fprintf(stdout, "%s\n", cmd_buffer);
499
500/* On stderr, write stuff for human consumption */
501
502fprintf(stderr,
503 "An error was detected while processing a file of BSMTP input.\n"
504 "The error message was:\n\n ");
505
506va_start(ap, format);
507vfprintf(stderr, format, ap);
508va_end(ap);
509
510fprintf(stderr,
511 "\n\nThe SMTP transaction started in line %d.\n"
512 "The error was detected in line %d.\n",
513 bsmtp_transaction_linecount, receive_linecount);
514
515if (cmd_buffer != NULL)
516 {
517 fprintf(stderr, "The SMTP command at fault was:\n\n %s\n\n",
518 cmd_buffer);
519 }
520
521fprintf(stderr, "%d previous message%s successfully processed.\n",
522 receive_messagecount, (receive_messagecount == 1)? " was" : "s were");
523
524fprintf(stderr, "The rest of the batch was abandoned.\n");
525
526exim_exit(yield);
527}
528
529
530
531
532/*************************************************
533* Check for error copies *
534*************************************************/
535
536/* This function is passed the recipient of an error message, and must check
537the error_copies string to see whether there is an additional recipient list to
538which errors for this recipient must be bcc'd. The incoming recipient is always
539fully qualified.
540
541Argument: recipient address
542Returns: additional recipient list or NULL
543*/
544
545uschar *
546moan_check_errorcopy(uschar *recipient)
547{
548uschar *item, *localpart, *domain;
549uschar *listptr = errors_copy;
550uschar *yield = NULL;
551uschar buffer[256];
552int sep = 0;
553int llen;
554
555if (errors_copy == NULL) return NULL;
556
557/* Set up pointer to the local part and domain, and compute the
558length of the local part. */
559
560localpart = recipient;
561domain = Ustrchr(recipient, '@');
562if (domain == NULL) return NULL; /* should not occur, but avoid crash */
563llen = domain++ - recipient;
564
565/* Scan through the configured items */
566
567while ((item = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer)))
568 != NULL)
569 {
570 uschar *newaddress = item;
571 uschar *pattern = string_dequote(&newaddress);
572
573 /* If no new address found, just skip this item. */
574
575 while (isspace(*newaddress)) newaddress++;
576 if (*newaddress == 0) continue;
577
578 /* We now have an item to match as an address in item, and the additional
579 address in newaddress. If the pattern matches, expand the new address string
580 and return it. During expansion, make local part and domain available for
581 insertion. This requires a copy to be made; we can't just temporarily
582 terminate it, as the whole address is required for $0. */
583
584 if (match_address_list(recipient, TRUE, TRUE, &pattern, NULL, 0, UCHAR_MAX+1,
585 NULL) == OK)
586 {
587 uschar temp[256];
588 Ustrncpy(temp, localpart, llen);
589 temp[llen] = 0;
590 deliver_localpart = temp;
591 deliver_domain = domain;
592 yield = expand_string_copy(newaddress);
593 deliver_domain = deliver_localpart = NULL;
594 if (yield == NULL)
595 log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand %s when processing "
596 "errors_copy: %s", newaddress, expand_string_message);
597 break;
598 }
599 }
600
601DEBUG(D_any) debug_printf("errors_copy check returned %s\n",
602 (yield == NULL)? US"NULL" : yield);
603
604expand_nmax = -1;
605return yield;
606}
607
608
609
610/************************************************
611* Handle skipped syntax errors *
612************************************************/
613
614/* This function is called by the redirect router when it has skipped over one
615or more syntax errors in the list of addresses. If there is an address to mail
616to, send a message, and always write the information to the log. In the case of
617a filter file, a "syntax error" might actually be something else, such as the
618inability to open a log file. Thus, the wording of the error message is
619general.
620
621Arguments:
622 rname the router name
623 eblock chain of error blocks
624 syntax_errors_to address to send mail to, or NULL
625 some TRUE if some addresses were generated; FALSE if none were
626 custom custom message text
627
628Returns: FALSE if string expansion failed; TRUE otherwise
629*/
630
631BOOL
632moan_skipped_syntax_errors(uschar *rname, error_block *eblock,
633 uschar *syntax_errors_to, BOOL some, uschar *custom)
634{
635int pid, fd;
636uschar *s, *t;
637FILE *f;
638error_block *e;
639
640for (e = eblock; e != NULL; e = e->next)
641 {
642 if (e->text2 != NULL)
643 log_write(0, LOG_MAIN, "%s router: skipped error: %s in \"%s\"",
644 rname, e->text1, e->text2);
645 else
646 log_write(0, LOG_MAIN, "%s router: skipped error: %s", rname,
647 e->text1);
648 }
649
650if (syntax_errors_to == NULL) return TRUE;
651
652s = expand_string(syntax_errors_to);
653if (s == NULL)
654 {
655 log_write(0, LOG_MAIN, "%s router failed to expand %s: %s", rname,
656 syntax_errors_to, expand_string_message);
657 return FALSE;
658 }
659
660/* If we can't create a process to send the message, just forget about
661it. */
662
663pid = child_open_exim(&fd);
664
665if (pid < 0)
666 {
667 DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n",
668 strerror(errno));
669 return TRUE;
670 }
671
672f = fdopen(fd, "wb");
456682f5 673fprintf(f, "Auto-Submitted: auto-replied\n");
059ec3d9
PH
674fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
675 qualify_domain_sender);
676fprintf(f, "To: %s\n", s);
677fprintf(f, "Subject: error(s) in forwarding or filtering\n\n");
678
679if (custom != NULL)
680 {
681 t = expand_string(custom);
682 if (t == NULL)
683 {
684 log_write(0, LOG_MAIN, "%s router failed to expand %s: %s", rname,
685 custom, expand_string_message);
686 return FALSE;
687 }
688 fprintf(f, "%s\n\n", t);
689 }
690
691fprintf(f, "The %s router encountered the following error(s):\n\n",
692 rname);
693
694for (e = eblock; e != NULL; e = e->next)
695 {
696 fprintf(f, " %s", e->text1);
697 if (e->text2 != NULL)
698 fprintf(f, " in the address\n \"%s\"", e->text2);
699 fprintf(f, "\n\n");
700 }
701
702if (some)
703 fprintf(f, "Other addresses were processed normally.\n");
704else
705 fprintf(f, "No valid addresses were generated.\n");
706
f1e894f3 707(void)fclose(f);
059ec3d9
PH
708child_close(pid, 0); /* Waits for child to close; no timeout */
709
710return TRUE;
711}
712
713/* End of moan.c */