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