-/* Inspired by OpenSSH's mm_send_fd(). Thanks! */
+/* Inspired by OpenSSH's mm_send_fd(). Thanks!
+Send fd over socketpair.
+Return: true iff good.
+*/
-static int
+static BOOL
log_send_fd(const int sock, const int fd)
{
struct msghdr msg;
char buf[CMSG_SPACE(sizeof(int))];
} cmsgbuf;
struct cmsghdr *cmsg;
-struct iovec vec;
char ch = 'A';
+struct iovec vec = {.iov_base = &ch, .iov_len = 1};
ssize_t n;
memset(&msg, 0, sizeof(msg));
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;
+return n == 1;
}
-/* Inspired by OpenSSH's mm_receive_fd(). Thanks! */
+/* Inspired by OpenSSH's mm_receive_fd(). Thanks!
+Return fd passed over socketpair, or -1 on error.
+*/
static int
log_recv_fd(const int sock)
char buf[CMSG_SPACE(sizeof(int))];
} cmsgbuf;
struct cmsghdr *cmsg;
-struct iovec vec;
-ssize_t n;
char ch = '\0';
-int fd = -1;
+struct iovec vec = {.iov_base = &ch, .iov_len = 1};
+ssize_t n;
+int fd;
memset(&msg, 0, sizeof(msg));
-vec.iov_base = &ch;
-vec.iov_len = 1;
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_control = &cmsgbuf.buf;
msg.msg_controllen = sizeof(cmsgbuf.buf);
-while ((n = recvmsg(sock, &msg, 0)) == -1 && errno == EINTR);
+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_FIRSTHDR(&msg))) return -1;
if (cmsg->cmsg_type != SCM_RIGHTS) return -1;
-fd = *(const int *)CMSG_DATA(cmsg);
-if (fd < 0) return -1;
+if ((fd = *(const int *)CMSG_DATA(cmsg)) < 0) return -1;
return fd;
}
const uid_t euid = geteuid();
if (euid == exim_uid)
- {
fd = log_open_already_exim(name);
- }
else if (euid == root_uid)
{
int sock[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == 0)
{
- const pid_t pid = exim_fork(US"logfile-open");
+ const pid_t pid = fork();
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 ( setgroups(1, &exim_gid) != 0
+ || setgid(exim_gid) != 0
+ || setuid(exim_uid) != 0
- if (getuid() != exim_uid || geteuid() != exim_uid) _exit(EXIT_FAILURE);
- if (getgid() != exim_gid || getegid() != exim_gid) _exit(EXIT_FAILURE);
+ || getuid() != exim_uid || geteuid() != exim_uid
+ || getgid() != exim_gid || getegid() != exim_gid
- fd = log_open_already_exim(name);
- if (fd < 0) _exit(EXIT_FAILURE);
- if (log_send_fd(sock[1], fd) != 0) _exit(EXIT_FAILURE);
+ || (fd = log_open_already_exim(name)) < 0
+ || !log_send_fd(sock[1], fd)
+ ) _exit(EXIT_FAILURE);
(void)close(sock[1]);
_exit(EXIT_SUCCESS);
}
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)
- {
- Ustrcpy(mainlog_name, buffer);
- if (string_datestamp_offset > 0)
- mainlog_datestamp = mainlog_name + string_datestamp_offset;
- }
-
-/* Ditto for the reject log */
-
-else if (type == lt_reject)
+switch (type)
{
- Ustrcpy(rejectlog_name, buffer);
- if (string_datestamp_offset > 0)
- rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
- }
-
-/* 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);
- }
- }
-
-/* 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;
+ 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;
+ case lt_reject:
+ /* Ditto for the reject log */
+ Ustrcpy(rejectlog_name, buffer);
+ if (string_datestamp_offset > 0)
+ rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
+ case lt_debug:
+ /* and deal with the debug log (which keeps the datestamp, but does not
+ update it) */
+ 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);
+ }
+ 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. */
+ 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);
+ }
}
/* If the file name is too long, it is an unrecoverable disaster */
}
-
-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)))
+const uschar *ss = *log_file_path ? log_file_path : US LOG_FILE_PATH;
+
+logging_mode = 0;
+while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
{
- if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
- file_path = string_copy(t);
- break;
+ if (Ustrcmp(s, "syslog") == 0)
+ logging_mode |= LOG_MODE_SYSLOG;
+ else if (logging_mode & LOG_MODE_FILE) /* we know a file already */
+ {
+ if (multiple) *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. */
+ }
}
}
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 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 */
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);
}
+void
+open_logs(void)
+{
+set_file_path(NULL);
+open_log(&mainlogfd, lt_main, 0);
+open_log(&rejectlogfd, lt_reject, 0);
+}
/* End of log.c */