Use RM_COMMAND everywhere during building.
[exim.git] / src / src / moan.c
CommitLineData
f1e894f3 1/* $Cambridge: exim/src/src/moan.c,v 1.3 2005/06/27 14:29:43 ph10 Exp $ */
059ec3d9
PH
2
3/*************************************************
4* Exim - an Internet mail transport agent *
5*************************************************/
6
c988f1f4 7/* Copyright (c) University of Cambridge 1995 - 2005 */
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);
64fprintf(f, "Auto_submitted: auto-generated\n");
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
188/* Now copy the message - headers then the rest of the input if
189available, up to the configured limit. */
190
191if (size_limit == 0 || size_limit > thismessage_size_limit)
192 size_limit = thismessage_size_limit;
193
194if (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 }
207else 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
212field will still be NULL; just omit such a header line. */
213
214while (headers != NULL)
215 {
216 if (headers->text != NULL) fprintf(f, "%s", CS headers->text);
217 headers = headers->next;
218 }
219
220if (ident != ERRMESS_VLONGHEADER && ident != ERRMESS_VLONGHDRLINE)
221 fputc('\n', f);
222
223/* After early detection of an error, the message file may be STDIN,
224in which case we might have to terminate on a line containing just "."
225as well as on EOF. We may already have the first line in memory. */
226
227if (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
249that is receiving the message. Wait for it to finish, without a timeout. */
250
f1e894f3 251(void)fclose(f);
059ec3d9
PH
252status = child_close(pid, 0); /* Waits for child to close */
253if (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
264return 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
274message. Delivery failures are handled separately in deliver.c.
275
276If there is a valid sender_address, and the failing message is not a local
277error message, then this function calls moan_send_message to send a message to
278that person. If the sender's address is null, then an error has occurred with a
279message that was generated by a mailer daemon. All we can do is to write
280information to log files. The same action is taken if local_error_message is
281set - this can happen for non null-senders in certain configurations where exim
282doesn't run setuid root.
283
284Arguments:
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
292Returns: FALSE if there is no sender_address to send to;
293 else the return from moan_send_message()
294*/
295
296BOOL
297moan_to_sender(int ident, error_block *eblock, header_line *headers,
298 FILE *message_file, BOOL check_sender)
299{
300uschar *firstline = NULL;
301uschar *msg = US"Error while reading message with no usable sender address";
302
303if (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
308if (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
320if (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
326switch(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
378return 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
388mailmaster) about some incident.
389
390Arguments:
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
397Returns: nothing
398*/
399
400void
401moan_tell_someone(uschar *who, address_item *addr, uschar *subject,
402 char *format, ...)
403{
404FILE *f;
405va_list ap;
406int fd;
407int pid = child_open_exim(&fd);
408
409if (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
416f = fdopen(fd, "wb");
417fprintf(f, "Auto_submitted: auto-generated\n");
418fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
419 qualify_domain_sender);
420fprintf(f, "To: %s\n", who);
421fprintf(f, "Subject: %s\n\n", subject);
422va_start(ap, format);
423vfprintf(f, format, ap);
424va_end(ap);
425
426if (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
f1e894f3 440(void)fclose(f);
059ec3d9
PH
441child_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.
451Information is written to stdout and/or stderr, and Exim exits with a non-zero
452completion code. BSMTP is almost always called by some other program, so it is
453up to that program to interpret the return code and do something with the error
454information, and also to preserve the batch input file for human analysis.
455
456Formerly, Exim used to attempt to continue after some errors, but this strategy
457has been abandoned as it can lead to loss of messages.
458
459Arguments:
460 cmd_buffer the command causing the error, or NULL
461 format a printf() format
462 ... arguments for the format
463
464Returns: 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
469void
470moan_smtp_batch(uschar *cmd_buffer, char *format, ...)
471{
472va_list ap;
473int yield = (receive_messagecount > 0)? 1 : 2;
474
475DEBUG(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
479va_start(ap, format);
480vfprintf(stdout, format, ap);
481va_end(ap);
482
483fprintf(stdout, "\nTransaction started in line %d\n",
484 bsmtp_transaction_linecount);
485fprintf(stdout, "Error detected in line %d\n", receive_linecount);
486if (cmd_buffer != NULL) fprintf(stdout, "%s\n", cmd_buffer);
487
488/* On stderr, write stuff for human consumption */
489
490fprintf(stderr,
491 "An error was detected while processing a file of BSMTP input.\n"
492 "The error message was:\n\n ");
493
494va_start(ap, format);
495vfprintf(stderr, format, ap);
496va_end(ap);
497
498fprintf(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
503if (cmd_buffer != NULL)
504 {
505 fprintf(stderr, "The SMTP command at fault was:\n\n %s\n\n",
506 cmd_buffer);
507 }
508
509fprintf(stderr, "%d previous message%s successfully processed.\n",
510 receive_messagecount, (receive_messagecount == 1)? " was" : "s were");
511
512fprintf(stderr, "The rest of the batch was abandoned.\n");
513
514exim_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
525the error_copies string to see whether there is an additional recipient list to
526which errors for this recipient must be bcc'd. The incoming recipient is always
527fully qualified.
528
529Argument: recipient address
530Returns: additional recipient list or NULL
531*/
532
533uschar *
534moan_check_errorcopy(uschar *recipient)
535{
536uschar *item, *localpart, *domain;
537uschar *listptr = errors_copy;
538uschar *yield = NULL;
539uschar buffer[256];
540int sep = 0;
541int llen;
542
543if (errors_copy == NULL) return NULL;
544
545/* Set up pointer to the local part and domain, and compute the
546length of the local part. */
547
548localpart = recipient;
549domain = Ustrchr(recipient, '@');
550if (domain == NULL) return NULL; /* should not occur, but avoid crash */
551llen = domain++ - recipient;
552
553/* Scan through the configured items */
554
555while ((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
589DEBUG(D_any) debug_printf("errors_copy check returned %s\n",
590 (yield == NULL)? US"NULL" : yield);
591
592expand_nmax = -1;
593return 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
603or more syntax errors in the list of addresses. If there is an address to mail
604to, send a message, and always write the information to the log. In the case of
605a filter file, a "syntax error" might actually be something else, such as the
606inability to open a log file. Thus, the wording of the error message is
607general.
608
609Arguments:
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
616Returns: FALSE if string expansion failed; TRUE otherwise
617*/
618
619BOOL
620moan_skipped_syntax_errors(uschar *rname, error_block *eblock,
621 uschar *syntax_errors_to, BOOL some, uschar *custom)
622{
623int pid, fd;
624uschar *s, *t;
625FILE *f;
626error_block *e;
627
628for (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
638if (syntax_errors_to == NULL) return TRUE;
639
640s = expand_string(syntax_errors_to);
641if (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
649it. */
650
651pid = child_open_exim(&fd);
652
653if (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
660f = fdopen(fd, "wb");
661fprintf(f, "Auto_submitted: auto-generated\n");
662fprintf(f, "From: Mail Delivery System <Mailer-Daemon@%s>\n",
663 qualify_domain_sender);
664fprintf(f, "To: %s\n", s);
665fprintf(f, "Subject: error(s) in forwarding or filtering\n\n");
666
667if (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
679fprintf(f, "The %s router encountered the following error(s):\n\n",
680 rname);
681
682for (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
690if (some)
691 fprintf(f, "Other addresses were processed normally.\n");
692else
693 fprintf(f, "No valid addresses were generated.\n");
694
f1e894f3 695(void)fclose(f);
059ec3d9
PH
696child_close(pid, 0); /* Waits for child to close; no timeout */
697
698return TRUE;
699}
700
701/* End of moan.c */