main.c revision 3982a9bf01c2520c7a864237c0d709d911395542
/* Copyright (C) 2002 Timo Sirainen */
#include "common.h"
#include "ioloop.h"
#include "lib-signals.h"
#include "network.h"
#include "env-util.h"
#include "fd-close-on-exec.h"
#include "write-full.h"
#include "askpass.h"
#include "auth-process.h"
#include "dict-process.h"
#include "login-process.h"
#include "mail-process.h"
#include "syslog-util.h"
#include "ssl-init.h"
#include "log.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
const char *process_names[PROCESS_TYPE_MAX] = {
"unknown",
"auth",
"auth-worker",
"login",
"imap",
"pop3",
"ssl-build-param",
"dict"
};
static const char *env_tz;
struct hash_table *pids;
int null_fd, inetd_login_fd;
char program_path[PATH_MAX];
char ssl_manual_key_password[100];
#ifdef DEBUG
static bool gdb;
#endif
static void listen_fds_open(bool retry);
{
size_t i;
for (i = 0; i < max_len; i++) {
if (str[i] == '\0')
return TRUE;
}
return FALSE;
}
void child_process_init_env(void)
{
int facility;
/* remove all environment, we don't need them */
env_clean();
/* we'll log through master process */
env_put("LOG_TO_MASTER=1");
if (settings_root == NULL ||
&facility))
#ifdef DEBUG
#endif
}
{
const char *executable, *p, **argv;
/* very simple argument splitting. */
if (*title == '\0')
else
executable = argv[0];
/* hide the path, it's ugly */
}
{
int facility;
} else {
/* log to file or stderr */
}
}
static void settings_reload(void)
{
i_warning("SIGHUP received - reloading configuration");
/* restart auth and login processes */
i_warning("Invalid configuration, keeping old one");
else {
if (!IS_INETD()) {
}
}
}
{
/* warn about being killed because of some signal, except SIGINT (^C)
which is too common at least while testing :) */
}
void *context __attr_unused__)
{
}
void *context __attr_unused__)
{
}
{
switch (status) {
case FATAL_LOGOPEN:
return "Can't open log file";
case FATAL_LOGWRITE:
return "Can't write to log file";
case FATAL_LOGERROR:
return "Internal logging error";
case FATAL_OUTOFMEM:
return "Out of memory";
case FATAL_EXEC:
return "exec() failed";
case FATAL_DEFAULT:
return NULL;
}
return NULL;
}
{
const char *process_type_name, *msg;
int status, process_type;
/* get the type and remove from hash */
switch (process_type) {
case PROCESS_TYPE_IMAP:
case PROCESS_TYPE_POP3:
break;
case PROCESS_TYPE_SSL_PARAM:
break;
case PROCESS_TYPE_DICT:
break;
}
/* write errors to syslog */
if (status != 0) {
if (process_type == PROCESS_TYPE_LOGIN)
i_error("child %s (%s) returned error %d%s",
}
} else if (WIFSIGNALED(status)) {
if (process_type == PROCESS_TYPE_LOGIN)
i_error("child %s (%s) killed with signal %d",
}
}
i_warning("waitpid() failed: %m");
}
{
const char *p;
if (*name == '\0') {
/* defaults to "*" or "[::]" */
return;
}
if (name[0] == '[') {
/* IPv6 address */
if (p == NULL)
p++;
if (*p == '\0')
p = NULL;
else if (*p != ':')
} else {
if (p != NULL)
}
if (p != NULL) {
}
/* IPv4 any */
return;
}
/* IPv6 any */
return;
}
/* Return the first IP if there happens to be multiple. */
if (ret != 0) {
i_fatal("Can't resolve address %s: %s",
}
if (ips_count < 1)
}
static void
{
}
}
}
const char *proto)
{
struct server_settings *server;
"imap", proto);
}
"pop3", proto);
}
}
}
{
const char *const *proto;
unsigned int port;
int *fd, i;
#ifdef HAVE_SSL
#else
set->ssl_listen_port = 0;
#endif
/* resolve */
/* if ssl_listen wasn't explicitly set in the config file,
use the non-ssl IP settings for the ssl listener, too. */
/* register wanted protocols */
}
!set->ssl_disable) {
}
}
!set->ssl_disable) {
}
} else {
}
continue;
if (*fd != -1)
if (port == 0)
else {
for (i = 0; i < 10; i++) {
break;
if (!retry)
break;
/* wait a while and try again. we're SIGHUPing
so we most likely just closed it ourself.. */
sleep(1);
}
if (*fd == -1)
}
}
}
static void listen_fds_open(bool retry)
{
struct server_settings *server;
}
}
{
i_error("close(imap.listen_fd) failed: %m");
}
i_error("close(pop3.listen_fd) failed: %m");
}
}
}
{
return TRUE;
return TRUE;
return FALSE;
}
{
return TRUE;
return TRUE;
}
return FALSE;
}
static void open_fds(void)
{
/* initialize fds. */
if (null_fd == -1)
/* make sure all fds between 0..3 are used. */
while (null_fd < 4) {
}
if (!IS_INETD())
/* close stdin and stdout. close stderr unless we're logging
i_fatal("dup2(0) failed: %m");
i_fatal("dup2(1) failed: %m");
if (!have_stderr(settings_root)) {
i_fatal("dup2(2) failed: %m");
}
}
static void create_pid_file(const char *path)
{
const char *pid;
int fd;
if (fd == -1)
}
static void main_init(void)
{
/* deny file access from everyone else except owner */
(void)umask(0077);
log_init();
ssl_init();
"/master.pid", NULL));
}
static void main_deinit(void)
{
"/master.pid", NULL));
/* make sure we log if child processes died unexpectedly */
ssl_deinit();
timeout_remove(&to);
i_error("close(null_fd) failed: %m");
log_deinit();
closelog();
}
{
if (pid < 0)
i_fatal("fork() failed: %m");
if (pid != 0)
_exit(0);
if (setsid() < 0)
i_fatal("setsid() failed: %m");
}
static void print_help(void)
{
"Usage: dovecot [-F] [-c <config file>] [-p] [-n] [-a]\n"
" [--exec-mail <protocol>] [--version] [--build-options]\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_DNOTIFY
" notify=dnotify"
#endif
#ifdef IOLOOP_NOTIFY_INOTIFY
" notify=inotify"
#endif
#ifdef IOLOOP_NOTIFY_KQUEUE
" notify=kqueue"
#endif
#ifdef HAVE_IPV6
" ipv6"
#endif
#ifdef HAVE_GNUTLS
" gnutls"
#endif
#ifdef HAVE_OPENSSL
" openssl"
#endif
"\nSQL drivers:"
#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"
#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");
}
{
/* parse arguments */
int i;
#ifdef DEBUG
#endif
lib_init();
master_uid = geteuid();
inetd_login_fd = -1;
for (i = 1; i < argc; i++) {
/* foreground */
foreground = TRUE;
dump_config = TRUE;
/* config file */
i++;
configfile = argv[i];
/* Ask SSL private key password */
ask_key_pass = TRUE;
/* <protocol> [<server section>]
read configuration and execute mail process */
i++;
exec_protocol = argv[i];
if (i+1 != argc)
exec_section = argv[++i];
return 0;
return 0;
} else {
print_help();
}
}
/* starting through inetd. */
inetd_login_fd = dup(0);
if (inetd_login_fd == -1)
i_fatal("dup(0) failed: %m");
foreground = TRUE;
}
/* read and verify settings before forking */
t_push();
t_pop();
if (dump_config || dump_config_nondefaults) {
return 0;
}
if (ask_key_pass) {
const char *prompt;
t_push();
"%s: ",
sizeof(ssl_manual_key_password));
t_pop();
}
/* save TZ environment. AIX depends on it to get the timezone
correctly. */
/* clean up the environment of everything */
env_clean();
/* put back the TZ */
if (exec_protocol != NULL) {
/* Put back user and home */
}
open_fds();
if (!foreground)
main_init();
main_deinit();
lib_deinit();
return 0;
}