/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "ioloop.h"
#include "lib-signals.h"
#include "array.h"
#include "write-full.h"
#include "env-util.h"
#include "hostpid.h"
#include "path-util.h"
#include "ipwd.h"
#include "str.h"
#include "execv-const.h"
#include "restrict-process-size.h"
#include "master-instance.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "askpass.h"
#include "capabilities.h"
#include "master-client.h"
#include "service.h"
#include "service-anvil.h"
#include "service-listen.h"
#include "service-monitor.h"
#include "service-process.h"
#include "service-log.h"
#include "dovecot-version.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
struct master_delayed_error {
const char *line;
};
bool core_dumps_disabled;
const char *ssl_manual_key_password;
static char *pidfile_path;
};
{
executable = argv[0];
/* hide the path, it's ugly */
/* prefix with dovecot/ */
argv[0]);
}
const char **error_r)
{
if (*user == '\0') {
return 0;
}
case -1:
return -1;
case 0:
return -1;
default:
return 0;
}
}
{
if (*group == '\0') {
return 0;
}
case -1:
return -1;
case 0:
return -1;
default:
return 0;
}
}
{
int fd;
/* if we already forked a child process, this isn't fatal for the
main process and there's no need to write the fatal file. */
i_unreached();
/* write the error message to a file (we're chdired to
base dir) */
if (fd != -1) {
i_close_fd(&fd);
}
}
abort(); /* just to silence the noreturn attribute warnings */
}
{
abort();
}
static void ATTR_FORMAT(2, 0)
{
}
static void ATTR_FORMAT(2, 0)
{
if (delayed_errors_pool == NULL) {
}
}
static void startup_early_errors_flush(void)
{
if (delayed_errors_pool == NULL)
return;
}
}
{
const char *path;
int fd;
if (fd == -1)
return;
if (ret < 0)
else {
"information): %s\n", buf);
}
i_close_fd(&fd);
}
{
int fd;
bool found;
if (fd == -1) {
return FALSE;
}
if (ret <= 0) {
if (ret == 0)
else
} else {
ret--;
i_error("PID file contains invalid PID value");
} else {
}
}
i_close_fd(&fd);
return found;
}
{
return;
i_fatal("Dovecot is already running with PID %s "
}
{
const char *pid;
int fd;
if (fd == -1)
i_close_fd(&fd);
}
{
const char *base_config_path;
i_error("symlink(%s, %s) failed: %m",
}
}
{
int ret;
if (ret == 0) {
/* duplicate instance names. allow without warning.. */
}
}
{
const char *path;
}
static void
void *context ATTR_UNUSED)
{
void **sets;
const char *error;
i_warning("SIGHUP received - reloading configuration");
/* see if hostname changed */
hostpid_init();
/* we can't reload config if there's no config process. */
i_error("Can't reload configuration because "
"we couldn't create a config process");
return;
}
}
return;
}
/* new configuration is invalid, keep the old */
return;
}
/* switch to new configuration. */
return;
}
/* anvil never dies. it just gets moved to the new services list */
}
}
static void
{
unsigned int uninitialized_count;
}
static void
{
}
{
i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
/* make sure new processes won't be created by the currently
running ioloop. */
}
{
const char *error;
&error) < 0)
return master_service_settings_get_others(master_service)[0];
}
{
else {
}
core_limit == 0;
if (core_dumps_disabled)
}
static void master_set_process_limit(void)
{
unsigned int process_limit = 0;
/* we'll just count all the processes that can exist and set the
process limit so that we won't reach it. it's usually higher than
needed, since we'd only need to set it high enough for each
separate UID not to reach the limit, but this is difficult to
guess: mail processes should probably be counted together for a
common vmail user (unless system users are being used), but
we can't really guess what the mail processes are. */
if (restrict_get_process_limit(&nproc) == 0 &&
}
{
/* deny file access from everyone else except owner */
(void)umask(0077);
}
static void global_dead_pipe_close(void)
{
if (close(global_master_dead_pipe_fd[0]) < 0)
i_error("close(global dead pipe) failed: %m");
i_error("close(global dead pipe) failed: %m");
global_master_dead_pipe_fd[0] = -1;
}
static void main_deinit(void)
{
/* kill services and wait for them to die before unlinking pid file */
}
{
const char *path;
if (*path == '/')
return path;
}
}
{
return;
/* time moved backwards. disable launching new service processes
until */
}
static void daemonize(void)
{
if (pid < 0)
i_fatal("fork() failed: %m");
if (pid != 0)
_exit(0);
if (setsid() < 0)
i_fatal("setsid() failed: %m");
/* update my_pid */
hostpid_init();
}
static void print_help(void)
{
"Usage: dovecot [-F] [-c <config file>] [-p] [-n] [-a] [--help] [--version]\n"
" [--build-options] [--hostdomain] [reload] [stop]\n");
}
static void print_build_options(void)
{
printf("Build options:"
#ifdef IOLOOP_EPOLL
" ioloop=epoll"
#endif
#ifdef IOLOOP_KQUEUE
" ioloop=kqueue"
#endif
#ifdef IOLOOP_POLL
" ioloop=poll"
#endif
#ifdef IOLOOP_SELECT
" ioloop=select"
#endif
#ifdef IOLOOP_NOTIFY_INOTIFY
" notify=inotify"
#endif
#ifdef IOLOOP_NOTIFY_KQUEUE
" notify=kqueue"
#endif
#ifdef HAVE_GNUTLS
" gnutls"
#endif
#ifdef HAVE_OPENSSL
" openssl"
#endif
" io_block_size=%u"
#ifdef SQL_DRIVER_PLUGINS
"\nSQL driver plugins:"
#else
"\nSQL drivers:"
#endif
#ifdef BUILD_CASSANDRA
" cassandra"
#endif
#ifdef BUILD_MYSQL
" mysql"
#endif
#ifdef BUILD_PGSQL
" postgresql"
#endif
#ifdef BUILD_SQLITE
" sqlite"
#endif
"\nPassdb:"
#ifdef PASSDB_BSDAUTH
" bsdauth"
#endif
#ifdef PASSDB_CHECKPASSWORD
" checkpassword"
#endif
#ifdef PASSDB_LDAP
" ldap"
#endif
#ifdef PASSDB_PAM
" pam"
#endif
#ifdef PASSDB_PASSWD
" passwd"
#endif
#ifdef PASSDB_PASSWD_FILE
" passwd-file"
#endif
#ifdef PASSDB_SHADOW
" shadow"
#endif
#ifdef PASSDB_SQL
" sql"
#endif
#ifdef PASSDB_VPOPMAIL
" vpopmail"
#endif
"\nUserdb:"
#ifdef USERDB_CHECKPASSWORD
" checkpassword"
#endif
#ifdef USERDB_LDAP
" ldap"
#ifndef BUILTIN_LDAP
"(plugin)"
#endif
#endif
#ifdef USERDB_NSS
" nss"
#endif
#ifdef USERDB_PASSWD
" passwd"
#endif
#ifdef USERDB_PREFETCH
" prefetch"
#endif
#ifdef USERDB_PASSWD_FILE
" passwd-file"
#endif
#ifdef USERDB_SQL
" sql"
#endif
#ifdef USERDB_STATIC
" static"
#endif
#ifdef USERDB_VPOPMAIL
" vpopmail"
#endif
"\n", IO_BLOCK_SIZE);
}
{
int i, c;
#ifdef DEBUG
#endif
/* drop -- prefix from all --args. ugly, but the only way that it
works with standard getopt() in all OSes.. */
for (i = 1; i < argc; i++) {
break;
argv[i] += 2;
doubleopts[i] = TRUE;
} else {
doubleopts[i] = FALSE;
}
}
master_uid = geteuid();
master_gid = getegid();
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'F':
foreground = TRUE;
break;
case 'a':
doveconf_arg = "-a";
break;
case 'n':
doveconf_arg = "-n";
break;
case 'p':
/* Ask SSL private key password */
ask_key_pass = TRUE;
break;
default:
c, optarg)) {
print_help();
}
break;
}
}
if (doveconf_arg != NULL) {
const char **args;
args[0] = DOVECOT_CONFIG_BIN_PATH;
}
/* starting Dovecot */
} else if (!doubleopts[optind]) {
/* dovecot xx -> doveadm xx */
return 0;
return 0;
return 0;
print_help();
return 0;
} else {
print_help();
}
if (pipe(global_master_dead_pipe_fd) < 0)
i_fatal("pipe() failed: %m");
set = master_settings_read();
if (ask_key_pass) {
t_askpass("Give the password for SSL keys: ");
}
i_fatal("dup2(dev_null_fd) failed: %m");
i_fatal("dup2(dev_null_fd) failed: %m");
/* create service structures from settings. if there are any errors in
service configuration we'll catch it here. */
/* if any listening fails, fail completely */
if (services_listen(services) <= 0)
i_fatal("Failed to start listeners");
if (!foreground)
daemonize();
T_BEGIN {
} T_END;
main_deinit();
return 0;
}