*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for writing log files. The code for maintaining datestamped
}
if (f.receive_call_bombout) receive_bomb_out(NULL, s2); /* does not return */
if (smtp_input) smtp_closedown(s2);
-exim_exit(EXIT_FAILURE, NULL);
+exim_exit(EXIT_FAILURE);
}
Returns: a file descriptor, or < 0 on failure (errno set)
*/
-int
-log_create(uschar *name)
+static int
+log_open_already_exim(uschar * const name)
{
-int fd = Uopen(name,
-#ifdef O_CLOEXEC
- O_CLOEXEC |
-#endif
- O_CREAT|O_APPEND|O_WRONLY, LOG_MODE);
+int fd = -1;
+const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK;
+
+if (geteuid() != exim_uid)
+ {
+ errno = EACCES;
+ return -1;
+ }
+
+fd = Uopen(name, flags, LOG_MODE);
/* If creation failed, attempt to build a log directory in case that is the
problem. */
uschar *lastslash = Ustrrchr(name, '/');
*lastslash = 0;
created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
- DEBUG(D_any) debug_printf("%s log directory %s\n",
- created ? "created" : "failed to create", name);
+ DEBUG(D_any)
+ if (created)
+ debug_printf("created log directory %s\n", name);
+ else
+ debug_printf("failed to create log directory %s: %s\n", name, strerror(errno));
*lastslash = '/';
- if (created) fd = Uopen(name,
-#ifdef O_CLOEXEC
- O_CLOEXEC |
-#endif
- O_CREAT|O_APPEND|O_WRONLY, LOG_MODE);
+ if (created) fd = Uopen(name, flags, LOG_MODE);
}
return fd;
+/* Inspired by OpenSSH's mm_send_fd(). Thanks! */
+
+static int
+log_send_fd(const int sock, const int fd)
+{
+struct msghdr msg;
+union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int))];
+} cmsgbuf;
+struct cmsghdr *cmsg;
+struct iovec vec;
+char ch = 'A';
+ssize_t n;
+
+memset(&msg, 0, sizeof(msg));
+memset(&cmsgbuf, 0, sizeof(cmsgbuf));
+msg.msg_control = &cmsgbuf.buf;
+msg.msg_controllen = sizeof(cmsgbuf.buf);
+
+cmsg = CMSG_FIRSTHDR(&msg);
+cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+cmsg->cmsg_level = SOL_SOCKET;
+cmsg->cmsg_type = SCM_RIGHTS;
+*(int *)CMSG_DATA(cmsg) = fd;
+
+vec.iov_base = &ch;
+vec.iov_len = 1;
+msg.msg_iov = &vec;
+msg.msg_iovlen = 1;
+
+while ((n = sendmsg(sock, &msg, 0)) == -1 && errno == EINTR);
+if (n != 1) return -1;
+return 0;
+}
+
+/* Inspired by OpenSSH's mm_receive_fd(). Thanks! */
+
+static int
+log_recv_fd(const int sock)
+{
+struct msghdr msg;
+union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int))];
+} cmsgbuf;
+struct cmsghdr *cmsg;
+struct iovec vec;
+ssize_t n;
+char ch = '\0';
+int fd = -1;
+
+memset(&msg, 0, sizeof(msg));
+vec.iov_base = &ch;
+vec.iov_len = 1;
+msg.msg_iov = &vec;
+msg.msg_iovlen = 1;
+
+memset(&cmsgbuf, 0, sizeof(cmsgbuf));
+msg.msg_control = &cmsgbuf.buf;
+msg.msg_controllen = sizeof(cmsgbuf.buf);
+
+while ((n = recvmsg(sock, &msg, 0)) == -1 && errno == EINTR);
+if (n != 1 || ch != 'A') return -1;
+
+cmsg = CMSG_FIRSTHDR(&msg);
+if (cmsg == NULL) return -1;
+if (cmsg->cmsg_type != SCM_RIGHTS) return -1;
+fd = *(const int *)CMSG_DATA(cmsg);
+if (fd < 0) return -1;
+return fd;
+}
+
+
+
/*************************************************
* Create a log file as the exim user *
*************************************************/
*/
int
-log_create_as_exim(uschar *name)
+log_open_as_exim(uschar * const name)
{
-pid_t pid = fork();
-int status = 1;
int fd = -1;
+const uid_t euid = geteuid();
-/* In the subprocess, change uid/gid and do the creation. Return 0 from the
-subprocess on success. If we don't check for setuid failures, then the file
-can be created as root, so vulnerabilities which cause setuid to fail mean
-that the Exim user can use symlinks to cause a file to be opened/created as
-root. We always open for append, so can't nuke existing content but it would
-still be Rather Bad. */
-
-if (pid == 0)
+if (euid == exim_uid)
+ fd = log_open_already_exim(name);
+else if (euid == root_uid)
{
- if (setgid(exim_gid) < 0)
- die(US"exim: setgid for log-file creation failed, aborting",
- US"Unexpected log failure, please try later");
- if (setuid(exim_uid) < 0)
- die(US"exim: setuid for log-file creation failed, aborting",
- US"Unexpected log failure, please try later");
- _exit((log_create(name) < 0)? 1 : 0);
- }
-
-/* If we created a subprocess, wait for it. If it succeeded, try the open. */
+ int sock[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == 0)
+ {
+ const pid_t pid = exim_fork(US"logfile-open");
+ if (pid == 0)
+ {
+ (void)close(sock[0]);
+ if (setgroups(1, &exim_gid) != 0) _exit(EXIT_FAILURE);
+ if (setgid(exim_gid) != 0) _exit(EXIT_FAILURE);
+ if (setuid(exim_uid) != 0) _exit(EXIT_FAILURE);
+
+ if (getuid() != exim_uid || geteuid() != exim_uid) _exit(EXIT_FAILURE);
+ if (getgid() != exim_gid || getegid() != exim_gid) _exit(EXIT_FAILURE);
+
+ fd = log_open_already_exim(name);
+ if (fd < 0) _exit(EXIT_FAILURE);
+ if (log_send_fd(sock[1], fd) != 0) _exit(EXIT_FAILURE);
+ (void)close(sock[1]);
+ _exit(EXIT_SUCCESS);
+ }
-while (pid > 0 && waitpid(pid, &status, 0) != pid);
-if (status == 0) fd = Uopen(name,
-#ifdef O_CLOEXEC
- O_CLOEXEC |
-#endif
- O_APPEND|O_WRONLY, LOG_MODE);
+ (void)close(sock[1]);
+ if (pid > 0)
+ {
+ fd = log_recv_fd(sock[0]);
+ while (waitpid(pid, NULL, 0) == -1 && errno == EINTR);
+ }
+ (void)close(sock[0]);
+ }
+ }
-/* If we failed to create a subprocess, we are in a bad way. We return
-with fd still < 0, and errno set, letting the caller handle the error. */
+if (fd >= 0)
+ {
+ int flags;
+ flags = fcntl(fd, F_GETFD);
+ if (flags != -1) (void)fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ flags = fcntl(fd, F_GETFL);
+ if (flags != -1) (void)fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+ }
+else
+ {
+ errno = EACCES;
+ }
return fd;
}
ok = string_format(buffer, sizeof(buffer), CS file_path, log_names[type]);
-/* Save the name of the mainlog for rollover processing. Without a datestamp,
-it gets statted to see if it has been cycled. With a datestamp, the datestamp
-will be compared. The static slot for saving it is the same size as buffer,
-and the text has been checked above to fit, so this use of strcpy() is OK. */
-
-if (type == lt_main && string_datestamp_offset >= 0)
+switch (type)
{
- Ustrcpy(mainlog_name, buffer);
- mainlog_datestamp = mainlog_name + string_datestamp_offset;
- }
+ case lt_main:
+ /* Save the name of the mainlog for rollover processing. Without a datestamp,
+ it gets statted to see if it has been cycled. With a datestamp, the datestamp
+ will be compared. The static slot for saving it is the same size as buffer,
+ and the text has been checked above to fit, so this use of strcpy() is OK. */
+
+ Ustrcpy(mainlog_name, buffer);
+ if (string_datestamp_offset > 0)
+ mainlog_datestamp = mainlog_name + string_datestamp_offset;
+ break;
-/* Ditto for the reject log */
+ case lt_reject:
+ /* Ditto for the reject log */
-else if (type == lt_reject && string_datestamp_offset >= 0)
- {
- Ustrcpy(rejectlog_name, buffer);
- rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
- }
+ Ustrcpy(rejectlog_name, buffer);
+ if (string_datestamp_offset > 0)
+ rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
+ break;
-/* and deal with the debug log (which keeps the datestamp, but does not
-update it) */
+ case lt_debug:
+ /* and deal with the debug log (which keeps the datestamp, but does not
+ update it) */
-else if (type == lt_debug)
- {
- Ustrcpy(debuglog_name, buffer);
- if (tag)
- {
- /* this won't change the offset of the datestamp */
- ok2 = string_format(buffer, sizeof(buffer), "%s%s",
- debuglog_name, tag);
- if (ok2)
- Ustrcpy(debuglog_name, buffer);
- }
- }
+ Ustrcpy(debuglog_name, buffer);
+ if (tag)
+ {
+ /* this won't change the offset of the datestamp */
+ ok2 = string_format(buffer, sizeof(buffer), "%s%s",
+ debuglog_name, tag);
+ if (ok2)
+ Ustrcpy(debuglog_name, buffer);
+ }
+ break;
-/* Remove any datestamp if this is the panic log. This is rare, so there's no
-need to optimize getting the datestamp length. We remove one non-alphanumeric
-char afterwards if at the start, otherwise one before. */
+ default:
+ /* Remove any datestamp if this is the panic log. This is rare, so there's no
+ need to optimize getting the datestamp length. We remove one non-alphanumeric
+ char afterwards if at the start, otherwise one before. */
-else if (string_datestamp_offset >= 0)
- {
- uschar * from = buffer + string_datestamp_offset;
- uschar * to = from + string_datestamp_length;
+ if (string_datestamp_offset >= 0)
+ {
+ uschar * from = buffer + string_datestamp_offset;
+ uschar * to = from + string_datestamp_length;
- if (from == buffer || from[-1] == '/')
- {
- if (!isalnum(*to)) to++;
- }
- else
- if (!isalnum(from[-1])) from--;
+ if (from == buffer || from[-1] == '/')
+ {
+ if (!isalnum(*to)) to++;
+ }
+ else
+ if (!isalnum(from[-1])) from--;
- /* This copy is ok, because we know that to is a substring of from. But
- due to overlap we must use memmove() not Ustrcpy(). */
- memmove(from, to, Ustrlen(to)+1);
+ /* This copy is ok, because we know that to is a substring of from. But
+ due to overlap we must use memmove() not Ustrcpy(). */
+ memmove(from, to, Ustrlen(to)+1);
+ }
+ break;
}
/* If the file name is too long, it is an unrecoverable disaster */
die(US"exim: log file path too long: aborting",
US"Logging failure; please try later");
-/* We now have the file name. Try to open an existing file. After a successful
-open, arrange for automatic closure on exec(), and then return. */
+/* We now have the file name. After a successful open, return. */
-*fd = Uopen(buffer,
-#ifdef O_CLOEXEC
- O_CLOEXEC |
-#endif
- O_APPEND|O_WRONLY, LOG_MODE);
+*fd = log_open_as_exim(buffer);
if (*fd >= 0)
- {
-#ifndef O_CLOEXEC
- (void)fcntl(*fd, F_SETFD, fcntl(*fd, F_GETFD) | FD_CLOEXEC);
-#endif
return;
- }
-
-/* Open was not successful: try creating the file. If this is a root process,
-we must do the creating in a subprocess set to exim:exim in order to ensure
-that the file is created with the right ownership. Otherwise, there can be a
-race if another Exim process is trying to write to the log at the same time.
-The use of SIGUSR1 by the exiwhat utility can provoke a lot of simultaneous
-writing. */
euid = geteuid();
-/* If we are already running as the Exim user (even if that user is root),
-we can go ahead and create in the current process. */
-
-if (euid == exim_uid) *fd = log_create(buffer);
-
-/* Otherwise, if we are root, do the creation in an exim:exim subprocess. If we
-are neither exim nor root, creation is not attempted. */
-
-else if (euid == root_uid) *fd = log_create_as_exim(buffer);
-
-/* If we now have an open file, set the close-on-exec flag and return. */
-
-if (*fd >= 0)
- {
-#ifndef O_CLOEXEC
- (void)fcntl(*fd, F_SETFD, fcntl(*fd, F_GETFD) | FD_CLOEXEC);
-#endif
- return;
- }
-
/* Creation failed. There are some circumstances in which we get here when
the effective uid is not root or exim, which is the problem. (For example, a
non-setuid binary with log_arguments set, called in certain ways.) Rather than
just bombing out, force the log to stderr and carry on if stderr is available.
*/
-if (euid != root_uid && euid != exim_uid && log_stderr != NULL)
+if (euid != root_uid && euid != exim_uid && log_stderr)
{
*fd = fileno(log_stderr);
return;
/* Otherwise this is a disaster. This call is deliberately ONLY to the panic
log. If possible, save a copy of the original line that was being logged. If we
are recursing (can't open the panic log either), the pointer will already be
-set. */
+set. Also, when we had to use a subprocess for the create we didn't retrieve
+errno from it, so get the error from the open attempt above (which is often
+meaningful enough, so leave it). */
if (!panic_save_buffer)
if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE)))
}
+/* Pull the file out of the configured or the compiled-in list.
+Called for an empty log_file_path element, for debug logging activation
+when file_path has not previously been set, and from the appenfile transport setup. */
-static void
-set_file_path(void)
+void
+set_file_path(BOOL *multiple)
{
+uschar *s;
int sep = ':'; /* Fixed separator - outside use */
-uschar *t;
-const uschar *tt = US LOG_FILE_PATH;
-while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
- {
- if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
- file_path = string_copy(t);
- break;
- }
+const uschar *ss = *log_file_path ? log_file_path : US LOG_FILE_PATH;
+
+if (*ss)
+ for (logging_mode = 0;
+ s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE); )
+ {
+ if (Ustrcmp(s, "syslog") == 0)
+ logging_mode |= LOG_MODE_SYSLOG;
+ else if (!(logging_mode & LOG_MODE_FILE)) /* no file yet */
+ {
+ /* If a non-empty path is given, use it */
+
+ if (*s)
+ file_path = string_copy(s);
+
+ /* If handling the config option, and the element is empty, we want to use
+ the first non-empty, non-syslog item in LOG_FILE_PATH, if there is one,
+ since the value of log_file_path may have been set at runtime. If there is
+ no such item, use the ultimate default in the spool directory. */
+
+ else if (*log_file_path && LOG_FILE_PATH[0])
+ {
+ ss = US LOG_FILE_PATH;
+ continue;
+ }
+
+ logging_mode |= LOG_MODE_FILE;
+ }
+ else
+ if (multiple) *multiple = TRUE;
+ }
+ else
+ logging_mode = LOG_MODE_FILE;
+
+/* Set up the ultimate default if necessary. */
+
+if (logging_mode & LOG_MODE_FILE && !*file_path)
+ file_path = string_sprintf("%s/log/%%slog", spool_directory);
}
void
mainlog_close(void)
{
-if (mainlogfd < 0) return;
+/* avoid closing it if it is closed already or if we do not see a chance
+to open the file mainlog later again */
+if (mainlogfd < 0 /* already closed */
+ || !(geteuid() == 0 || geteuid() == exim_uid))
+ return;
(void)close(mainlogfd);
mainlogfd = -1;
mainlog_inode = 0;
if (!(log_buffer = US malloc(LOG_BUFFER_SIZE)))
{
fprintf(stderr, "exim: failed to get store for log buffer\n");
- exim_exit(EXIT_FAILURE, NULL);
+ exim_exit(EXIT_FAILURE);
}
/* If we haven't already done so, inspect the setting of log_file_path to
/* If nothing has been set, don't waste effort... the default values for the
statics are file_path="" and logging_mode = LOG_MODE_FILE. */
- if (*log_file_path)
- {
- int sep = ':'; /* Fixed separator - outside use */
- uschar *s;
- const uschar *ss = log_file_path;
-
- logging_mode = 0;
- while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
- {
- if (Ustrcmp(s, "syslog") == 0)
- logging_mode |= LOG_MODE_SYSLOG;
- else if (logging_mode & LOG_MODE_FILE)
- multiple = TRUE;
- else
- {
- logging_mode |= LOG_MODE_FILE;
-
- /* If a non-empty path is given, use it */
-
- if (*s)
- file_path = string_copy(s);
-
- /* If the path is empty, we want to use the first non-empty, non-
- syslog item in LOG_FILE_PATH, if there is one, since the value of
- log_file_path may have been set at runtime. If there is no such item,
- use the ultimate default in the spool directory. */
-
- else
- set_file_path(); /* Empty item in log_file_path */
- } /* First non-syslog item in log_file_path */
- } /* Scan of log_file_path */
- }
+ if (*log_file_path) set_file_path(&multiple);
/* If no modes have been selected, it is a major disaster */
die(US"Neither syslog nor file logging set in log_file_path",
US"Unexpected logging failure");
- /* Set up the ultimate default if necessary. Then revert to the old store
- pool, and record that we've sorted out the path. */
+ /* Revert to the old store pool, and record that we've sorted out the path. */
- if (logging_mode & LOG_MODE_FILE && !file_path[0])
- file_path = string_sprintf("%s/log/%%slog", spool_directory);
store_pool = old_pool;
path_inspected = TRUE;
if (flags & LOG_CONFIG) g = log_config_info(g, flags);
+ /* We want to be able to log tainted info, but log_buffer is directly
+ malloc'd. So use deliberately taint-nonchecking routines to build into
+ it, trusting that we will never expand the results. */
+
va_start(ap, format);
i = g->ptr;
- if (!string_vformat(g, FALSE, format, ap))
+ if (!string_vformat(g, SVFMT_TAINT_NOCHK, format, ap))
{
g->ptr = i;
g = string_cat(g, US"**** log string overflowed log buffer ****");
if (f.disable_logging)
{
DEBUG(D_any) debug_printf("log writing disabled\n");
+ if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE) exim_exit(EXIT_FAILURE);
return;
}
va_start(ap, format);
{
int i = g->ptr;
- if (!string_vformat(g, FALSE, format, ap))
+
+ /* We want to be able to log tainted info, but log_buffer is directly
+ malloc'd. So use deliberately taint-nonchecking routines to build into
+ it, trusting that we will never expand the results. */
+
+ if (!string_vformat(g, SVFMT_TAINT_NOCHK, format, ap))
{
g->ptr = i;
g = string_cat(g, US"**** log string overflowed log buffer ****\n");
if ( flags & LOG_SENDER
&& g->ptr < LOG_BUFFER_SIZE - 10 - Ustrlen(raw_sender))
- g = string_fmt_append(g, " from <%s>", raw_sender);
+ g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " from <%s>", raw_sender);
/* Add list of recipients to the message if required; the raw list,
before rewriting, was saved in raw_recipients. There may be none, if an ACL
&& raw_recipients_count > 0)
{
int i;
- g = string_fmt_append(g, " for");
+ g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " for", NULL);
for (i = 0; i < raw_recipients_count; i++)
{
uschar * s = raw_recipients[i];
if (LOG_BUFFER_SIZE - g->ptr < Ustrlen(s) + 3) break;
- g = string_fmt_append(g, " %s", s);
+ g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s", s);
}
}
else
fprintf(log_stderr, "%s", CS log_buffer);
- if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE) exim_exit(EXIT_FAILURE, US"");
+ if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE) exim_exit(EXIT_FAILURE);
return;
}
{
if (header_list && LOGGING(rejected_header))
{
- uschar * p = g->s + g->ptr;
+ gstring * g2;
int i;
if (recipients_count > 0)
{
/* List the sender */
- string_format(p, LOG_BUFFER_SIZE - g->ptr,
- "Envelope-from: <%s>\n", sender_address);
- while (*p) p++;
- g->ptr = p - g->s;
+ g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK,
+ "Envelope-from: <%s>\n", sender_address);
+ if (g2) g = g2;
/* List up to 5 recipients */
- string_format(p, LOG_BUFFER_SIZE - g->ptr,
- "Envelope-to: <%s>\n", recipients_list[0].address);
- while (*p) p++;
- g->ptr = p - g->s;
+ g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK,
+ "Envelope-to: <%s>\n", recipients_list[0].address);
+ if (g2) g = g2;
for (i = 1; i < recipients_count && i < 5; i++)
{
- string_format(p, LOG_BUFFER_SIZE - g->ptr, " <%s>\n",
- recipients_list[i].address);
- while (*p) p++;
- g->ptr = p - g->s;
+ g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK,
+ " <%s>\n", recipients_list[i].address);
+ if (g2) g = g2;
}
if (i < recipients_count)
{
- string_format(p, LOG_BUFFER_SIZE - g->ptr,
- " ...\n");
- while (*p) p++;
- g->ptr = p - g->s;
+ g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " ...\n", NULL);
+ if (g2) g = g2;
}
}
for (header_line * h = header_list; h; h = h->next) if (h->text)
{
- BOOL fitted = string_format(p, LOG_BUFFER_SIZE - g->ptr,
- "%c %s", h->type, h->text);
- while (*p) p++;
- g->ptr = p - g->s;
- if (!fitted) /* Buffer is full; truncate */
+ g2 = string_fmt_append_f(g, SVFMT_TAINT_NOCHK,
+ "%c %s", h->type, h->text);
+ if (g2)
+ g = g2;
+ else /* Buffer is full; truncate */
{
g->ptr -= 100; /* For message and separator */
if (g->s[g->ptr-1] == '\n') g->ptr--;
if (logging_mode & LOG_MODE_FILE)
{
+ if (!*file_path) set_file_path(NULL);
panic_recurseflag = TRUE;
open_log(&paniclogfd, lt_panic, NULL); /* Won't return on failure */
panic_recurseflag = FALSE;
uschar *string, bit_table *options, int count, uschar *which, int flags)
{
uschar *errmsg;
-if (string == NULL) return;
+if (!string) return;
if (*string == '=')
{
char *end; /* Not uschar */
memset(selector, 0, sizeof(*selector)*selsize);
*selector = strtoul(CS string+1, &end, 0);
- if (*end == 0) return;
+ if (!*end) return;
errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which,
string);
goto ERROR_RETURN;
int len;
bit_table *start, *end;
- while (isspace(*string)) string++;
- if (*string == 0) return;
+ Uskip_whitespace(&string);
+ if (!*string) return;
if (*string != '+' && *string != '-')
{
bit_table *middle = start + (end - start)/2;
int c = Ustrncmp(s, middle->name, len);
if (c == 0)
- {
if (middle->name[len] != 0) c = -1; else
{
unsigned int bit = middle->bit;
break; /* Out of loop to match selector name */
}
- }
if (c < 0) end = middle; else start = middle + 1;
} /* Loop to match selector name */
resulting in certain setup not having been done. Hack this for now so we
do not segfault; note that nondefault log locations will not work */
-if (!*file_path) set_file_path();
+if (!*file_path) set_file_path(NULL);
open_log(&fd, lt_debug, tag_name);
unlink_log(lt_debug);
}
+/* Called from the appendfile transport setup. */
+void
+open_logs(void)
+{
+set_file_path(NULL);
+if (!(logging_mode & LOG_MODE_FILE)) return;
+open_log(&mainlogfd, lt_main, 0);
+open_log(&rejectlogfd, lt_reject, 0);
+}
/* End of log.c */