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