CVE-2020-28007: Link attack in Exim's log directory
[exim.git] / src / src / log.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 */
7 /* See the file NOTICE for conditions of use and distribution. */
8
9 /* Functions for writing log files. The code for maintaining datestamped
10 log files was originally contributed by Tony Sheen. */
11
12
13 #include "exim.h"
14
15 #define LOG_NAME_SIZE 256
16 #define MAX_SYSLOG_LEN 870
17
18 #define LOG_MODE_FILE   1
19 #define LOG_MODE_SYSLOG 2
20
21 enum { lt_main, lt_reject, lt_panic, lt_debug };
22
23 static uschar *log_names[] = { US"main", US"reject", US"panic", US"debug" };
24
25
26
27 /*************************************************
28 *           Local static variables               *
29 *************************************************/
30
31 static uschar mainlog_name[LOG_NAME_SIZE];
32 static uschar rejectlog_name[LOG_NAME_SIZE];
33 static uschar debuglog_name[LOG_NAME_SIZE];
34
35 static uschar *mainlog_datestamp = NULL;
36 static uschar *rejectlog_datestamp = NULL;
37
38 static int    mainlogfd = -1;
39 static int    rejectlogfd = -1;
40 static ino_t  mainlog_inode = 0;
41 static ino_t  rejectlog_inode = 0;
42
43 static uschar *panic_save_buffer = NULL;
44 static BOOL   panic_recurseflag = FALSE;
45
46 static BOOL   syslog_open = FALSE;
47 static BOOL   path_inspected = FALSE;
48 static int    logging_mode = LOG_MODE_FILE;
49 static uschar *file_path = US"";
50
51 static size_t pid_position[2];
52
53
54 /* These should be kept in-step with the private delivery error
55 number definitions in macros.h */
56
57 static const uschar * exim_errstrings[] = {
58   US"",
59   US"unknown error",
60   US"user slash",
61   US"exist race",
62   US"not regular",
63   US"not directory",
64   US"bad ugid",
65   US"bad mode",
66   US"inode changed",
67   US"lock failed",
68   US"bad address2",
69   US"forbid pipe",
70   US"forbid file",
71   US"forbid reply",
72   US"missing pipe",
73   US"missing file",
74   US"missing reply",
75   US"bad redirect",
76   US"smtp closed",
77   US"smtp format",
78   US"spool format",
79   US"not absolute",
80   US"Exim-imposed quota",
81   US"held",
82   US"Delivery filter process failure",
83   US"Delivery add/remove header failure",
84   US"Delivery write incomplete error",
85   US"Some expansion failed",
86   US"Failed to get gid",
87   US"Failed to get uid",
88   US"Unset or non-existent transport",
89   US"MBX length mismatch",
90   US"Lookup failed routing or in smtp tpt",
91   US"Can't match format in appendfile",
92   US"Creation outside home in appendfile",
93   US"Can't check a list; lookup defer",
94   US"DNS lookup defer",
95   US"Failed to start TLS session",
96   US"Mandatory TLS session not started",
97   US"Failed to chown a file",
98   US"Failed to create a pipe",
99   US"When verifying",
100   US"When required by client",
101   US"Used internally in smtp transport",
102   US"RCPT gave 4xx error",
103   US"MAIL gave 4xx error",
104   US"DATA gave 4xx error",
105   US"Negotiation failed for proxy configured host",
106   US"Authenticator 'other' failure",
107   US"target not supporting SMTPUTF8",
108   US"",
109
110   US"Not time for routing",
111   US"Not time for local delivery",
112   US"Not time for any remote host",
113   US"Local-only delivery",
114   US"Domain in queue_domains",
115   US"Transport concurrency limit",
116   US"Event requests alternate response",
117 };
118
119
120 /************************************************/
121 const uschar *
122 exim_errstr(int err)
123 {
124 return err < 0 ? exim_errstrings[-err] : CUS strerror(err);
125 }
126
127 /*************************************************
128 *              Write to syslog                   *
129 *************************************************/
130
131 /* The given string is split into sections according to length, or at embedded
132 newlines, and syslogged as a numbered sequence if it is overlong or if there is
133 more than one line. However, if we are running in the test harness, do not do
134 anything. (The test harness doesn't use syslog - for obvious reasons - but we
135 can get here if there is a failure to open the panic log.)
136
137 Arguments:
138   priority       syslog priority
139   s              the string to be written
140
141 Returns:         nothing
142 */
143
144 static void
145 write_syslog(int priority, const uschar *s)
146 {
147 int len;
148 int linecount = 0;
149
150 if (!syslog_pid && LOGGING(pid))
151   s = string_sprintf("%.*s%s", (int)pid_position[0], s, s + pid_position[1]);
152 if (!syslog_timestamp)
153   {
154   len = log_timezone ? 26 : 20;
155   if (LOGGING(millisec)) len += 4;
156   s += len;
157   }
158
159 len = Ustrlen(s);
160
161 #ifndef NO_OPENLOG
162 if (!syslog_open && !f.running_in_test_harness)
163   {
164 # ifdef SYSLOG_LOG_PID
165   openlog(CS syslog_processname, LOG_PID|LOG_CONS, syslog_facility);
166 # else
167   openlog(CS syslog_processname, LOG_CONS, syslog_facility);
168 # endif
169   syslog_open = TRUE;
170   }
171 #endif
172
173 /* First do a scan through the message in order to determine how many lines
174 it is going to end up as. Then rescan to output it. */
175
176 for (int pass = 0; pass < 2; pass++)
177   {
178   const uschar * ss = s;
179   for (int i = 1, tlen = len; tlen > 0; i++)
180     {
181     int plen = tlen;
182     uschar *nlptr = Ustrchr(ss, '\n');
183     if (nlptr != NULL) plen = nlptr - ss;
184 #ifndef SYSLOG_LONG_LINES
185     if (plen > MAX_SYSLOG_LEN) plen = MAX_SYSLOG_LEN;
186 #endif
187     tlen -= plen;
188     if (ss[plen] == '\n') tlen--;    /* chars left */
189
190     if (pass == 0)
191       linecount++;
192     else if (f.running_in_test_harness)
193       if (linecount == 1)
194         fprintf(stderr, "SYSLOG: '%.*s'\n", plen, ss);
195       else
196         fprintf(stderr, "SYSLOG: '[%d%c%d] %.*s'\n", i,
197           ss[plen] == '\n' && tlen != 0 ? '\\' : '/',
198           linecount, plen, ss);
199     else
200       if (linecount == 1)
201         syslog(priority, "%.*s", plen, ss);
202       else
203         syslog(priority, "[%d%c%d] %.*s", i,
204           ss[plen] == '\n' && tlen != 0 ? '\\' : '/',
205           linecount, plen, ss);
206
207     ss += plen;
208     if (*ss == '\n') ss++;
209     }
210   }
211 }
212
213
214
215 /*************************************************
216 *             Die tidily                         *
217 *************************************************/
218
219 /* This is called when Exim is dying as a result of something going wrong in
220 the logging, or after a log call with LOG_PANIC_DIE set. Optionally write a
221 message to debug_file or a stderr file, if they exist. Then, if in the middle
222 of accepting a message, throw it away tidily by calling receive_bomb_out();
223 this will attempt to send an SMTP response if appropriate. Passing NULL as the
224 first argument stops it trying to run the NOTQUIT ACL (which might try further
225 logging and thus cause problems). Otherwise, try to close down an outstanding
226 SMTP call tidily.
227
228 Arguments:
229   s1         Error message to write to debug_file and/or stderr and syslog
230   s2         Error message for any SMTP call that is in progress
231 Returns:     The function does not return
232 */
233
234 static void
235 die(uschar *s1, uschar *s2)
236 {
237 if (s1)
238   {
239   write_syslog(LOG_CRIT, s1);
240   if (debug_file) debug_printf("%s\n", s1);
241   if (log_stderr && log_stderr != debug_file)
242     fprintf(log_stderr, "%s\n", s1);
243   }
244 if (f.receive_call_bombout) receive_bomb_out(NULL, s2);  /* does not return */
245 if (smtp_input) smtp_closedown(s2);
246 exim_exit(EXIT_FAILURE);
247 }
248
249
250
251 /*************************************************
252 *             Create a log file                  *
253 *************************************************/
254
255 /* This function is called to create and open a log file. It may be called in a
256 subprocess when the original process is root.
257
258 Arguments:
259   name         the file name
260
261 The file name has been build in a working buffer, so it is permissible to
262 overwrite it temporarily if it is necessary to create the directory.
263
264 Returns:       a file descriptor, or < 0 on failure (errno set)
265 */
266
267 static int
268 log_open_already_exim(uschar * const name)
269 {
270 int fd = -1;
271 const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK;
272
273 if (geteuid() != exim_uid)
274   {
275   errno = EACCES;
276   return -1;
277   }
278
279 fd = Uopen(name, flags, LOG_MODE);
280
281 /* If creation failed, attempt to build a log directory in case that is the
282 problem. */
283
284 if (fd < 0 && errno == ENOENT)
285   {
286   BOOL created;
287   uschar *lastslash = Ustrrchr(name, '/');
288   *lastslash = 0;
289   created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
290   DEBUG(D_any) debug_printf("%s log directory %s\n",
291     created ? "created" : "failed to create", name);
292   *lastslash = '/';
293   if (created) fd = Uopen(name, flags, LOG_MODE);
294   }
295
296 return fd;
297 }
298
299
300
301 /* Inspired by OpenSSH's mm_send_fd(). Thanks! */
302
303 static int
304 log_send_fd(const int sock, const int fd)
305 {
306 struct msghdr msg;
307 union {
308   struct cmsghdr hdr;
309   char buf[CMSG_SPACE(sizeof(int))];
310 } cmsgbuf;
311 struct cmsghdr *cmsg;
312 struct iovec vec;
313 char ch = 'A';
314 ssize_t n;
315
316 memset(&msg, 0, sizeof(msg));
317 memset(&cmsgbuf, 0, sizeof(cmsgbuf));
318 msg.msg_control = &cmsgbuf.buf;
319 msg.msg_controllen = sizeof(cmsgbuf.buf);
320
321 cmsg = CMSG_FIRSTHDR(&msg);
322 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
323 cmsg->cmsg_level = SOL_SOCKET;
324 cmsg->cmsg_type = SCM_RIGHTS;
325 *(int *)CMSG_DATA(cmsg) = fd;
326
327 vec.iov_base = &ch;
328 vec.iov_len = 1;
329 msg.msg_iov = &vec;
330 msg.msg_iovlen = 1;
331
332 while ((n = sendmsg(sock, &msg, 0)) == -1 && errno == EINTR);
333 if (n != 1) return -1;
334 return 0;
335 }
336
337 /* Inspired by OpenSSH's mm_receive_fd(). Thanks! */
338
339 static int
340 log_recv_fd(const int sock)
341 {
342 struct msghdr msg;
343 union {
344   struct cmsghdr hdr;
345   char buf[CMSG_SPACE(sizeof(int))];
346 } cmsgbuf;
347 struct cmsghdr *cmsg;
348 struct iovec vec;
349 ssize_t n;
350 char ch = '\0';
351 int fd = -1;
352
353 memset(&msg, 0, sizeof(msg));
354 vec.iov_base = &ch;
355 vec.iov_len = 1;
356 msg.msg_iov = &vec;
357 msg.msg_iovlen = 1;
358
359 memset(&cmsgbuf, 0, sizeof(cmsgbuf));
360 msg.msg_control = &cmsgbuf.buf;
361 msg.msg_controllen = sizeof(cmsgbuf.buf);
362
363 while ((n = recvmsg(sock, &msg, 0)) == -1 && errno == EINTR);
364 if (n != 1 || ch != 'A') return -1;
365
366 cmsg = CMSG_FIRSTHDR(&msg);
367 if (cmsg == NULL) return -1;
368 if (cmsg->cmsg_type != SCM_RIGHTS) return -1;
369 fd = *(const int *)CMSG_DATA(cmsg);
370 if (fd < 0) return -1;
371 return fd;
372 }
373
374
375
376 /*************************************************
377 *     Create a log file as the exim user         *
378 *************************************************/
379
380 /* This function is called when we are root to spawn an exim:exim subprocess
381 in which we can create a log file. It must be signal-safe since it is called
382 by the usr1_handler().
383
384 Arguments:
385   name         the file name
386
387 Returns:       a file descriptor, or < 0 on failure (errno set)
388 */
389
390 int
391 log_open_as_exim(uschar * const name)
392 {
393 int fd = -1;
394 const uid_t euid = geteuid();
395
396 if (euid == exim_uid)
397   {
398   fd = log_open_already_exim(name);
399   }
400 else if (euid == root_uid)
401   {
402   int sock[2];
403   if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == 0)
404     {
405     const pid_t pid = exim_fork(US"logfile-open");
406     if (pid == 0)
407       {
408       (void)close(sock[0]);
409       if (setgroups(1, &exim_gid) != 0) _exit(EXIT_FAILURE);
410       if (setgid(exim_gid) != 0) _exit(EXIT_FAILURE);
411       if (setuid(exim_uid) != 0) _exit(EXIT_FAILURE);
412
413       if (getuid() != exim_uid || geteuid() != exim_uid) _exit(EXIT_FAILURE);
414       if (getgid() != exim_gid || getegid() != exim_gid) _exit(EXIT_FAILURE);
415
416       fd = log_open_already_exim(name);
417       if (fd < 0) _exit(EXIT_FAILURE);
418       if (log_send_fd(sock[1], fd) != 0) _exit(EXIT_FAILURE);
419       (void)close(sock[1]);
420       _exit(EXIT_SUCCESS);
421       }
422
423     (void)close(sock[1]);
424     if (pid > 0)
425       {
426       fd = log_recv_fd(sock[0]);
427       while (waitpid(pid, NULL, 0) == -1 && errno == EINTR);
428       }
429     (void)close(sock[0]);
430     }
431   }
432
433 if (fd >= 0)
434   {
435   int flags;
436   flags = fcntl(fd, F_GETFD);
437   if (flags != -1) (void)fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
438   flags = fcntl(fd, F_GETFL);
439   if (flags != -1) (void)fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
440   }
441 else
442   {
443   errno = EACCES;
444   }
445
446 return fd;
447 }
448
449
450
451
452 /*************************************************
453 *                Open a log file                 *
454 *************************************************/
455
456 /* This function opens one of a number of logs, creating the log directory if
457 it does not exist. This may be called recursively on failure, in order to open
458 the panic log.
459
460 The directory is in the static variable file_path. This is static so that it
461 the work of sorting out the path is done just once per Exim process.
462
463 Exim is normally configured to avoid running as root wherever possible, the log
464 files must be owned by the non-privileged exim user. To ensure this, first try
465 an open without O_CREAT - most of the time this will succeed. If it fails, try
466 to create the file; if running as root, this must be done in a subprocess to
467 avoid races.
468
469 Arguments:
470   fd         where to return the resulting file descriptor
471   type       lt_main, lt_reject, lt_panic, or lt_debug
472   tag        optional tag to include in the name (only hooked up for debug)
473
474 Returns:   nothing
475 */
476
477 static void
478 open_log(int *fd, int type, uschar *tag)
479 {
480 uid_t euid;
481 BOOL ok, ok2;
482 uschar buffer[LOG_NAME_SIZE];
483
484 /* The names of the log files are controlled by file_path. The panic log is
485 written to the same directory as the main and reject logs, but its name does
486 not have a datestamp. The use of datestamps is indicated by %D/%M in file_path.
487 When opening the panic log, if %D or %M is present, we remove the datestamp
488 from the generated name; if it is at the start, remove a following
489 non-alphanumeric character as well; otherwise, remove a preceding
490 non-alphanumeric character. This is definitely kludgy, but it sort of does what
491 people want, I hope. */
492
493 ok = string_format(buffer, sizeof(buffer), CS file_path, log_names[type]);
494
495 /* Save the name of the mainlog for rollover processing. Without a datestamp,
496 it gets statted to see if it has been cycled. With a datestamp, the datestamp
497 will be compared. The static slot for saving it is the same size as buffer,
498 and the text has been checked above to fit, so this use of strcpy() is OK. */
499
500 if (type == lt_main && string_datestamp_offset >= 0)
501   {
502   Ustrcpy(mainlog_name, buffer);
503   mainlog_datestamp = mainlog_name + string_datestamp_offset;
504   }
505
506 /* Ditto for the reject log */
507
508 else if (type == lt_reject && string_datestamp_offset >= 0)
509   {
510   Ustrcpy(rejectlog_name, buffer);
511   rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
512   }
513
514 /* and deal with the debug log (which keeps the datestamp, but does not
515 update it) */
516
517 else if (type == lt_debug)
518   {
519   Ustrcpy(debuglog_name, buffer);
520   if (tag)
521     {
522     /* this won't change the offset of the datestamp */
523     ok2 = string_format(buffer, sizeof(buffer), "%s%s",
524       debuglog_name, tag);
525     if (ok2)
526       Ustrcpy(debuglog_name, buffer);
527     }
528   }
529
530 /* Remove any datestamp if this is the panic log. This is rare, so there's no
531 need to optimize getting the datestamp length. We remove one non-alphanumeric
532 char afterwards if at the start, otherwise one before. */
533
534 else if (string_datestamp_offset >= 0)
535   {
536   uschar * from = buffer + string_datestamp_offset;
537   uschar * to = from + string_datestamp_length;
538
539   if (from == buffer || from[-1] == '/')
540     {
541     if (!isalnum(*to)) to++;
542     }
543   else
544     if (!isalnum(from[-1])) from--;
545
546   /* This copy is ok, because we know that to is a substring of from. But
547   due to overlap we must use memmove() not Ustrcpy(). */
548   memmove(from, to, Ustrlen(to)+1);
549   }
550
551 /* If the file name is too long, it is an unrecoverable disaster */
552
553 if (!ok)
554   die(US"exim: log file path too long: aborting",
555       US"Logging failure; please try later");
556
557 /* We now have the file name. After a successful open, return. */
558
559 *fd = log_open_as_exim(buffer);
560
561 if (*fd >= 0)
562   {
563   return;
564   }
565
566 euid = geteuid();
567
568 /* Creation failed. There are some circumstances in which we get here when
569 the effective uid is not root or exim, which is the problem. (For example, a
570 non-setuid binary with log_arguments set, called in certain ways.) Rather than
571 just bombing out, force the log to stderr and carry on if stderr is available.
572 */
573
574 if (euid != root_uid && euid != exim_uid && log_stderr)
575   {
576   *fd = fileno(log_stderr);
577   return;
578   }
579
580 /* Otherwise this is a disaster. This call is deliberately ONLY to the panic
581 log. If possible, save a copy of the original line that was being logged. If we
582 are recursing (can't open the panic log either), the pointer will already be
583 set.  Also, when we had to use a subprocess for the create we didn't retrieve
584 errno from it, so get the error from the open attempt above (which is often
585 meaningful enough, so leave it). */
586
587 if (!panic_save_buffer)
588   if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE)))
589     memcpy(panic_save_buffer, log_buffer, LOG_BUFFER_SIZE);
590
591 log_write(0, LOG_PANIC_DIE, "Cannot open %s log file \"%s\": %s: "
592   "euid=%d egid=%d", log_names[type], buffer, strerror(errno), euid, getegid());
593 /* Never returns */
594 }
595
596
597 static void
598 unlink_log(int type)
599 {
600 if (type == lt_debug) unlink(CS debuglog_name);
601 }
602
603
604
605 /*************************************************
606 *     Add configuration file info to log line    *
607 *************************************************/
608
609 /* This is put in a function because it's needed twice (once for debugging,
610 once for real).
611
612 Arguments:
613   ptr         pointer to the end of the line we are building
614   flags       log flags
615
616 Returns:      updated pointer
617 */
618
619 static gstring *
620 log_config_info(gstring * g, int flags)
621 {
622 g = string_cat(g, US"Exim configuration error");
623
624 if (flags & (LOG_CONFIG_FOR & ~LOG_CONFIG))
625   return string_cat(g, US" for ");
626
627 if (flags & (LOG_CONFIG_IN & ~LOG_CONFIG))
628   g = string_fmt_append(g, " in line %d of %s", config_lineno, config_filename);
629
630 return string_catn(g, US":\n  ", 4);
631 }
632
633
634 /*************************************************
635 *           A write() operation failed           *
636 *************************************************/
637
638 /* This function is called when write() fails on anything other than the panic
639 log, which can happen if a disk gets full or a file gets too large or whatever.
640 We try to save the relevant message in the panic_save buffer before crashing
641 out.
642
643 The potential invoker should probably not call us for EINTR -1 writes.  But
644 otherwise, short writes are bad as we don't do non-blocking writes to fds
645 subject to flow control.  (If we do, that's new and the logic of this should
646 be reconsidered).
647
648 Arguments:
649   name      the name of the log being written
650   length    the string length being written
651   rc        the return value from write()
652
653 Returns:    does not return
654 */
655
656 static void
657 log_write_failed(uschar *name, int length, int rc)
658 {
659 int save_errno = errno;
660
661 if (!panic_save_buffer)
662   if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE)))
663     memcpy(panic_save_buffer, log_buffer, LOG_BUFFER_SIZE);
664
665 log_write(0, LOG_PANIC_DIE, "failed to write to %s: length=%d result=%d "
666   "errno=%d (%s)", name, length, rc, save_errno,
667   (save_errno == 0)? "write incomplete" : strerror(save_errno));
668 /* Never returns */
669 }
670
671
672
673 /*************************************************
674 *     Write to an fd, retrying after signals     *
675 *************************************************/
676
677 /* Basic write to fd for logs, handling EINTR.
678
679 Arguments:
680   fd        the fd to write to
681   buf       the string to write
682   length    the string length being written
683
684 Returns:
685   length actually written, persisting an errno from write()
686 */
687 ssize_t
688 write_to_fd_buf(int fd, const uschar *buf, size_t length)
689 {
690 ssize_t wrote;
691 size_t total_written = 0;
692 const uschar *p = buf;
693 size_t left = length;
694
695 while (1)
696   {
697   wrote = write(fd, p, left);
698   if (wrote == (ssize_t)-1)
699     {
700     if (errno == EINTR) continue;
701     return wrote;
702     }
703   total_written += wrote;
704   if (wrote == left)
705     break;
706   else
707     {
708     p += wrote;
709     left -= wrote;
710     }
711   }
712 return total_written;
713 }
714
715
716
717 static void
718 set_file_path(void)
719 {
720 int sep = ':';              /* Fixed separator - outside use */
721 uschar *t;
722 const uschar *tt = US LOG_FILE_PATH;
723 while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
724   {
725   if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
726   file_path = string_copy(t);
727   break;
728   }
729 }
730
731
732 void
733 mainlog_close(void)
734 {
735 if (mainlogfd < 0) return;
736 (void)close(mainlogfd);
737 mainlogfd = -1;
738 mainlog_inode = 0;
739 }
740
741 /*************************************************
742 *            Write message to log file           *
743 *************************************************/
744
745 /* Exim can be configured to log to local files, or use syslog, or both. This
746 is controlled by the setting of log_file_path. The following cases are
747 recognized:
748
749   log_file_path = ""               write files in the spool/log directory
750   log_file_path = "xxx"            write files in the xxx directory
751   log_file_path = "syslog"         write to syslog
752   log_file_path = "syslog : xxx"   write to syslog and to files (any order)
753
754 The message always gets '\n' added on the end of it, since more than one
755 process may be writing to the log at once and we don't want intermingling to
756 happen in the middle of lines. To be absolutely sure of this we write the data
757 into a private buffer and then put it out in a single write() call.
758
759 The flags determine which log(s) the message is written to, or for syslogging,
760 which priority to use, and in the case of the panic log, whether the process
761 should die afterwards.
762
763 The variable really_exim is TRUE only when exim is running in privileged state
764 (i.e. not with a changed configuration or with testing options such as -brw).
765 If it is not, don't try to write to the log because permission will probably be
766 denied.
767
768 Avoid actually writing to the logs when exim is called with -bv or -bt to
769 test an address, but take other actions, such as panicking.
770
771 In Exim proper, the buffer for building the message is got at start-up, so that
772 nothing gets done if it can't be got. However, some functions that are also
773 used in utilities occasionally obey log_write calls in error situations, and it
774 is simplest to put a single malloc() here rather than put one in each utility.
775 Malloc is used directly because the store functions may call log_write().
776
777 If a message_id exists, we include it after the timestamp.
778
779 Arguments:
780   selector  write to main log or LOG_INFO only if this value is zero, or if
781               its bit is set in log_selector[0]
782   flags     each bit indicates some independent action:
783               LOG_SENDER      add raw sender to the message
784               LOG_RECIPIENTS  add raw recipients list to message
785               LOG_CONFIG      add "Exim configuration error"
786               LOG_CONFIG_FOR  add " for " instead of ":\n  "
787               LOG_CONFIG_IN   add " in line x[ of file y]"
788               LOG_MAIN        write to main log or syslog LOG_INFO
789               LOG_REJECT      write to reject log or syslog LOG_NOTICE
790               LOG_PANIC       write to panic log or syslog LOG_ALERT
791               LOG_PANIC_DIE   write to panic log or LOG_ALERT and then crash
792   format    a printf() format
793   ...       arguments for format
794
795 Returns:    nothing
796 */
797
798 void
799 log_write(unsigned int selector, int flags, const char *format, ...)
800 {
801 int paniclogfd;
802 ssize_t written_len;
803 gstring gs = { .size = LOG_BUFFER_SIZE-1, .ptr = 0, .s = log_buffer };
804 gstring * g;
805 va_list ap;
806
807 /* If panic_recurseflag is set, we have failed to open the panic log. This is
808 the ultimate disaster. First try to write the message to a debug file and/or
809 stderr and also to syslog. If panic_save_buffer is not NULL, it contains the
810 original log line that caused the problem. Afterwards, expire. */
811
812 if (panic_recurseflag)
813   {
814   uschar *extra = panic_save_buffer ? panic_save_buffer : US"";
815   if (debug_file) debug_printf("%s%s", extra, log_buffer);
816   if (log_stderr && log_stderr != debug_file)
817     fprintf(log_stderr, "%s%s", extra, log_buffer);
818   if (*extra) write_syslog(LOG_CRIT, extra);
819   write_syslog(LOG_CRIT, log_buffer);
820   die(US"exim: could not open panic log - aborting: see message(s) above",
821     US"Unexpected log failure, please try later");
822   }
823
824 /* Ensure we have a buffer (see comment above); this should never be obeyed
825 when running Exim proper, only when running utilities. */
826
827 if (!log_buffer)
828   if (!(log_buffer = US malloc(LOG_BUFFER_SIZE)))
829     {
830     fprintf(stderr, "exim: failed to get store for log buffer\n");
831     exim_exit(EXIT_FAILURE);
832     }
833
834 /* If we haven't already done so, inspect the setting of log_file_path to
835 determine whether to log to files and/or to syslog. Bits in logging_mode
836 control this, and for file logging, the path must end up in file_path. This
837 variable must be in permanent store because it may be required again later in
838 the process. */
839
840 if (!path_inspected)
841   {
842   BOOL multiple = FALSE;
843   int old_pool = store_pool;
844
845   store_pool = POOL_PERM;
846
847   /* If nothing has been set, don't waste effort... the default values for the
848   statics are file_path="" and logging_mode = LOG_MODE_FILE. */
849
850   if (*log_file_path)
851     {
852     int sep = ':';              /* Fixed separator - outside use */
853     uschar *s;
854     const uschar *ss = log_file_path;
855
856     logging_mode = 0;
857     while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
858       {
859       if (Ustrcmp(s, "syslog") == 0)
860         logging_mode |= LOG_MODE_SYSLOG;
861       else if (logging_mode & LOG_MODE_FILE)
862         multiple = TRUE;
863       else
864         {
865         logging_mode |= LOG_MODE_FILE;
866
867         /* If a non-empty path is given, use it */
868
869         if (*s)
870           file_path = string_copy(s);
871
872         /* If the path is empty, we want to use the first non-empty, non-
873         syslog item in LOG_FILE_PATH, if there is one, since the value of
874         log_file_path may have been set at runtime. If there is no such item,
875         use the ultimate default in the spool directory. */
876
877         else
878           set_file_path();  /* Empty item in log_file_path */
879         }    /* First non-syslog item in log_file_path */
880       }      /* Scan of log_file_path */
881     }
882
883   /* If no modes have been selected, it is a major disaster */
884
885   if (logging_mode == 0)
886     die(US"Neither syslog nor file logging set in log_file_path",
887         US"Unexpected logging failure");
888
889   /* Set up the ultimate default if necessary. Then revert to the old store
890   pool, and record that we've sorted out the path. */
891
892   if (logging_mode & LOG_MODE_FILE  &&  !file_path[0])
893     file_path = string_sprintf("%s/log/%%slog", spool_directory);
894   store_pool = old_pool;
895   path_inspected = TRUE;
896
897   /* If more than one file path was given, log a complaint. This recursive call
898   should work since we have now set up the routing. */
899
900   if (multiple)
901     log_write(0, LOG_MAIN|LOG_PANIC,
902       "More than one path given in log_file_path: using %s", file_path);
903   }
904
905 /* If debugging, show all log entries, but don't show headers. Do it all
906 in one go so that it doesn't get split when multi-processing. */
907
908 DEBUG(D_any|D_v)
909   {
910   int i;
911
912   g = string_catn(&gs, US"LOG:", 4);
913
914   /* Show the selector that was passed into the call. */
915
916   for (i = 0; i < log_options_count; i++)
917     {
918     unsigned int bitnum = log_options[i].bit;
919     if (bitnum < BITWORDSIZE && selector == BIT(bitnum))
920       g = string_fmt_append(g, " %s", log_options[i].name);
921     }
922
923   g = string_fmt_append(g, "%s%s%s%s\n  ",
924     flags & LOG_MAIN ?    " MAIN"   : "",
925     flags & LOG_PANIC ?   " PANIC"  : "",
926     (flags & LOG_PANIC_DIE) == LOG_PANIC_DIE ? " DIE" : "",
927     flags & LOG_REJECT ?  " REJECT" : "");
928
929   if (flags & LOG_CONFIG) g = log_config_info(g, flags);
930
931   /* We want to be able to log tainted info, but log_buffer is directly
932   malloc'd.  So use deliberately taint-nonchecking routines to build into
933   it, trusting that we will never expand the results. */
934
935   va_start(ap, format);
936   i = g->ptr;
937   if (!string_vformat(g, SVFMT_TAINT_NOCHK, format, ap))
938     {
939     g->ptr = i;
940     g = string_cat(g, US"**** log string overflowed log buffer ****");
941     }
942   va_end(ap);
943
944   g->size = LOG_BUFFER_SIZE;
945   g = string_catn(g, US"\n", 1);
946   debug_printf("%s", string_from_gstring(g));
947
948   gs.size = LOG_BUFFER_SIZE-1;  /* Having used the buffer for debug output, */
949   gs.ptr = 0;                   /* reset it for the real use. */
950   gs.s = log_buffer;
951   }
952 /* If no log file is specified, we are in a mess. */
953
954 if (!(flags & (LOG_MAIN|LOG_PANIC|LOG_REJECT)))
955   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "log_write called with no log "
956     "flags set");
957
958 /* There are some weird circumstances in which logging is disabled. */
959
960 if (f.disable_logging)
961   {
962   DEBUG(D_any) debug_printf("log writing disabled\n");
963   if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE) exim_exit(EXIT_FAILURE);
964   return;
965   }
966
967 /* Handle disabled reject log */
968
969 if (!write_rejectlog) flags &= ~LOG_REJECT;
970
971 /* Create the main message in the log buffer. Do not include the message id
972 when called by a utility. */
973
974 g = string_fmt_append(&gs, "%s ", tod_stamp(tod_log));
975
976 if (LOGGING(pid))
977   {
978   if (!syslog_pid) pid_position[0] = g->ptr;            /* remember begin â€¦ */
979   g = string_fmt_append(g, "[%d] ", (int)getpid());
980   if (!syslog_pid) pid_position[1] = g->ptr;            /*  â€¦ and end+1 of the PID */
981   }
982
983 if (f.really_exim && message_id[0] != 0)
984   g = string_fmt_append(g, "%s ", message_id);
985
986 if (flags & LOG_CONFIG)
987   g = log_config_info(g, flags);
988
989 va_start(ap, format);
990   {
991   int i = g->ptr;
992
993   /* We want to be able to log tainted info, but log_buffer is directly
994   malloc'd.  So use deliberately taint-nonchecking routines to build into
995   it, trusting that we will never expand the results. */
996
997   if (!string_vformat(g, SVFMT_TAINT_NOCHK, format, ap))
998     {
999     g->ptr = i;
1000     g = string_cat(g, US"**** log string overflowed log buffer ****\n");
1001     }
1002   }
1003 va_end(ap);
1004
1005 /* Add the raw, unrewritten, sender to the message if required. This is done
1006 this way because it kind of fits with LOG_RECIPIENTS. */
1007
1008 if (   flags & LOG_SENDER
1009    && g->ptr < LOG_BUFFER_SIZE - 10 - Ustrlen(raw_sender))
1010   g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " from <%s>", raw_sender);
1011
1012 /* Add list of recipients to the message if required; the raw list,
1013 before rewriting, was saved in raw_recipients. There may be none, if an ACL
1014 discarded them all. */
1015
1016 if (  flags & LOG_RECIPIENTS
1017    && g->ptr < LOG_BUFFER_SIZE - 6
1018    && raw_recipients_count > 0)
1019   {
1020   int i;
1021   g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " for", NULL);
1022   for (i = 0; i < raw_recipients_count; i++)
1023     {
1024     uschar * s = raw_recipients[i];
1025     if (LOG_BUFFER_SIZE - g->ptr < Ustrlen(s) + 3) break;
1026     g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s", s);
1027     }
1028   }
1029
1030 g = string_catn(g, US"\n", 1);
1031 string_from_gstring(g);
1032
1033 /* Handle loggable errors when running a utility, or when address testing.
1034 Write to log_stderr unless debugging (when it will already have been written),
1035 or unless there is no log_stderr (expn called from daemon, for example). */
1036
1037 if (!f.really_exim || f.log_testing_mode)
1038   {
1039   if (  !debug_selector
1040      && log_stderr
1041      && (selector == 0 || (selector & log_selector[0]) != 0)
1042     )
1043     if (host_checking)
1044       fprintf(log_stderr, "LOG: %s", CS(log_buffer + 20));  /* no timestamp */
1045     else
1046       fprintf(log_stderr, "%s", CS log_buffer);
1047
1048   if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE) exim_exit(EXIT_FAILURE);
1049   return;
1050   }
1051
1052 /* Handle the main log. We know that either syslog or file logging (or both) is
1053 set up. A real file gets left open during reception or delivery once it has
1054 been opened, but we don't want to keep on writing to it for too long after it
1055 has been renamed. Therefore, do a stat() and see if the inode has changed, and
1056 if so, re-open. */
1057
1058 if (  flags & LOG_MAIN
1059    && (!selector ||  selector & log_selector[0]))
1060   {
1061   if (  logging_mode & LOG_MODE_SYSLOG
1062      && (syslog_duplication || !(flags & (LOG_REJECT|LOG_PANIC))))
1063     write_syslog(LOG_INFO, log_buffer);
1064
1065   if (logging_mode & LOG_MODE_FILE)
1066     {
1067     struct stat statbuf;
1068
1069     /* Check for a change to the mainlog file name when datestamping is in
1070     operation. This happens at midnight, at which point we want to roll over
1071     the file. Closing it has the desired effect. */
1072
1073     if (mainlog_datestamp)
1074       {
1075       uschar *nowstamp = tod_stamp(string_datestamp_type);
1076       if (Ustrncmp (mainlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
1077         {
1078         (void)close(mainlogfd);       /* Close the file */
1079         mainlogfd = -1;               /* Clear the file descriptor */
1080         mainlog_inode = 0;            /* Unset the inode */
1081         mainlog_datestamp = NULL;     /* Clear the datestamp */
1082         }
1083       }
1084
1085     /* Otherwise, we want to check whether the file has been renamed by a
1086     cycling script. This could be "if else", but for safety's sake, leave it as
1087     "if" so that renaming the log starts a new file even when datestamping is
1088     happening. */
1089
1090     if (mainlogfd >= 0)
1091       if (Ustat(mainlog_name, &statbuf) < 0 || statbuf.st_ino != mainlog_inode)
1092         mainlog_close();
1093
1094     /* If the log is closed, open it. Then write the line. */
1095
1096     if (mainlogfd < 0)
1097       {
1098       open_log(&mainlogfd, lt_main, NULL);     /* No return on error */
1099       if (fstat(mainlogfd, &statbuf) >= 0) mainlog_inode = statbuf.st_ino;
1100       }
1101
1102     /* Failing to write to the log is disastrous */
1103
1104     written_len = write_to_fd_buf(mainlogfd, g->s, g->ptr);
1105     if (written_len != g->ptr)
1106       {
1107       log_write_failed(US"main log", g->ptr, written_len);
1108       /* That function does not return */
1109       }
1110     }
1111   }
1112
1113 /* Handle the log for rejected messages. This can be globally disabled, in
1114 which case the flags are altered above. If there are any header lines (i.e. if
1115 the rejection is happening after the DATA phase), log the recipients and the
1116 headers. */
1117
1118 if (flags & LOG_REJECT)
1119   {
1120   if (header_list && LOGGING(rejected_header))
1121     {
1122     gstring * g2;
1123     int i;
1124
1125     if (recipients_count > 0)
1126       {
1127       /* List the sender */
1128
1129       g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK,
1130                         "Envelope-from: <%s>\n", sender_address);
1131       if (g2) g = g2;
1132
1133       /* List up to 5 recipients */
1134
1135       g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK,
1136                         "Envelope-to: <%s>\n", recipients_list[0].address);
1137       if (g2) g = g2;
1138
1139       for (i = 1; i < recipients_count && i < 5; i++)
1140         {
1141         g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK,
1142                         "    <%s>\n", recipients_list[i].address);
1143         if (g2) g = g2;
1144         }
1145
1146       if (i < recipients_count)
1147         {
1148         g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "    ...\n", NULL);
1149         if (g2) g = g2;
1150         }
1151       }
1152
1153     /* A header with a NULL text is an unfilled in Received: header */
1154
1155     for (header_line * h = header_list; h; h = h->next) if (h->text)
1156       {
1157       g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK,
1158                         "%c %s", h->type, h->text);
1159       if (g2)
1160         g = g2;
1161       else              /* Buffer is full; truncate */
1162         {
1163         g->ptr -= 100;        /* For message and separator */
1164         if (g->s[g->ptr-1] == '\n') g->ptr--;
1165         g = string_cat(g, US"\n*** truncated ***\n");
1166         break;
1167         }
1168       }
1169     }
1170
1171   /* Write to syslog or to a log file */
1172
1173   if (  logging_mode & LOG_MODE_SYSLOG
1174      && (syslog_duplication || !(flags & LOG_PANIC)))
1175     write_syslog(LOG_NOTICE, string_from_gstring(g));
1176
1177   /* Check for a change to the rejectlog file name when datestamping is in
1178   operation. This happens at midnight, at which point we want to roll over
1179   the file. Closing it has the desired effect. */
1180
1181   if (logging_mode & LOG_MODE_FILE)
1182     {
1183     struct stat statbuf;
1184
1185     if (rejectlog_datestamp)
1186       {
1187       uschar *nowstamp = tod_stamp(string_datestamp_type);
1188       if (Ustrncmp (rejectlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
1189         {
1190         (void)close(rejectlogfd);       /* Close the file */
1191         rejectlogfd = -1;               /* Clear the file descriptor */
1192         rejectlog_inode = 0;            /* Unset the inode */
1193         rejectlog_datestamp = NULL;     /* Clear the datestamp */
1194         }
1195       }
1196
1197     /* Otherwise, we want to check whether the file has been renamed by a
1198     cycling script. This could be "if else", but for safety's sake, leave it as
1199     "if" so that renaming the log starts a new file even when datestamping is
1200     happening. */
1201
1202     if (rejectlogfd >= 0)
1203       if (Ustat(rejectlog_name, &statbuf) < 0 ||
1204            statbuf.st_ino != rejectlog_inode)
1205         {
1206         (void)close(rejectlogfd);
1207         rejectlogfd = -1;
1208         rejectlog_inode = 0;
1209         }
1210
1211     /* Open the file if necessary, and write the data */
1212
1213     if (rejectlogfd < 0)
1214       {
1215       open_log(&rejectlogfd, lt_reject, NULL); /* No return on error */
1216       if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino;
1217       }
1218
1219     written_len = write_to_fd_buf(rejectlogfd, g->s, g->ptr);
1220     if (written_len != g->ptr)
1221       {
1222       log_write_failed(US"reject log", g->ptr, written_len);
1223       /* That function does not return */
1224       }
1225     }
1226   }
1227
1228
1229 /* Handle the panic log, which is not kept open like the others. If it fails to
1230 open, there will be a recursive call to log_write(). We detect this above and
1231 attempt to write to the system log as a last-ditch try at telling somebody. In
1232 all cases except mua_wrapper, try to write to log_stderr. */
1233
1234 if (flags & LOG_PANIC)
1235   {
1236   if (log_stderr && log_stderr != debug_file && !mua_wrapper)
1237     fprintf(log_stderr, "%s", CS string_from_gstring(g));
1238
1239   if (logging_mode & LOG_MODE_SYSLOG)
1240     write_syslog(LOG_ALERT, log_buffer);
1241
1242   /* If this panic logging was caused by a failure to open the main log,
1243   the original log line is in panic_save_buffer. Make an attempt to write it. */
1244
1245   if (logging_mode & LOG_MODE_FILE)
1246     {
1247     panic_recurseflag = TRUE;
1248     open_log(&paniclogfd, lt_panic, NULL);  /* Won't return on failure */
1249     panic_recurseflag = FALSE;
1250
1251     if (panic_save_buffer)
1252       {
1253       int i = write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
1254       i = i;    /* compiler quietening */
1255       }
1256
1257     written_len = write_to_fd_buf(paniclogfd, g->s, g->ptr);
1258     if (written_len != g->ptr)
1259       {
1260       int save_errno = errno;
1261       write_syslog(LOG_CRIT, log_buffer);
1262       sprintf(CS log_buffer, "write failed on panic log: length=%d result=%d "
1263         "errno=%d (%s)", g->ptr, (int)written_len, save_errno, strerror(save_errno));
1264       write_syslog(LOG_CRIT, string_from_gstring(g));
1265       flags |= LOG_PANIC_DIE;
1266       }
1267
1268     (void)close(paniclogfd);
1269     }
1270
1271   /* Give up if the DIE flag is set */
1272
1273   if ((flags & LOG_PANIC_DIE) != LOG_PANIC)
1274     die(NULL, US"Unexpected failure, please try later");
1275   }
1276 }
1277
1278
1279
1280 /*************************************************
1281 *            Close any open log files            *
1282 *************************************************/
1283
1284 void
1285 log_close_all(void)
1286 {
1287 if (mainlogfd >= 0)
1288   { (void)close(mainlogfd); mainlogfd = -1; }
1289 if (rejectlogfd >= 0)
1290   { (void)close(rejectlogfd); rejectlogfd = -1; }
1291 closelog();
1292 syslog_open = FALSE;
1293 }
1294
1295
1296
1297 /*************************************************
1298 *             Multi-bit set or clear             *
1299 *************************************************/
1300
1301 /* These functions take a list of bit indexes (terminated by -1) and
1302 clear or set the corresponding bits in the selector.
1303
1304 Arguments:
1305   selector       address of the bit string
1306   selsize        number of words in the bit string
1307   bits           list of bits to set
1308 */
1309
1310 void
1311 bits_clear(unsigned int *selector, size_t selsize, int *bits)
1312 {
1313 for(; *bits != -1; ++bits)
1314   BIT_CLEAR(selector, selsize, *bits);
1315 }
1316
1317 void
1318 bits_set(unsigned int *selector, size_t selsize, int *bits)
1319 {
1320 for(; *bits != -1; ++bits)
1321   BIT_SET(selector, selsize, *bits);
1322 }
1323
1324
1325
1326 /*************************************************
1327 *         Decode bit settings for log/debug      *
1328 *************************************************/
1329
1330 /* This function decodes a string containing bit settings in the form of +name
1331 and/or -name sequences, and sets/unsets bits in a bit string accordingly. It
1332 also recognizes a numeric setting of the form =<number>, but this is not
1333 intended for user use. It's an easy way for Exim to pass the debug settings
1334 when it is re-exec'ed.
1335
1336 The option table is a list of names and bit indexes. The index -1
1337 means "set all bits, except for those listed in notall". The notall
1338 list is terminated by -1.
1339
1340 The action taken for bad values varies depending upon why we're here.
1341 For log messages, or if the debugging is triggered from config, then we write
1342 to the log on the way out.  For debug setting triggered from the command-line,
1343 we treat it as an unknown option: error message to stderr and die.
1344
1345 Arguments:
1346   selector       address of the bit string
1347   selsize        number of words in the bit string
1348   notall         list of bits to exclude from "all"
1349   string         the configured string
1350   options        the table of option names
1351   count          size of table
1352   which          "log" or "debug"
1353   flags          DEBUG_FROM_CONFIG
1354
1355 Returns:         nothing on success - bomb out on failure
1356 */
1357
1358 void
1359 decode_bits(unsigned int *selector, size_t selsize, int *notall,
1360   uschar *string, bit_table *options, int count, uschar *which, int flags)
1361 {
1362 uschar *errmsg;
1363 if (!string) return;
1364
1365 if (*string == '=')
1366   {
1367   char *end;    /* Not uschar */
1368   memset(selector, 0, sizeof(*selector)*selsize);
1369   *selector = strtoul(CS string+1, &end, 0);
1370   if (!*end) return;
1371   errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which,
1372     string);
1373   goto ERROR_RETURN;
1374   }
1375
1376 /* Handle symbolic setting */
1377
1378 else for(;;)
1379   {
1380   BOOL adding;
1381   uschar *s;
1382   int len;
1383   bit_table *start, *end;
1384
1385   Uskip_whitespace(&string);
1386   if (!*string) return;
1387
1388   if (*string != '+' && *string != '-')
1389     {
1390     errmsg = string_sprintf("malformed %s_selector setting: "
1391       "+ or - expected but found \"%s\"", which, string);
1392     goto ERROR_RETURN;
1393     }
1394
1395   adding = *string++ == '+';
1396   s = string;
1397   while (isalnum(*string) || *string == '_') string++;
1398   len = string - s;
1399
1400   start = options;
1401   end = options + count;
1402
1403   while (start < end)
1404     {
1405     bit_table *middle = start + (end - start)/2;
1406     int c = Ustrncmp(s, middle->name, len);
1407     if (c == 0)
1408       if (middle->name[len] != 0) c = -1; else
1409         {
1410         unsigned int bit = middle->bit;
1411
1412         if (bit == -1)
1413           {
1414           if (adding)
1415             {
1416             memset(selector, -1, sizeof(*selector)*selsize);
1417             bits_clear(selector, selsize, notall);
1418             }
1419           else
1420             memset(selector, 0, sizeof(*selector)*selsize);
1421           }
1422         else if (adding)
1423           BIT_SET(selector, selsize, bit);
1424         else
1425           BIT_CLEAR(selector, selsize, bit);
1426
1427         break;  /* Out of loop to match selector name */
1428         }
1429     if (c < 0) end = middle; else start = middle + 1;
1430     }  /* Loop to match selector name */
1431
1432   if (start >= end)
1433     {
1434     errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", which,
1435       adding? '+' : '-', len, s);
1436     goto ERROR_RETURN;
1437     }
1438   }    /* Loop for selector names */
1439
1440 /* Handle disasters */
1441
1442 ERROR_RETURN:
1443 if (Ustrcmp(which, "debug") == 0)
1444   {
1445   if (flags & DEBUG_FROM_CONFIG)
1446     {
1447     log_write(0, LOG_CONFIG|LOG_PANIC, "%s", errmsg);
1448     return;
1449     }
1450   fprintf(stderr, "exim: %s\n", errmsg);
1451   exit(EXIT_FAILURE);
1452   }
1453 else log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "%s", errmsg);
1454 }
1455
1456
1457
1458 /*************************************************
1459 *        Activate a debug logfile (late)         *
1460 *************************************************/
1461
1462 /* Normally, debugging is activated from the command-line; it may be useful
1463 within the configuration to activate debugging later, based on certain
1464 conditions.  If debugging is already in progress, we return early, no action
1465 taken (besides debug-logging that we wanted debug-logging).
1466
1467 Failures in options are not fatal but will result in paniclog entries for the
1468 misconfiguration.
1469
1470 The first use of this is in ACL logic, "control = debug/tag=foo/opts=+expand"
1471 which can be combined with conditions, etc, to activate extra logging only
1472 for certain sources. The second use is inetd wait mode debug preservation. */
1473
1474 void
1475 debug_logging_activate(uschar *tag_name, uschar *opts)
1476 {
1477 int fd = -1;
1478
1479 if (debug_file)
1480   {
1481   debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n"
1482       "DEBUG: Tag=\"%s\" opts=\"%s\"\n", tag_name, opts ? opts : US"");
1483   return;
1484   }
1485
1486 if (tag_name != NULL && (Ustrchr(tag_name, '/') != NULL))
1487   {
1488   log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s",
1489       tag_name);
1490   return;
1491   }
1492
1493 debug_selector = D_default;
1494 if (opts)
1495   decode_bits(&debug_selector, 1, debug_notall, opts,
1496       debug_options, debug_options_count, US"debug", DEBUG_FROM_CONFIG);
1497
1498 /* When activating from a transport process we may never have logged at all
1499 resulting in certain setup not having been done.  Hack this for now so we
1500 do not segfault; note that nondefault log locations will not work */
1501
1502 if (!*file_path) set_file_path();
1503
1504 open_log(&fd, lt_debug, tag_name);
1505
1506 if (fd != -1)
1507   debug_file = fdopen(fd, "w");
1508 else
1509   log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log");
1510 }
1511
1512
1513 void
1514 debug_logging_stop(void)
1515 {
1516 if (!debug_file || !debuglog_name[0]) return;
1517
1518 debug_selector = 0;
1519 fclose(debug_file);
1520 debug_file = NULL;
1521 unlink_log(lt_debug);
1522 }
1523
1524
1525 /* End of log.c */