main.c revision 4c2ac2804213f22edb4fe8ce12af709c7571bdf0
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenconst char *process_names[PROCESS_TYPE_MAX] = {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "auth-worker",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "ssl-build-param",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic const char *configfile = SYSCONFDIR "/" PACKAGE ".conf";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic const char *env_tz;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void listen_fds_close(struct server_settings *server);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool validate_str(const char *str, size_t max_len)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < max_len; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* remove all environment, we don't need them */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we'll log through master process */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen !syslog_facility_find(settings_root->defaults->syslog_facility,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf("SYSLOG_FACILITY=%d", facility));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (settings_root != NULL && !settings_root->defaults->version_ignore)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid client_process_exec(const char *cmd, const char *title)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* very simple argument splitting. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen argv = t_strsplit(t_strconcat(cmd, " ", title, NULL), " ");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* hide the path, it's ugly */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!syslog_facility_find(set->syslog_facility, &facility))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* log to file or stderr */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_timestamp_format(set->log_timestamp);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void settings_reload(void)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct server_settings *old_set = settings_root;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_warning("SIGHUP received - reloading configuration");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* restart auth and login processes */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!master_settings_read(configfile, FALSE, FALSE))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_warning("Invalid configuration, keeping old one");
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainenstatic void sig_die(int signo, void *context __attr_unused__)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen which is too common at least while testing :) */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void sig_reload_settings(int signo __attr_unused__,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void sig_reopen_logs(int signo __attr_unused__,
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainenstatic const char *get_exit_status_message(enum fatal_exit_status status)
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen return "Can't open log file";
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen return "Can't write to log file";
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen return "Internal logging error";
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen return "Out of memory";
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen return "exec() failed";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void sigchld_handler(int signo __attr_unused__,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* get the type and remove from hash */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* write errors to syslog */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process_type_name = process_names[process_type];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("child %s (%s) killed with signal %d",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (pid == -1 && errno != EINTR && errno != ECHILD)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void resolve_ip(const char *set_name, const char *name,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *p;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* defaults to "*" or "[::]" */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* IPv6 address */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*p == '\0')
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else if (*p != ':') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("%s: Invalid data after ']' in address %s",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* IPv4 any */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* IPv6 any */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* Return the first IP if there happens to be multiple. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = net_gethostbyname(name, &ip_list, &ips_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("%s: No IPs for address: %s", set_name, name);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainencheck_conflicts_set(const struct settings *set, const struct ip_addr *ip,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int port, const char *name1, const char *name2)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (set->listen_port == port && net_ip_compare(ip, &set->listen_ip) &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("Protocols %s and %s are listening in same ip/port",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen net_ip_compare(ip, &set->ssl_listen_ip) && set->ssl_listen_fd > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("Protocols %ss and %s are listening in same ip/port",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void check_conflicts(const struct ip_addr *ip, unsigned int port,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (server = settings_root; server != NULL; server = server->next) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void listen_protocols(struct settings *set, bool retry)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *proto;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int port;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen set->listen_port = set->protocol == MAIL_PROTOCOL_IMAP ? 143 : 110;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen set->ssl_listen_port = set->protocol == MAIL_PROTOCOL_IMAP ? 993 : 995;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* resolve */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen resolve_ip("listen", set->listen, &set->listen_ip, &set->listen_port);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen resolve_ip("ssl_listen", set->ssl_listen, &set->ssl_listen_ip,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* if ssl_listen wasn't explicitly set in the config file,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen use the non-ssl IP settings for the ssl listener, too. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (set->ssl_listen_ip.family == 0 && *set->ssl_listen == '\0')
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* register wanted protocols */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen proto = t_strsplit_spaces(set->protocols, " ");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (strcasecmp(*proto, "imaps") == 0) {
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen } else if (strcasecmp(*proto, "pop3s") == 0) {
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen i_fatal("Protocol %s given more than once", *proto);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < 10; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* SIGHUPing sometimes gets us here.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen we don't want to die. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* wait a while and try again. we're SIGHUPing
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen so we most likely just closed it ourself.. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (server = settings_root; server != NULL; server = server->next) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void listen_fds_close(struct server_settings *server)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (; server != NULL; server = server->next) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("close(imap.ssl_listen_fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("close(pop3.ssl_listen_fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool have_stderr_set(struct settings *set)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen strcmp(set->info_log_path, "/dev/stderr") == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool have_stderr(struct server_settings *server)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (server->imap != NULL && have_stderr_set(server->imap))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (server->pop3 != NULL && have_stderr_set(server->pop3))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void open_fds(void)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* initialize fds. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* make sure all fds between 0..3 are used. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* close stdin and stdout. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *pid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pid = t_strconcat(dec2str(getpid()), "\n", NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* deny file access from everyone else except owner */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* close stderr unless we're logging into /dev/stderr. keep as little
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen distance between closing it and opening the actual log file so that
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen we don't lose anything. */
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lib_signals_set_handler(SIGHUP, TRUE, sig_reload_settings, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lib_signals_set_handler(SIGUSR1, TRUE, sig_reopen_logs, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pids = hash_create(default_pool, default_pool, 128, NULL, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lib_signals_set_handler(SIGCHLD, TRUE, sigchld_handler, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen create_pid_file(t_strconcat(settings_root->defaults->base_dir,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void main_deinit(void)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)unlink(t_strconcat(settings_root->defaults->base_dir,
ssl_deinit();
log_deinit();
closelog();
if (pid < 0)
if (pid != 0)
_exit(0);
if (setsid() < 0)
static void print_help(void)
static void print_build_options(void)
#ifdef IOLOOP_EPOLL
#ifdef IOLOOP_KQUEUE
#ifdef IOLOOP_POLL
#ifdef IOLOOP_SELECT
#ifdef IOLOOP_NOTIFY_DNOTIFY
#ifdef IOLOOP_NOTIFY_INOTIFY
#ifdef IOLOOP_NOTIFY_KQUEUE
#ifdef HAVE_IPV6
#ifdef HAVE_GNUTLS
#ifdef HAVE_OPENSSL
#ifdef BUILD_MYSQL
#ifdef BUILD_PGSQL
#ifdef BUILD_SQLITE
#ifdef PASSDB_BSDAUTH
#ifdef PASSDB_CHECKPASSWORD
#ifdef PASSDB_LDAP
#ifdef PASSDB_PAM
#ifdef PASSDB_PASSWD
#ifdef PASSDB_PASSWD_FILE
#ifdef PASSDB_SHADOW
#ifdef PASSDB_SQL
#ifdef PASSDB_VPOPMAIL
#ifdef USERDB_CHECKPASSWORD
#ifdef USERDB_LDAP
#ifdef USERDB_PASSWD
#ifdef USERDB_PREFETCH
#ifdef USERDB_PASSWD_FILE
#ifdef USERDB_SQL
#ifdef USERDB_STATIC
#ifdef USERDB_VPOPMAIL
#ifdef DEBUG
lib_init();
print_help();
if (dump_config) {
t_push();
t_pop();
if (dump_config) {
if (ask_key_pass) {
const char *prompt;
t_push();
sizeof(ssl_manual_key_password));
t_pop();
env_clean();
open_fds();
if (!foreground)
main_deinit();
lib_deinit();