NDBM: check for bogus name given to create call
[exim.git] / src / src / transports / autoreply.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2018 */
6 /* Copyright (c) The Exim Maintainers 2020 - 2021 */
7 /* See the file NOTICE for conditions of use and distribution. */
8
9
10 #include "../exim.h"
11 #include "autoreply.h"
12
13
14
15 /* Options specific to the autoreply transport. They must be in alphabetic
16 order (note that "_" comes before the lower case letters). Those starting
17 with "*" are not settable by the user but are used by the option-reading
18 software for alternative value types. Some options are publicly visible and so
19 are stored in the driver instance block. These are flagged with opt_public. */
20 #define LOFF(field) OPT_OFF(autoreply_transport_options_block, field)
21
22 optionlist autoreply_transport_options[] = {
23   { "bcc",               opt_stringptr, LOFF(bcc) },
24   { "cc",                opt_stringptr, LOFF(cc) },
25   { "file",              opt_stringptr, LOFF(file) },
26   { "file_expand",     opt_bool,        LOFF(file_expand) },
27   { "file_optional",     opt_bool,      LOFF(file_optional) },
28   { "from",              opt_stringptr, LOFF(from) },
29   { "headers",           opt_stringptr, LOFF(headers) },
30   { "log",               opt_stringptr, LOFF(logfile) },
31   { "mode",              opt_octint,    LOFF(mode) },
32   { "never_mail",        opt_stringptr, LOFF(never_mail) },
33   { "once",              opt_stringptr, LOFF(oncelog) },
34   { "once_file_size",    opt_int,       LOFF(once_file_size) },
35   { "once_repeat",       opt_stringptr, LOFF(once_repeat) },
36   { "reply_to",          opt_stringptr, LOFF(reply_to) },
37   { "return_message",    opt_bool,      LOFF(return_message) },
38   { "subject",           opt_stringptr, LOFF(subject) },
39   { "text",              opt_stringptr, LOFF(text) },
40   { "to",                opt_stringptr, LOFF(to) },
41 };
42
43 /* Size of the options list. An extern variable has to be used so that its
44 address can appear in the tables drtables.c. */
45
46 int autoreply_transport_options_count =
47   sizeof(autoreply_transport_options)/sizeof(optionlist);
48
49
50 #ifdef MACRO_PREDEF
51
52 /* Dummy values */
53 autoreply_transport_options_block autoreply_transport_option_defaults = {0};
54 void autoreply_transport_init(transport_instance *tblock) {}
55 BOOL autoreply_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
56
57 #else   /*!MACRO_PREDEF*/
58
59
60 /* Default private options block for the autoreply transport.
61 All non-mentioned lements zero/null/false. */
62
63 autoreply_transport_options_block autoreply_transport_option_defaults = {
64   .mode = 0600,
65 };
66
67
68
69 /* Type of text for the checkexpand() function */
70
71 enum { cke_text, cke_hdr, cke_file };
72
73
74
75 /*************************************************
76 *          Initialization entry point            *
77 *************************************************/
78
79 /* Called for each instance, after its options have been read, to
80 enable consistency checks to be done, or anything else that needs
81 to be set up. */
82
83 void
84 autoreply_transport_init(transport_instance *tblock)
85 {
86 /*
87 autoreply_transport_options_block *ob =
88   (autoreply_transport_options_block *)(tblock->options_block);
89 */
90
91 /* If a fixed uid field is set, then a gid field must also be set. */
92
93 if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL)
94   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
95     "user set without group for the %s transport", tblock->name);
96 }
97
98
99
100
101 /*************************************************
102 *          Expand string and check               *
103 *************************************************/
104
105 /* If the expansion fails, the error is set up in the address. Expanded
106 strings must be checked to ensure they contain only printing characters
107 and white space. If not, the function fails.
108
109 Arguments:
110    s         string to expand
111    addr      address that is being worked on
112    name      transport name, for error text
113    type      type, for checking content:
114                cke_text => no check
115                cke_hdr  => header, allow \n + whitespace
116                cke_file => file name, no non-printers allowed
117
118 Returns:     expanded string if expansion succeeds;
119              NULL otherwise
120 */
121
122 static uschar *
123 checkexpand(uschar *s, address_item *addr, uschar *name, int type)
124 {
125 uschar *ss = expand_string(s);
126
127 if (!ss)
128   {
129   addr->transport_return = FAIL;
130   addr->message = string_sprintf("Expansion of \"%s\" failed in %s transport: "
131     "%s", s, name, expand_string_message);
132   return NULL;
133   }
134
135 if (type != cke_text) for (uschar * t = ss; *t != 0; t++)
136   {
137   int c = *t;
138   const uschar * sp;
139   if (mac_isprint(c)) continue;
140   if (type == cke_hdr && c == '\n' && (t[1] == ' ' || t[1] == '\t')) continue;
141   sp = string_printing(s);
142   addr->transport_return = FAIL;
143   addr->message = string_sprintf("Expansion of \"%s\" in %s transport "
144     "contains non-printing character %d", sp, name, c);
145   return NULL;
146   }
147
148 return ss;
149 }
150
151
152
153
154 /*************************************************
155 *          Check a header line for never_mail    *
156 *************************************************/
157
158 /* This is called to check to, cc, and bcc for addresses in the never_mail
159 list. Any that are found are removed.
160
161 Arguments:
162   list        list of addresses to be checked
163   never_mail  an address list, already expanded
164
165 Returns:      edited replacement address list, or NULL, or original
166 */
167
168 static uschar *
169 check_never_mail(uschar * list, const uschar * never_mail)
170 {
171 rmark reset_point = store_mark();
172 uschar * newlist = string_copy(list);
173 uschar * s = newlist;
174 BOOL hit = FALSE;
175
176 while (*s)
177   {
178   uschar *error, *next;
179   uschar *e = parse_find_address_end(s, FALSE);
180   int terminator = *e;
181   int start, end, domain, rc;
182
183   /* Temporarily terminate the string at the address end while extracting
184   the operative address within. */
185
186   *e = 0;
187   next = parse_extract_address(s, &error, &start, &end, &domain, FALSE);
188   *e = terminator;
189
190   /* If there is some kind of syntax error, just give up on this header
191   line. */
192
193   if (!next) break;
194
195   /* See if the address is on the never_mail list */
196
197   rc = match_address_list(next,         /* address to check */
198                           TRUE,         /* start caseless */
199                           FALSE,        /* don't expand the list */
200                           &never_mail,  /* the list */
201                           NULL,         /* no caching */
202                           -1,           /* no expand setup */
203                           0,            /* separator from list */
204                           NULL);        /* no lookup value return */
205
206   if (rc == OK)                         /* Remove this address */
207     {
208     DEBUG(D_transport)
209       debug_printf("discarding recipient %s (matched never_mail)\n", next);
210     hit = TRUE;
211     if (terminator == ',') e++;
212     memmove(s, e, Ustrlen(e) + 1);
213     }
214   else                                  /* Skip over this address */
215     {
216     s = e;
217     if (terminator == ',') s++;
218     }
219   }
220
221 /* If no addresses were removed, retrieve the memory used and return
222 the original. */
223
224 if (!hit)
225   {
226   store_reset(reset_point);
227   return list;
228   }
229
230 /* Check to see if we removed the last address, leaving a terminating comma
231 that needs to be removed */
232
233 s = newlist + Ustrlen(newlist);
234 while (s > newlist && (isspace(s[-1]) || s[-1] == ',')) s--;
235 *s = 0;
236
237 /* Check to see if there any addresses left; if not, return NULL */
238
239 s = newlist;
240 while (s && isspace(*s)) s++;
241 if (*s)
242   return newlist;
243
244 store_reset(reset_point);
245 return NULL;
246 }
247
248
249
250 /*************************************************
251 *              Main entry point                  *
252 *************************************************/
253
254 /* See local README for interface details. This transport always returns
255 FALSE, indicating that the top address has the status for all - though in fact
256 this transport can handle only one address at at time anyway. */
257
258 BOOL
259 autoreply_transport_entry(
260   transport_instance *tblock,      /* data for this instantiation */
261   address_item *addr)              /* address we are working on */
262 {
263 int fd, pid, rc;
264 int cache_fd = -1;
265 int cache_size = 0;
266 int add_size = 0;
267 EXIM_DB *dbm_file = NULL;
268 BOOL file_expand, return_message;
269 uschar *from, *reply_to, *to, *cc, *bcc, *subject, *headers, *text, *file;
270 uschar *logfile, *oncelog;
271 uschar *cache_buff = NULL;
272 uschar *cache_time = NULL;
273 uschar *message_id = NULL;
274 header_line *h;
275 time_t now = time(NULL);
276 time_t once_repeat_sec = 0;
277 FILE *fp;
278 FILE *ff = NULL;
279
280 autoreply_transport_options_block *ob =
281   (autoreply_transport_options_block *)(tblock->options_block);
282
283 DEBUG(D_transport) debug_printf("%s transport entered\n", tblock->name);
284
285 /* Set up for the good case */
286
287 addr->transport_return = OK;
288 addr->basic_errno = 0;
289
290 /* If the address is pointing to a reply block, then take all the data
291 from that block. It has typically been set up by a mail filter processing
292 router. Otherwise, the data must be supplied by this transport, and
293 it has to be expanded here. */
294
295 if (addr->reply)
296   {
297   DEBUG(D_transport) debug_printf("taking data from address\n");
298   from = addr->reply->from;
299   reply_to = addr->reply->reply_to;
300   to = addr->reply->to;
301   cc = addr->reply->cc;
302   bcc = addr->reply->bcc;
303   subject = addr->reply->subject;
304   headers = addr->reply->headers;
305   text = addr->reply->text;
306   file = addr->reply->file;
307   logfile = addr->reply->logfile;
308   oncelog = addr->reply->oncelog;
309   once_repeat_sec = addr->reply->once_repeat;
310   file_expand = addr->reply->file_expand;
311   expand_forbid = addr->reply->expand_forbid;
312   return_message = addr->reply->return_message;
313   }
314 else
315   {
316   uschar *oncerepeat = ob->once_repeat;
317
318   DEBUG(D_transport) debug_printf("taking data from transport\n");
319   from = ob->from;
320   reply_to = ob->reply_to;
321   to = ob->to;
322   cc = ob->cc;
323   bcc = ob->bcc;
324   subject = ob->subject;
325   headers = ob->headers;
326   text = ob->text;
327   file = ob->file;
328   logfile = ob->logfile;
329   oncelog = ob->oncelog;
330   file_expand = ob->file_expand;
331   return_message = ob->return_message;
332
333   if (  from && !(from = checkexpand(from, addr, tblock->name, cke_hdr))
334      || reply_to && !(reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr))
335      || to && !(to = checkexpand(to, addr, tblock->name, cke_hdr))
336      || cc && !(cc = checkexpand(cc, addr, tblock->name, cke_hdr))
337      || bcc && !(bcc = checkexpand(bcc, addr, tblock->name, cke_hdr))
338      || subject && !(subject = checkexpand(subject, addr, tblock->name, cke_hdr))
339      || headers && !(headers = checkexpand(headers, addr, tblock->name, cke_text))
340      || text && !(text = checkexpand(text, addr, tblock->name, cke_text))
341      || file && !(file = checkexpand(file, addr, tblock->name, cke_file))
342      || logfile && !(logfile = checkexpand(logfile, addr, tblock->name, cke_file))
343      || oncelog && !(oncelog = checkexpand(oncelog, addr, tblock->name, cke_file))
344      || oncerepeat && !(oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file))
345      )
346     return FALSE;
347
348   if (oncerepeat)
349     if ((once_repeat_sec = readconf_readtime(oncerepeat, 0, FALSE)) < 0)
350       {
351       addr->transport_return = FAIL;
352       addr->message = string_sprintf("Invalid time value \"%s\" for "
353         "\"once_repeat\" in %s transport", oncerepeat, tblock->name);
354       return FALSE;
355       }
356   }
357
358 /* If the never_mail option is set, we have to scan all the recipients and
359 remove those that match. */
360
361 if (ob->never_mail)
362   {
363   const uschar *never_mail = expand_string(ob->never_mail);
364
365   if (!never_mail)
366     {
367     addr->transport_return = FAIL;
368     addr->message = string_sprintf("Failed to expand \"%s\" for "
369       "\"never_mail\" in %s transport", ob->never_mail, tblock->name);
370     return FALSE;
371     }
372
373   if (to) to = check_never_mail(to, never_mail);
374   if (cc) cc = check_never_mail(cc, never_mail);
375   if (bcc) bcc = check_never_mail(bcc, never_mail);
376
377   if (!to && !cc && !bcc)
378     {
379     DEBUG(D_transport)
380       debug_printf("*** all recipients removed by never_mail\n");
381     return OK;
382     }
383   }
384
385 /* If the -N option is set, can't do any more. */
386
387 if (f.dont_deliver)
388   {
389   DEBUG(D_transport)
390     debug_printf("*** delivery by %s transport bypassed by -N option\n",
391       tblock->name);
392   return FALSE;
393   }
394
395
396 /* If the oncelog field is set, we send want to send only one message to the
397 given recipient(s). This works only on the "To" field. If there is no "To"
398 field, the message is always sent. If the To: field contains more than one
399 recipient, the effect might not be quite as envisaged. If once_file_size is
400 set, instead of a dbm file, we use a regular file containing a circular buffer
401 recipient cache. */
402
403 if (oncelog && *oncelog && to)
404   {
405   uschar *m;
406   time_t then = 0;
407
408   if ((m = is_tainted2(oncelog, 0, "Tainted '%s' (once file for %s transport)"
409       " not permitted", oncelog, tblock->name)))
410     {
411     addr->transport_return = DEFER;
412     addr->basic_errno = EACCES;
413     addr->message = m;
414     goto END_OFF;
415     }
416
417   /* Handle fixed-size cache file. */
418
419   if (ob->once_file_size > 0)
420     {
421     uschar * nextp;
422     struct stat statbuf;
423
424     cache_fd = Uopen(oncelog, O_CREAT|O_RDWR, ob->mode);
425     if (cache_fd < 0 || fstat(cache_fd, &statbuf) != 0)
426       {
427       addr->transport_return = DEFER;
428       addr->basic_errno = errno;
429       addr->message = string_sprintf("Failed to %s \"once\" file %s when "
430         "sending message from %s transport: %s",
431         cache_fd < 0 ? "open" : "stat", oncelog, tblock->name, strerror(errno));
432       goto END_OFF;
433       }
434
435     /* Get store in the temporary pool and read the entire file into it. We get
436     an amount of store that is big enough to add the new entry on the end if we
437     need to do that. */
438
439     cache_size = statbuf.st_size;
440     add_size = sizeof(time_t) + Ustrlen(to) + 1;
441     cache_buff = store_get(cache_size + add_size, is_tainted(oncelog));
442
443     if (read(cache_fd, cache_buff, cache_size) != cache_size)
444       {
445       addr->transport_return = DEFER;
446       addr->basic_errno = errno;
447       addr->message = US"error while reading \"once\" file";
448       goto END_OFF;
449       }
450
451     DEBUG(D_transport) debug_printf("%d bytes read from %s\n", cache_size, oncelog);
452
453     /* Scan the data for this recipient. Each entry in the file starts with
454     a time_t sized time value, followed by the address, followed by a binary
455     zero. If we find a match, put the time into "then", and the place where it
456     was found into "cache_time". Otherwise, "then" is left at zero. */
457
458     for (uschar * p = cache_buff; p < cache_buff + cache_size; p = nextp)
459       {
460       uschar *s = p + sizeof(time_t);
461       nextp = s + Ustrlen(s) + 1;
462       if (Ustrcmp(to, s) == 0)
463         {
464         memcpy(&then, p, sizeof(time_t));
465         cache_time = p;
466         break;
467         }
468       }
469     }
470
471   /* Use a DBM file for the list of previous recipients. */
472
473   else
474     {
475     EXIM_DATUM key_datum, result_datum;
476     uschar * dirname, * s;
477
478     dirname = (s = Ustrrchr(oncelog, '/'))
479       ? string_copyn(oncelog, s - oncelog) : NULL;
480     EXIM_DBOPEN(oncelog, dirname, O_RDWR|O_CREAT, ob->mode, &dbm_file);
481     if (!dbm_file)
482       {
483       addr->transport_return = DEFER;
484       addr->basic_errno = errno;
485       addr->message = string_sprintf("Failed to open %s file %s when sending "
486         "message from %s transport: %s", EXIM_DBTYPE, oncelog, tblock->name,
487         strerror(errno));
488       goto END_OFF;
489       }
490
491     EXIM_DATUM_INIT(key_datum);        /* Some DBM libraries need datums */
492     EXIM_DATUM_INIT(result_datum);     /* to be cleared */
493     EXIM_DATUM_DATA(key_datum) = CS to;
494     EXIM_DATUM_SIZE(key_datum) = Ustrlen(to) + 1;
495
496     if (EXIM_DBGET(dbm_file, key_datum, result_datum))
497       {
498       /* If the datum size is that of a binary time, we are in the new world
499       where messages are sent periodically. Otherwise the file is an old one,
500       where the datum was filled with a tod_log time, which is assumed to be
501       different in size. For that, only one message is ever sent. This change
502       introduced at Exim 3.00. In a couple of years' time the test on the size
503       can be abolished. */
504
505       if (EXIM_DATUM_SIZE(result_datum) == sizeof(time_t))
506         memcpy(&then, EXIM_DATUM_DATA(result_datum), sizeof(time_t));
507       else
508         then = now;
509       }
510     }
511
512   /* Either "then" is set zero, if no message has yet been sent, or it
513   is set to the time of the last sending. */
514
515   if (then != 0 && (once_repeat_sec <= 0 || now - then < once_repeat_sec))
516     {
517     uschar *m;
518     int log_fd;
519     if ((m = is_tainted2(logfile, 0, "Tainted '%s' (logfile for %s transport)"
520         " not permitted", logfile, tblock->name)))
521       {
522       addr->transport_return = DEFER;
523       addr->basic_errno = EACCES;
524       addr->message = m;
525       goto END_OFF;
526       }
527
528     DEBUG(D_transport) debug_printf("message previously sent to %s%s\n", to,
529       (once_repeat_sec > 0)? " and repeat time not reached" : "");
530     log_fd = logfile ? Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode) : -1;
531     if (log_fd >= 0)
532       {
533       uschar *ptr = log_buffer;
534       sprintf(CS ptr, "%s\n  previously sent to %.200s\n", tod_stamp(tod_log), to);
535       while(*ptr) ptr++;
536       if(write(log_fd, log_buffer, ptr - log_buffer) != ptr-log_buffer
537         || close(log_fd))
538         DEBUG(D_transport) debug_printf("Problem writing log file %s for %s "
539           "transport\n", logfile, tblock->name);
540       }
541     goto END_OFF;
542     }
543
544   DEBUG(D_transport) debug_printf("%s %s\n", (then <= 0)?
545     "no previous message sent to" : "repeat time reached for", to);
546   }
547
548 /* We are going to send a message. Ensure any requested file is available. */
549 if (file)
550   {
551   uschar *m;
552   if ((m = is_tainted2(file, 0, "Tainted '%s' (file for %s transport)"
553       " not permitted", file, tblock->name)))
554     {
555     addr->transport_return = DEFER;
556     addr->basic_errno = EACCES;
557     addr->message = m;
558     return FALSE;
559     }
560   if (!(ff = Ufopen(file, "rb")) && !ob->file_optional)
561     {
562     addr->transport_return = DEFER;
563     addr->basic_errno = errno;
564     addr->message = string_sprintf("Failed to open file %s when sending "
565       "message from %s transport: %s", file, tblock->name, strerror(errno));
566     return FALSE;
567     }
568   }
569
570 /* Make a subprocess to send the message */
571
572 if ((pid = child_open_exim(&fd, US"autoreply")) < 0)
573   {
574   /* Creation of child failed; defer this delivery. */
575
576   addr->transport_return = DEFER;
577   addr->basic_errno = errno;
578   addr->message = string_sprintf("Failed to create child process to send "
579     "message from %s transport: %s", tblock->name, strerror(errno));
580   DEBUG(D_transport) debug_printf("%s\n", addr->message);
581   if (dbm_file) EXIM_DBCLOSE(dbm_file);
582   return FALSE;
583   }
584
585 /* Create the message to be sent - recipients are taken from the headers,
586 as the -t option is used. The "headers" stuff *must* be last in case there
587 are newlines in it which might, if placed earlier, screw up other headers. */
588
589 fp = fdopen(fd, "wb");
590
591 if (from) fprintf(fp, "From: %s\n", from);
592 if (reply_to) fprintf(fp, "Reply-To: %s\n", reply_to);
593 if (to) fprintf(fp, "To: %s\n", to);
594 if (cc) fprintf(fp, "Cc: %s\n", cc);
595 if (bcc) fprintf(fp, "Bcc: %s\n", bcc);
596 if (subject) fprintf(fp, "Subject: %s\n", subject);
597
598 /* Generate In-Reply-To from the message_id header; there should
599 always be one, but code defensively. */
600
601 for (h = header_list; h; h = h->next)
602   if (h->type == htype_id) break;
603
604 if (h)
605   {
606   message_id = Ustrchr(h->text, ':') + 1;
607   while (isspace(*message_id)) message_id++;
608   fprintf(fp, "In-Reply-To: %s", message_id);
609   }
610
611 moan_write_references(fp, message_id);
612
613 /* Add an Auto-Submitted: header */
614
615 fprintf(fp, "Auto-Submitted: auto-replied\n");
616
617 /* Add any specially requested headers */
618
619 if (headers) fprintf(fp, "%s\n", headers);
620 fprintf(fp, "\n");
621
622 if (text)
623   {
624   fprintf(fp, "%s", CS text);
625   if (text[Ustrlen(text)-1] != '\n') fprintf(fp, "\n");
626   }
627
628 if (ff)
629   {
630 debug_printf("%s %d: ff\n", __FUNCTION__, __LINE__);
631   while (Ufgets(big_buffer, big_buffer_size, ff) != NULL)
632     {
633     if (file_expand)
634       {
635       uschar *s = expand_string(big_buffer);
636       DEBUG(D_transport)
637         {
638         if (!s)
639           debug_printf("error while expanding line from file:\n  %s\n  %s\n",
640             big_buffer, expand_string_message);
641         }
642       fprintf(fp, "%s", s ? CS s : CS big_buffer);
643       }
644     else fprintf(fp, "%s", CS big_buffer);
645     }
646   (void) fclose(ff);
647   }
648
649 /* Copy the original message if required, observing the return size
650 limit if we are returning the body. */
651
652 if (return_message)
653   {
654 debug_printf("%s %d: ret msg\n", __FUNCTION__, __LINE__);
655   uschar *rubric = tblock->headers_only
656     ? US"------ This is a copy of the message's header lines.\n"
657     : tblock->body_only
658     ? US"------ This is a copy of the body of the message, without the headers.\n"
659     : US"------ This is a copy of the message, including all the headers.\n";
660   transport_ctx tctx = {
661     .u = {.fd = fileno(fp)},
662     .tblock = tblock,
663     .addr = addr,
664     .check_string = NULL,
665     .escape_string =  NULL,
666     .options = (tblock->body_only ? topt_no_headers : 0)
667         | (tblock->headers_only ? topt_no_body : 0)
668         | (tblock->return_path_add ? topt_add_return_path : 0)
669         | (tblock->delivery_date_add ? topt_add_delivery_date : 0)
670         | (tblock->envelope_to_add ? topt_add_envelope_to : 0)
671         | topt_not_socket
672   };
673
674   if (bounce_return_size_limit > 0 && !tblock->headers_only)
675     {
676     struct stat statbuf;
677     int max = (bounce_return_size_limit/DELIVER_IN_BUFFER_SIZE + 1) *
678       DELIVER_IN_BUFFER_SIZE;
679     if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max)
680       {
681       fprintf(fp, "\n%s"
682 "------ The body of the message is " OFF_T_FMT " characters long; only the first\n"
683 "------ %d or so are included here.\n\n", rubric, statbuf.st_size,
684         (max/1000)*1000);
685       }
686     else fprintf(fp, "\n%s\n", rubric);
687     }
688   else fprintf(fp, "\n%s\n", rubric);
689
690   fflush(fp);
691   transport_count = 0;
692   transport_write_message(&tctx, bounce_return_size_limit);
693   }
694
695 /* End the message and wait for the child process to end; no timeout. */
696
697 (void)fclose(fp);
698 rc = child_close(pid, 0);
699
700 /* Update the "sent to" log whatever the yield. This errs on the side of
701 missing out a message rather than risking sending more than one. We either have
702 cache_fd set to a fixed size, circular buffer file, or dbm_file set to an open
703 DBM file (or neither, if "once" is not set). */
704
705 /* Update fixed-size cache file. If cache_time is set, we found a previous
706 entry; that is the spot into which to put the current time. Otherwise we have
707 to add a new record; remove the first one in the file if the file is too big.
708 We always rewrite the entire file in a single write operation. This is
709 (hopefully) going to be the safest thing because there is no interlocking
710 between multiple simultaneous deliveries. */
711
712 if (cache_fd >= 0)
713   {
714   uschar *from = cache_buff;
715   int size = cache_size;
716
717   if (lseek(cache_fd, 0, SEEK_SET) == 0)
718     {
719     if (!cache_time)
720       {
721       cache_time = from + size;
722       memcpy(cache_time + sizeof(time_t), to, add_size - sizeof(time_t));
723       size += add_size;
724
725       if (cache_size > 0 && size > ob->once_file_size)
726         {
727         from += sizeof(time_t) + Ustrlen(from + sizeof(time_t)) + 1;
728         size -= (from - cache_buff);
729         }
730       }
731
732     memcpy(cache_time, &now, sizeof(time_t));
733     if(write(cache_fd, from, size) != size)
734       DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s "
735         "transport\n", oncelog, tblock->name);
736     }
737   }
738
739 /* Update DBM file */
740
741 else if (dbm_file)
742   {
743   EXIM_DATUM key_datum, value_datum;
744   EXIM_DATUM_INIT(key_datum);          /* Some DBM libraries need to have */
745   EXIM_DATUM_INIT(value_datum);        /* cleared datums. */
746   EXIM_DATUM_DATA(key_datum) = CS to;
747   EXIM_DATUM_SIZE(key_datum) = Ustrlen(to) + 1;
748
749   /* Many OS define the datum value, sensibly, as a void *. However, there
750   are some which still have char *. By casting this address to a char * we
751   can avoid warning messages from the char * systems. */
752
753   EXIM_DATUM_DATA(value_datum) = CS (&now);
754   EXIM_DATUM_SIZE(value_datum) = (int)sizeof(time_t);
755   EXIM_DBPUT(dbm_file, key_datum, value_datum);
756   }
757
758 /* If sending failed, defer to try again - but if once is set the next
759 try will skip, of course. However, if there were no recipients in the
760 message, we do not fail. */
761
762 if (rc != 0)
763   if (rc == EXIT_NORECIPIENTS)
764     {
765     DEBUG(D_any) debug_printf("%s transport: message contained no recipients\n",
766       tblock->name);
767     }
768   else
769     {
770     addr->transport_return = DEFER;
771     addr->message = string_sprintf("Failed to send message from %s "
772       "transport (%d)", tblock->name, rc);
773     goto END_OFF;
774     }
775
776 /* Log the sending of the message if successful and required. If the file
777 fails to open, it's hard to know what to do. We cannot write to the Exim
778 log from here, since we may be running under an unprivileged uid. We don't
779 want to fail the delivery, since the message has been successfully sent. For
780 the moment, ignore open failures. Write the log entry as a single write() to a
781 file opened for appending, in order to avoid interleaving of output from
782 different processes. The log_buffer can be used exactly as for main log
783 writing. */
784
785 if (logfile)
786   {
787   int log_fd = Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode);
788   if (log_fd >= 0)
789     {
790     gstring gs = { .size = LOG_BUFFER_SIZE, .ptr = 0, .s = log_buffer }, *g = &gs;
791
792     /* Use taint-unchecked routines for writing into log_buffer, trusting
793     that we'll never expand it. */
794
795     DEBUG(D_transport) debug_printf("logging message details\n");
796     g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "%s\n", tod_stamp(tod_log));
797     if (from)
798       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  From: %s\n", from);
799     if (to)
800       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  To: %s\n", to);
801     if (cc)
802       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  Cc: %s\n", cc);
803     if (bcc)
804       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  Bcc: %s\n", bcc);
805     if (subject)
806       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  Subject: %s\n", subject);
807     if (headers)
808       g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "  %s\n", headers);
809     if(write(log_fd, g->s, g->ptr) != g->ptr || close(log_fd))
810       DEBUG(D_transport) debug_printf("Problem writing log file %s for %s "
811         "transport\n", logfile, tblock->name);
812     }
813   else DEBUG(D_transport) debug_printf("Failed to open log file %s for %s "
814     "transport: %s\n", logfile, tblock->name, strerror(errno));
815   }
816
817 END_OFF:
818 if (dbm_file) EXIM_DBCLOSE(dbm_file);
819 if (cache_fd > 0) (void)close(cache_fd);
820
821 DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
822
823 return FALSE;
824 }
825
826 #endif  /*!MACRO_PREDEF*/
827 /* End of transport/autoreply.c */