main.c revision 7df48840258676571b69d91d532d3d6b627db420
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen/* Copyright (C) 2002 Timo Sirainen */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "common.h"
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#include "ioloop.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "lib-signals.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "network.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "env-util.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "fd-close-on-exec.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "write-full.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "auth-process.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "login-process.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "mail-process.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "ssl-init.h"
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#include "log.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen#include <stdio.h>
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen#include <stdlib.h>
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#include <unistd.h>
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include <fcntl.h>
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#include <syslog.h>
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#include <sys/stat.h>
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#include <sys/wait.h>
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenconst char *process_names[PROCESS_TYPE_MAX] = {
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen "unknown",
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen "auth",
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen "login",
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen "imap",
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen "pop3",
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen "ssl-param"
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen};
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenstatic const char *configfile = SYSCONFDIR "/" PACKAGE ".conf";
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic struct timeout *to;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstruct ioloop *ioloop;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstruct hash_table *pids;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenint null_fd, inetd_login_fd;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenuid_t master_uid;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#ifdef DEBUG
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenstatic int gdb;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#endif
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void listen_fds_open(int retry);
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenstatic void listen_fds_close(struct server_settings *server);
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenint validate_str(const char *str, size_t max_len)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen size_t i;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen for (i = 0; i < max_len; i++) {
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen if (str[i] == '\0')
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return TRUE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return FALSE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenvoid child_process_init_env(void)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* remove all environment, we don't need them */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen env_clean();
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* we'll log through master process */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen env_put("LOG_TO_MASTER=1");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#ifdef DEBUG
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (gdb) env_put("GDB=1");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#endif
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void sig_quit(int signo __attr_unused__)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen io_loop_stop(ioloop);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void set_logfile(struct settings *set)
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (set->log_path == NULL)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, LOG_MAIL);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* log to file or stderr */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_set_failure_file(set->log_path, "dovecot");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (set->info_log_path != NULL)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_set_info_file(set->info_log_path);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_set_failure_timestamp_format(set->log_timestamp);
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen}
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic void settings_reload(void)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct server_settings *old_set = settings_root;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_warning("SIGHUP received - reloading configuration");
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen /* restart auth and login processes */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen login_processes_destroy_all();
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen auth_processes_destroy_all();
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (!master_settings_read(configfile, FALSE))
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_warning("Invalid configuration, keeping old one");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen listen_fds_close(old_set);
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen listen_fds_open(TRUE);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen set_logfile(settings_root->defaults);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
e2ae85924b0ef1a7c97e021a3b901b498f599c18Timo Sirainen}
e2ae85924b0ef1a7c97e021a3b901b498f599c18Timo Sirainen
e2ae85924b0ef1a7c97e021a3b901b498f599c18Timo Sirainenstatic const char *get_exit_status_message(enum fatal_exit_status status)
e2ae85924b0ef1a7c97e021a3b901b498f599c18Timo Sirainen{
e2ae85924b0ef1a7c97e021a3b901b498f599c18Timo Sirainen switch (status) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen case FATAL_LOGOPEN:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return "Can't open log file";
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen case FATAL_LOGWRITE:
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return "Can't write to log file";
7a87427770874f38d1d299635b37d699f9772860Timo Sirainen case FATAL_LOGERROR:
7a87427770874f38d1d299635b37d699f9772860Timo Sirainen return "Internal logging error";
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen case FATAL_OUTOFMEM:
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return "Out of memory";
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen case FATAL_EXEC:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return "exec() failed";
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen case FATAL_DEFAULT:
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return NULL;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return NULL;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic void timeout_handler(void *context __attr_unused__)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen const char *process_type_name, *msg;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen pid_t pid;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen int status, process_type;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (lib_signal_hup != 0) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen settings_reload();
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen lib_signal_hup = 0;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* get the type and remove from hash */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen process_type = PID_GET_PROCESS_TYPE(pid);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen PID_REMOVE_PROCESS_TYPE(pid);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (process_type == PROCESS_TYPE_IMAP ||
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen process_type == PROCESS_TYPE_POP3)
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen mail_process_destroyed(pid);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (process_type == PROCESS_TYPE_SSL_PARAM)
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen ssl_parameter_process_destroyed(pid);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen
4b8c92b4773677a7b4064816e469eeafc976ba75Timo Sirainen /* write errors to syslog */
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen process_type_name = process_names[process_type];
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (WIFEXITED(status)) {
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen status = WEXITSTATUS(status);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (status != 0) {
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (process_type == PROCESS_TYPE_LOGIN)
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen login_process_abormal_exit(pid);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen msg = get_exit_status_message(status);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen msg = msg == NULL ? "" :
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen t_strconcat(" (", msg, ")", NULL);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_error("child %s (%s) returned error %d%s",
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen dec2str(pid), process_type_name,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen status, msg);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen } else if (WIFSIGNALED(status)) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (process_type == PROCESS_TYPE_LOGIN)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen login_process_abormal_exit(pid);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_error("child %s (%s) killed with signal %d",
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen dec2str(pid), process_type_name,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen WTERMSIG(status));
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (pid == -1 && errno != EINTR && errno != ECHILD)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_warning("waitpid() failed: %m");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic struct ip_addr *resolve_ip(const char *name, unsigned int *port)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen{
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen const char *p;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct ip_addr *ip;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen int ret, ips_count;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (name == NULL)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return NULL; /* defaults to "*" or "[::]" */
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (name[0] == '[') {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* IPv6 address */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen p = strchr(name, ']');
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (p == NULL)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_fatal("Missing ']' in address %s", name);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen name = t_strdup_until(name+1, p);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen p++;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (*p == '\0')
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen p = NULL;
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen else if (*p != ':')
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen i_fatal("Invalid data after ']' in address %s", name);
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen } else {
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen p = strrchr(name, ':');
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen if (p != NULL)
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen name = t_strdup_until(name, p);
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen }
7d81a331d0af7a7e2c6fecaee11e80a525bec507Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (p != NULL) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (!is_numeric(p+1, '\0'))
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_fatal("Invalid port in address %s", name);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen *port = atoi(p+1);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (strcmp(name, "*") == 0) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* IPv4 any */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen ip = t_new(struct ip_addr, 1);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen net_get_ip_any4(ip);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen return ip;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (strcmp(name, "::") == 0) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* IPv6 any */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen ip = t_new(struct ip_addr, 1);
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen net_get_ip_any6(ip);
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen return ip;
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen }
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen /* Return the first IP if there happens to be multiple. */
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen ret = net_gethostbyname(name, &ip, &ips_count);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (ret != 0) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_fatal("Can't resolve address %s: %s",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen name, net_gethosterror(ret));
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (ips_count < 1)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_fatal("No IPs for address: %s", name);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return ip;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
4b8c92b4773677a7b4064816e469eeafc976ba75Timo Sirainen
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainenstatic void listen_protocols(struct settings *set, int retry)
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen{
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen struct ip_addr *normal_ip, *ssl_ip, *ip;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen const char *const *proto;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen unsigned int normal_port, ssl_port, port;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen int *fd, i;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen normal_port = set->protocol == MAIL_PROTOCOL_IMAP ? 143 : 110;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#ifdef HAVE_SSL
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen ssl_port = set->protocol == MAIL_PROTOCOL_IMAP ? 993 : 995;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#else
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen ssl_port = 0;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#endif
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* resolve */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen normal_ip = resolve_ip(set->listen, &normal_port);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen ssl_ip = resolve_ip(set->ssl_listen, &ssl_port);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (ssl_ip == NULL && set->ssl_listen == NULL)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen ssl_ip = normal_ip;
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen /* register wanted protocols */
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen proto = t_strsplit_spaces(set->protocols, " ");
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen for (; *proto != NULL; proto++) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen fd = NULL; ip = NULL; port = 0;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (strcasecmp(*proto, "imap") == 0) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (set->protocol == MAIL_PROTOCOL_IMAP) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen fd = &set->listen_fd;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen port = normal_port; ip = normal_ip;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen } else if (strcasecmp(*proto, "imaps") == 0) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (set->protocol == MAIL_PROTOCOL_IMAP &&
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen !set->ssl_disable) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen fd = &set->ssl_listen_fd;
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen port = ssl_port; ip = ssl_ip;
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen }
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen } else if (strcasecmp(*proto, "pop3") == 0) {
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen if (set->protocol == MAIL_PROTOCOL_POP3) {
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen fd = &set->listen_fd;
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen port = normal_port; ip = normal_ip;
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen }
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen } else if (strcasecmp(*proto, "pop3s") == 0) {
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen if (set->protocol == MAIL_PROTOCOL_POP3 &&
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen !set->ssl_disable) {
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen fd = &set->ssl_listen_fd;
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen port = ssl_port; ip = ssl_ip;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen } else {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_fatal("Unknown protocol %s", *proto);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (fd == NULL)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen continue;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (*fd != -1)
7a87427770874f38d1d299635b37d699f9772860Timo Sirainen i_fatal("Protocol %s given more than once", *proto);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (port == 0)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen *fd = null_fd;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen else {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen for (i = 0; i < 10; i++) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen *fd = net_listen(ip, &port);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen if (*fd != -1 || errno != EADDRINUSE || !retry)
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen break;
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen /* wait a while and try again. we're SIGHUPing
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen so we most likely just closed it ourself.. */
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen sleep(1);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen if (*fd == -1)
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen i_fatal("listen(%d) failed: %m", port);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen net_set_nonblock(*fd, TRUE);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen }
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen fd_close_on_exec(*fd, TRUE);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (set->listen_fd == -1)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen set->listen_fd = null_fd;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (set->ssl_listen_fd == -1)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen set->ssl_listen_fd = null_fd;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic void listen_fds_open(int retry)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct server_settings *server;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen for (server = settings_root; server != NULL; server = server->next) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (server->imap != NULL)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen listen_protocols(server->imap, retry);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (server->pop3 != NULL)
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen listen_protocols(server->pop3, retry);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen}
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainenstatic void listen_fds_close(struct server_settings *server)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen for (; server != NULL; server = server->next) {
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen if (server->imap != NULL) {
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen if (server->imap->listen_fd != null_fd &&
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen close(server->imap->listen_fd) < 0)
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen i_error("close(imap.listen_fd) failed: %m");
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen if (server->imap->ssl_listen_fd != null_fd &&
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen close(server->imap->ssl_listen_fd) < 0)
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen i_error("close(imap.ssl_listen_fd) failed: %m");
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen }
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen if (server->pop3 != NULL) {
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen if (server->pop3->listen_fd != null_fd &&
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen close(server->pop3->listen_fd) < 0)
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen i_error("close(pop3.listen_fd) failed: %m");
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen if (server->pop3->ssl_listen_fd != null_fd &&
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen close(server->pop3->ssl_listen_fd) < 0)
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen i_error("close(pop3.ssl_listen_fd) failed: %m");
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen }
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainenstatic int have_stderr_set(struct settings *set)
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen{
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen if (set->log_path != NULL &&
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen strcmp(set->log_path, "/dev/stderr") == 0)
f540662dd02e930cf704c1468cccd05d512bc663Timo Sirainen return TRUE;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (set->info_log_path != NULL &&
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen strcmp(set->info_log_path, "/dev/stderr") == 0)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return TRUE;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return FALSE;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic int have_stderr(struct server_settings *server)
{
while (server != NULL) {
if (server->imap != NULL && have_stderr_set(server->imap))
return TRUE;
if (server->pop3 != NULL && have_stderr_set(server->pop3))
return TRUE;
server = server->next;
}
return FALSE;
}
static void open_fds(void)
{
/* initialize fds. */
null_fd = open("/dev/null", O_RDONLY);
if (null_fd == -1)
i_fatal("Can't open /dev/null: %m");
fd_close_on_exec(null_fd, TRUE);
/* make sure all fds between 0..3 are used. */
while (null_fd < 4) {
null_fd = dup(null_fd);
fd_close_on_exec(null_fd, TRUE);
}
if (!IS_INETD())
listen_fds_open(FALSE);
/* close stdin and stdout. close stderr unless we're logging
into /dev/stderr. */
if (dup2(null_fd, 0) < 0)
i_fatal("dup2(0) failed: %m");
if (dup2(null_fd, 1) < 0)
i_fatal("dup2(1) failed: %m");
if (!have_stderr(settings_root)) {
if (dup2(null_fd, 2) < 0)
i_fatal("dup2(2) failed: %m");
}
}
static void create_pid_file(const char *path)
{
const char *pid;
int fd;
pid = t_strconcat(dec2str(getpid()), "\n", NULL);
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd == -1)
i_fatal("open(%s) failed: %m", path);
if (write_full(fd, pid, strlen(pid)) < 0)
i_fatal("write() failed in %s: %m", path);
(void)close(fd);
}
static void main_init(void)
{
/* deny file access from everyone else except owner */
(void)umask(0077);
set_logfile(settings_root->defaults);
i_info("Dovecot v"VERSION" starting up");
log_init();
lib_init_signals(sig_quit);
pids = hash_create(default_pool, default_pool, 128, NULL, NULL);
to = timeout_add(100, timeout_handler, NULL);
ssl_init();
auth_processes_init();
login_processes_init();
create_pid_file(t_strconcat(settings_root->defaults->base_dir,
"/master.pid", NULL));
}
static void main_deinit(void)
{
if (lib_signal_kill != 0)
i_warning("Killed with signal %d", lib_signal_kill);
(void)unlink(t_strconcat(settings_root->defaults->base_dir,
"/master.pid", NULL));
/* make sure we log if child processes died unexpectedly */
timeout_handler(NULL);
login_processes_deinit();
auth_processes_deinit();
ssl_deinit();
timeout_remove(to);
if (close(null_fd) < 0)
i_error("close(null_fd) failed: %m");
hash_destroy(pids);
log_deinit();
closelog();
}
static void daemonize(struct settings *set)
{
pid_t pid;
pid = fork();
if (pid < 0)
i_fatal("fork() failed: %m");
if (pid != 0)
_exit(0);
if (setsid() < 0)
i_fatal("setsid() failed: %m");
if (chdir(set->base_dir) < 0)
i_fatal("chdir(%s) failed: %m", set->base_dir);
}
static void print_help(void)
{
printf("Usage: dovecot [-F] [-c <config file>]\n");
}
int main(int argc, char *argv[])
{
/* parse arguments */
const char *exec_protocol = NULL, *exec_section = NULL;
int foreground = FALSE;
int i;
#ifdef DEBUG
gdb = getenv("GDB") != NULL;
#endif
lib_init();
master_uid = geteuid();
inetd_login_fd = -1;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-F") == 0) {
/* foreground */
foreground = TRUE;
} else if (strcmp(argv[i], "-c") == 0) {
/* config file */
i++;
if (i == argc) i_fatal("Missing config file argument");
configfile = argv[i];
} else if (strcmp(argv[i], "--exec-mail") == 0) {
/* <protocol> [<server section>]
read configuration and execute mail process */
i++;
if (i == argc) i_fatal("Missing protocol argument");
exec_protocol = argv[i];
if (i+1 != argc)
exec_section = argv[++i];
} else if (strcmp(argv[i], "--version") == 0) {
printf("%s\n", VERSION);
return 0;
} else {
print_help();
i_fatal("Unknown argument: %s", argv[1]);
}
}
if (getenv("DOVECOT_INETD") != NULL) {
/* starting through inetd. */
inetd_login_fd = dup(0);
if (inetd_login_fd == -1)
i_fatal("dup(0) failed: %m");
fd_close_on_exec(inetd_login_fd, TRUE);
foreground = TRUE;
}
/* read and verify settings before forking */
master_settings_init();
if (!master_settings_read(configfile, exec_protocol != NULL))
exit(FATAL_DEFAULT);
if (exec_protocol != NULL)
mail_process_exec(exec_protocol, exec_section);
/* we don't need any environment anymore */
env_clean();
open_fds();
if (!foreground)
daemonize(settings_root->defaults);
ioloop = io_loop_create(system_pool);
main_init();
io_loop_run(ioloop);
main_deinit();
master_settings_deinit();
io_loop_destroy(ioloop);
lib_deinit();
return 0;
}