service-process.c revision 41ee23907b084da5baed459e35bccd5a33430419
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "common.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "array.h"
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen#include "aqueue.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ioloop.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "istream.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ostream.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "write-full.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "base64.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "hash.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "str.h"
2cd2518bab14292a67cf8a490b58ab9ef89879daTimo Sirainen#include "strescape.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "llist.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "hostpid.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "env-util.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "fd-close-on-exec.h"
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen#include "restrict-access.h"
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen#include "restrict-process-size.h"
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen#include "eacces-error.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-service.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-service-settings.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "dup2-array.h"
cf2e6953d03a1c22f272ec19432fc03c136ac1bbTimo Sirainen#include "service.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-anvil.h"
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen#include "service-listen.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-log.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-process-notify.h"
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen#include "service-process.h"
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <fcntl.h>
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen#include <syslog.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <signal.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <sys/wait.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_reopen_inet_listeners(struct service *service)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct service_listener *const *listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int old_fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen listeners = array_get(&service->listeners, &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!listeners[i]->reuse_port || listeners[i]->fd == -1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_fd = listeners[i]->fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen listeners[i]->fd = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service_listener_listen(listeners[i]) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen listeners[i]->fd = old_fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic void
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenservice_dup_fds(struct service *service)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen struct service_listener *const *listeners;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen ARRAY_TYPE(dup2) dups;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen string_t *listener_settings;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen int fd = MASTER_LISTEN_FD_FIRST;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen unsigned int i, count, socket_listener_count;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
230ef558135f16a66b86cbe3762524eaa9ae9d81Timo Sirainen /* stdin/stdout is already redirected to /dev/null. Other master fds
230ef558135f16a66b86cbe3762524eaa9ae9d81Timo Sirainen should have been opened with fd_close_on_exec() so we don't have to
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen worry about them.
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen because the destination fd might be another one's source fd we have
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen to be careful not to overwrite anything. dup() the fd when needed */
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen socket_listener_count = 0;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen listeners = array_get(&service->listeners, &count);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen t_array_init(&dups, count + 10);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen switch (service->type) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen case SERVICE_TYPE_LOG:
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen i_assert(fd == MASTER_LISTEN_FD_FIRST);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen services_log_dup2(&dups, service->list, fd,
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen &socket_listener_count);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen fd += socket_listener_count;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen break;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen case SERVICE_TYPE_ANVIL:
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dup2_append(&dups, service_anvil_global->log_fdpass_fd[0],
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen MASTER_ANVIL_LOG_FDPASS_FD);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* nonblocking anvil fd must be the first one. anvil treats it
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen as the master's fd */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen socket_listener_count += 2;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen break;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen default:
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen break;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* add listeners */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen listener_settings = t_str_new(256);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen for (i = 0; i < count; i++) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (listeners[i]->fd != -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_truncate(listener_settings, 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append_tabescaped(listener_settings, listeners[i]->name);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (listeners[i]->type == SERVICE_LISTENER_INET) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (listeners[i]->set.inetset.set->ssl)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen str_append(listener_settings, "\tssl");
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen if (listeners[i]->set.inetset.set->haproxy)
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen str_append(listener_settings, "\thaproxy");
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen }
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen dup2_append(&dups, listeners[i]->fd, fd++);
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s",
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen socket_listener_count, str_c(listener_settings)));
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen socket_listener_count++;
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen }
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen }
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->login_notify_fd != -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service->login_notify_fd,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MASTER_LOGIN_NOTIFY_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (service->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_LOG:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_ANVIL:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_CONFIG:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, dev_null_fd, MASTER_ANVIL_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_UNKNOWN:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_LOGIN:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_STARTUP:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service_anvil_global->blocking_fd[1],
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MASTER_ANVIL_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->type != SERVICE_TYPE_ANVIL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service->master_dead_pipe_fd[1],
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MASTER_DEAD_FD);
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, global_master_dead_pipe_fd[1],
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MASTER_DEAD_FD);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->type == SERVICE_TYPE_LOG) {
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen /* keep stderr as-is. this is especially important when
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen log_path=/dev/stderr, but might be helpful even in other
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen situations for logging startup errors */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen /* set log file to stderr. dup2() here immediately so that
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen we can set up logging to it without causing any log messages
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen to be lost. */
614529ee060755c0b282102b70daf56bcd64222dTimo Sirainen i_assert(service->log_fd[1] != -1);
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen env_put("LOG_SERVICE=1");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("dup2(log fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_internal();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* make sure we don't leak syslog fd. try to do it as late as possible,
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen but also before dup2()s in case syslog fd is one of them. */
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen closelog();
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen if (dup2_array(&dups) < 0)
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen i_fatal("service(%s): dup2s failed", service->set->name);
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(fd == MASTER_LISTEN_FD_FIRST + (int)socket_listener_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainendrop_privileges(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen struct restrict_access_settings rset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool disallow_root;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int len;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->vsz_limit != 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen restrict_process_size(service->vsz_limit);
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen restrict_access_init(&rset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.uid = service->uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.gid = service->gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.privileged_gid = service->privileged_gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.chroot_dir = *service->set->chroot == '\0' ? NULL :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->set->chroot;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (rset.chroot_dir != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* drop trailing / if it exists */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen len = strlen(rset.chroot_dir);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (rset.chroot_dir[len-1] == '/')
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.chroot_dir = t_strndup(rset.chroot_dir, len-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.extra_groups = service->extra_gids;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen restrict_access_set_env(&rset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->set->drop_priv_before_exec) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen disallow_root = service->type == SERVICE_TYPE_LOGIN;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen restrict_access(&rset, NULL, disallow_root);
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_setup_config_environment(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct master_service_settings *set = service->list->service_set;
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (service->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_CONFIG:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen service->config_file_path, NULL));
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen break;
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen case SERVICE_TYPE_LOG:
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen /* give the log's configuration directly, so it won't depend
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen on config process */
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen env_put("DOVECONF_ENV=1");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("LOG_PATH=", set->log_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("INFO_LOG_PATH=", set->info_log_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("DEBUG_LOG_PATH=", set->debug_log_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("LOG_TIMESTAMP=", set->log_timestamp, NULL));
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen env_put(t_strconcat("SYSLOG_FACILITY=", set->syslog_facility, NULL));
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen if (set->verbose_proctitle)
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen env_put("VERBOSE_PROCTITLE=1");
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen env_put("SSL=no");
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen break;
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen default:
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services_get_config_socket_path(service->list), NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainenstatic void
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainenservice_process_setup_environment(struct service *service, unsigned int uid,
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen const char *hostdomain)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen master_service_env_clean();
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(MASTER_IS_PARENT_ENV"=1");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_setup_config_environment(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_CLIENT_LIMIT_ENV"=%u",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->client_limit));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen env_put(t_strdup_printf(MASTER_PROCESS_LIMIT_ENV"=%u",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_limit));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_PROCESS_MIN_AVAIL_ENV"=%u",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->set->process_min_avail));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_SERVICE_IDLE_KILL_ENV"=%u",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->idle_kill));
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (service->set->service_count != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_SERVICE_COUNT_ENV"=%u",
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen service->set->service_count));
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen }
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen env_put(t_strdup_printf(MASTER_UID_ENV"=%u", uid));
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen env_put(t_strdup_printf(MY_HOSTNAME_ENV"=%s", my_hostname));
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen env_put(t_strdup_printf(MY_HOSTDOMAIN_ENV"=%s", hostdomain));
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!service->set->master_set->version_ignore)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen env_put(MASTER_DOVECOT_VERSION_ENV"="PACKAGE_VERSION);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (ssl_manual_key_password != NULL && service->have_inet_listeners) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen /* manually given SSL password. give it only to services
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen that have inet listeners. */
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen env_put(t_strconcat(MASTER_SSL_KEY_PASSWORD_ENV"=",
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen ssl_manual_key_password, NULL));
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen }
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (service->type == SERVICE_TYPE_ANVIL &&
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen service_anvil_global->restarted)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put("ANVIL_RESTARTED=1");
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_status_timeout(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_error(process->service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Initial status notification not received in %d "
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "seconds, killing the process",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen SERVICE_FIRST_STATUS_TIMEOUT_SECS);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (kill(process->pid, SIGKILL) < 0 && errno != ESRCH) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_error(process->service, "kill(%s, SIGKILL) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dec2str(process->pid));
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen }
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen timeout_remove(&process->to_status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct service_process *service_process_create(struct service *service)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen{
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen static unsigned int uid_counter = 0;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen struct service_process *process;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen unsigned int uid = ++uid_counter;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen const char *hostdomain;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pid_t pid;
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen bool process_forked;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->status_fd[0] != -1);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->to_throttle != NULL) {
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen /* throttling service, don't create new processes */
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen return NULL;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen }
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (service->list->destroying) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen /* these services are being destroyed, no point in creating
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen new processes now */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* look this up before fork()ing so that it gets cached for all the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen future lookups. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hostdomain = my_hostdomain();
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->type == SERVICE_TYPE_ANVIL &&
2cd2518bab14292a67cf8a490b58ab9ef89879daTimo Sirainen service_anvil_global->pid != 0) {
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen pid = service_anvil_global->pid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uid = service_anvil_global->uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process_forked = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pid = fork();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process_forked = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->list->fork_counter++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (pid < 0) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen service_error(service, "fork() failed: %m");
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return NULL;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (pid == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* child */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_setup_environment(service, uid, hostdomain);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service_reopen_inet_listeners(service);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service_dup_fds(service);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen drop_privileges(service);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen process_exec(service->executable, NULL);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen i_assert(hash_table_lookup(service_pids, POINTER_CAST(pid)) == NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process = i_new(struct service_process, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->service = service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->refcount = 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->pid = pid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->uid = uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process_forked) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->to_status =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_add(SERVICE_FIRST_STATUS_TIMEOUT_SECS * 1000,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_status_timeout, process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->available_count = service->client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_count++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_avail++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen DLLIST_PREPEND(&service->processes, process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_list_ref(service->list);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_insert(service_pids, POINTER_CAST(process->pid), process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->type == SERVICE_TYPE_ANVIL && process_forked)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_anvil_process_created(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return process;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_destroy(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = process->service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_list *service_list = service->list;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen DLLIST_REMOVE(&service->processes, process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_remove(service_pids, POINTER_CAST(process->pid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
614529ee060755c0b282102b70daf56bcd64222dTimo Sirainen if (process->available_count > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_avail--;
a3dcda4b01461c7690c655a013ec12851cdb78d4Timo Sirainen service->process_count--;
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen i_assert(service->process_avail <= service->process_count);
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process->to_status != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_remove(&process->to_status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process->to_idle != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_remove(&process->to_idle);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->list->log_byes != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_notify_add(service->list->log_byes, process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->destroyed = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_unref(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
129db31de1780783a175633eba5811e44c361a81Timo Sirainen if (service->process_count < service->process_limit &&
129db31de1780783a175633eba5811e44c361a81Timo Sirainen service->type == SERVICE_TYPE_LOGIN)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_login_notify(service, FALSE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_list_unref(service_list);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_ref(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(process->refcount > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->refcount++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_unref(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(process->refcount > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (--process->refcount > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
63849db64682675a2fd3e1aea05c10ecbc6d473aTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(process->destroyed);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_free(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic const char *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenget_exit_status_message(struct service *service, enum fatal_exit_status status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen string_t *str;
63849db64682675a2fd3e1aea05c10ecbc6d473aTimo Sirainen
129db31de1780783a175633eba5811e44c361a81Timo Sirainen switch (status) {
129db31de1780783a175633eba5811e44c361a81Timo Sirainen case FATAL_LOGOPEN:
63849db64682675a2fd3e1aea05c10ecbc6d473aTimo Sirainen return "Can't open log file";
63849db64682675a2fd3e1aea05c10ecbc6d473aTimo Sirainen case FATAL_LOGWRITE:
63849db64682675a2fd3e1aea05c10ecbc6d473aTimo Sirainen return "Can't write to log file";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_LOGERROR:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Internal logging error";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_OUTOFMEM:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str = t_str_new(128);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, "Out of memory");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->vsz_limit != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (service %s { vsz_limit=%u MB }, "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "you may need to increase it)",
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen service->set->name,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (unsigned int)(service->vsz_limit/1024/1024));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv("CORE_OUTOFMEM") == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, " - set CORE_OUTOFMEM=1 environment to get core dump");
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen return str_c(str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_EXEC:
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen return "exec() failed";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_DEFAULT:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Fatal failure";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenlog_coredump(struct service *service, string_t *str, int status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#ifdef WCOREDUMP
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int signum = WTERMSIG(status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (WCOREDUMP(status) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, " (core dumped)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (signum != SIGABRT && signum != SIGSEGV && signum != SIGBUS)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* let's try to figure out why we didn't get a core dump */
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen if (core_dumps_disabled) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (core dumps disabled)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#ifndef HAVE_PR_SET_DUMPABLE
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!service->set->drop_priv_before_exec && service->uid != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (core not dumped - set service %s "
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen "{ drop_priv_before_exec=yes })",
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen service->set->name);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*service->set->privileged_group != '\0' && service->uid != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (core not dumped - service %s "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "{ privileged_group } prevented it)",
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen service->set->name);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen#else
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (!service->set->login_dump_core &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->type == SERVICE_TYPE_LOGIN) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen str_printfa(str, " (core not dumped - add -D parameter to "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "service %s { executable }", service->set->name);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->set->chroot[0] != '\0') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (core not dumped - try to clear "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "service %s { chroot = } )", service->set->name);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, " (core not dumped)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#endif
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainenstatic void
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainenservice_process_get_status_error(string_t *str, struct service_process *process,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int status, bool *default_fatal_r)
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = process->service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *msg;
*default_fatal_r = FALSE;
str_printfa(str, "service(%s): child %s ", service->set->name,
dec2str(process->pid));
if (WIFSIGNALED(status)) {
str_printfa(str, "killed with signal %d", WTERMSIG(status));
log_coredump(service, str, status);
return;
}
if (!WIFEXITED(status)) {
str_printfa(str, "died with status %d", status);
return;
}
status = WEXITSTATUS(status);
if (status == 0) {
str_truncate(str, 0);
return;
}
str_printfa(str, "returned error %d", status);
msg = get_exit_status_message(service, status);
if (msg != NULL)
str_printfa(str, " (%s)", msg);
if (status == FATAL_DEFAULT)
*default_fatal_r = TRUE;
}
static void service_process_log(struct service_process *process,
bool default_fatal, const char *str)
{
const char *data;
if (process->service->log_fd[1] == -1) {
i_error("%s", str);
return;
}
/* log it via the log process in charge of handling
this process's logging */
data = t_strdup_printf("%d %s %s %s\n",
process->service->log_process_internal_fd,
dec2str(process->pid),
default_fatal ? "DEFAULT-FATAL" : "FATAL", str);
if (write(process->service->list->master_log_fd[1],
data, strlen(data)) < 0) {
i_error("write(log process) failed: %m");
i_error("%s", str);
}
}
void service_process_log_status_error(struct service_process *process,
int status)
{
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
/* fast path */
return;
}
T_BEGIN {
string_t *str = t_str_new(256);
bool default_fatal;
service_process_get_status_error(str, process, status,
&default_fatal);
if (str_len(str) > 0)
service_process_log(process, default_fatal, str_c(str));
} T_END;
}