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