main.c revision 89795c6bbbc52bb382e88bc8617d22092223e9a5
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "common.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "ioloop.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "array.h"
65988f5a8abed57e9894fec77105941e046d3490Timo Sirainen#include "lib-signals.h"
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen#include "randgen.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "restrict-access.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "restrict-process-size.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "process-title.h"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include "fd-close-on-exec.h"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include "master.h"
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen#include "client-common.h"
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen#include "auth-client.h"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include "ssl-proxy.h"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include "login-proxy.h"
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include <stdlib.h>
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include <unistd.h>
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen#include <syslog.h>
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenbool disable_plaintext_auth, process_per_connection, greeting_capability;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenbool verbose_proctitle, verbose_ssl, verbose_auth;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenconst char *greeting, *log_format;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenconst char *const *log_format_elements;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenconst char *trusted_networks;
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainenunsigned int max_connections;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenunsigned int login_process_uid;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstruct auth_client *auth_client;
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainenbool closing_down;
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstatic const char *process_name;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstatic struct ioloop *ioloop;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstatic int main_refcount;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstatic bool is_inetd, listening;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstatic ARRAY_DEFINE(listen_ios, struct io *);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenstatic unsigned int listen_count, ssl_listen_count;
e4f1a5fdad77884e1de516521504c15dc936fa9dTimo Sirainen
e4f1a5fdad77884e1de516521504c15dc936fa9dTimo Sirainenvoid main_ref(void)
e4f1a5fdad77884e1de516521504c15dc936fa9dTimo Sirainen{
e4f1a5fdad77884e1de516521504c15dc936fa9dTimo Sirainen main_refcount++;
e4f1a5fdad77884e1de516521504c15dc936fa9dTimo Sirainen}
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainenvoid main_unref(void)
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen{
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (--main_refcount == 0) {
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen /* nothing to do, quit */
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen io_loop_stop(ioloop);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen } else if (closing_down && clients_get_count() == 0) {
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen /* last login finished, close all communications
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen to master process */
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen master_close();
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen /* we might still be proxying. close the connection to
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen dovecot-auth, since it's not needed anymore. */
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen if (auth_client != NULL)
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen auth_client_free(&auth_client);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen } else if (clients_get_count() == 0) {
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen /* make sure we clear all the memory used by the
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen authentication connections. also this makes sure that if
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen this connection's authentication was finished but the master
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen login wasn't, the next connection won't be able to log in
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen as this user by finishing the master login. */
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen if (auth_client != NULL)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen auth_client_reconnect(auth_client);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen }
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen}
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenstatic void sig_die(int signo, void *context ATTR_UNUSED)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen{
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen which is too common at least while testing :) */
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen if (signo != SIGINT)
7c424aa51c956c628e3512055841aa2f9eef4833Timo Sirainen i_warning("Killed with signal %d", signo);
f923659c0e5298263d80622c99f4dc4132b4675bTimo Sirainen io_loop_stop(ioloop);
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen}
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainenstatic void login_accept(void *context)
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen{
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen int listen_fd = POINTER_CAST_TO(context, int);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen struct ip_addr remote_ip, local_ip;
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen unsigned int remote_port, local_port;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen struct client *client;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen int fd;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen fd = net_accept(listen_fd, &remote_ip, &remote_port);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (fd < 0) {
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen if (fd < -1)
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen i_error("accept() failed: %m");
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen return;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen }
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (net_getsockname(fd, &local_ip, &local_port) < 0) {
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen memset(&local_ip, 0, sizeof(local_ip));
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen local_port = 0;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen }
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen client = client_create(fd, FALSE, &local_ip, &remote_ip);
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen client->remote_port = remote_port;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen client->local_port = local_port;
fab050cbfdf3da692441d2e2fb4b2a4c6ac9e0daTimo Sirainen
fab050cbfdf3da692441d2e2fb4b2a4c6ac9e0daTimo Sirainen if (process_per_connection) {
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen closing_down = TRUE;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen main_listen_stop();
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen }
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen}
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainenstatic void login_accept_ssl(void *context)
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen{
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen int listen_fd = POINTER_CAST_TO(context, int);
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen struct ip_addr remote_ip, local_ip;
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen unsigned int remote_port, local_port;
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen struct client *client;
2a3fc652e13a574ca14ff2405b5c29a59232db49Timo Sirainen struct ssl_proxy *proxy;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen int fd, fd_ssl;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen fd = net_accept(listen_fd, &remote_ip, &remote_port);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (fd < 0) {
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (fd < -1)
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen i_error("accept() failed: %m");
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen return;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen }
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (net_getsockname(fd, &local_ip, &local_port) < 0) {
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen memset(&local_ip, 0, sizeof(local_ip));
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen local_port = 0;
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen }
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen fd_ssl = ssl_proxy_new(fd, &remote_ip, &proxy);
812ac1e2570c600a086c09b24d250224a822a97dTimo Sirainen if (fd_ssl == -1)
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen net_disconnect(fd);
d65a556a5ec078cd7f1d0060adb16fc860d66b27Timo Sirainen else {
d65a556a5ec078cd7f1d0060adb16fc860d66b27Timo Sirainen client = client_create(fd_ssl, TRUE, &local_ip, &remote_ip);
d65a556a5ec078cd7f1d0060adb16fc860d66b27Timo Sirainen client->proxy = proxy;
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipek client->remote_port = remote_port;
847aeef259d42e2f14cf126699e28291e6e1fb53Timo Sirainen client->local_port = local_port;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen }
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen if (process_per_connection) {
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen closing_down = TRUE;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen main_listen_stop();
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen }
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen}
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainenvoid main_listen_start(void)
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen{
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen struct io *io;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen unsigned int i, current_count;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen int cur_fd;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen if (listening)
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen return;
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen if (closing_down) {
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen /* typically happens only with
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen login_process_per_connection=yes after client logs in */
b516a7812b9acc04522869fead3aa6d2787dcdc6Timo Sirainen master_notify_state_change(LOGIN_STATE_FULL_LOGINS);
b516a7812b9acc04522869fead3aa6d2787dcdc6Timo Sirainen return;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen }
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen current_count = ssl_proxy_get_count() + login_proxy_get_count();
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen if (current_count >= max_connections) {
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen /* can't accept any more connections until existing proxies
af6c7862e6160ffaecec458f4cec43b94272ad57Timo Sirainen get destroyed */
af6c7862e6160ffaecec458f4cec43b94272ad57Timo Sirainen return;
af6c7862e6160ffaecec458f4cec43b94272ad57Timo Sirainen }
af6c7862e6160ffaecec458f4cec43b94272ad57Timo Sirainen
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen cur_fd = LOGIN_MASTER_SOCKET_FD + 1;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen i_array_init(&listen_ios, listen_count + ssl_listen_count);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen for (i = 0; i < listen_count; i++, cur_fd++) {
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen io = io_add(cur_fd, IO_READ, login_accept,
055f4599bba1874fa1148a8fa488517fa077619cTimo Sirainen POINTER_CAST(cur_fd));
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen array_append(&listen_ios, &io, 1);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen }
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen for (i = 0; i < ssl_listen_count; i++, cur_fd++) {
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen io = io_add(cur_fd, IO_READ, login_accept_ssl,
82d3a1d1594ed93d04d7bf999027b3e5104de6e4Timo Sirainen POINTER_CAST(cur_fd));
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen array_append(&listen_ios, &io, 1);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen }
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen listening = TRUE;
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* the initial notification tells master that we're ok. if we die
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen before sending it, the master should shutdown itself. */
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen master_notify_state_change(LOGIN_STATE_LISTENING);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen}
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen
void main_listen_stop(void)
{
struct io **ios;
unsigned int i, count;
int cur_fd;
if (!listening)
return;
ios = array_get_modifiable(&listen_ios, &count);
for (i = 0; i < count; i++)
io_remove(&ios[i]);
array_free(&listen_ios);
if (closing_down) {
cur_fd = LOGIN_MASTER_SOCKET_FD + 1;
for (i = 0; i < count; i++, cur_fd++) {
if (close(cur_fd) < 0) {
i_fatal("close(listener %d) failed: %m",
cur_fd);
}
}
}
listening = FALSE;
if (io_loop_is_running(ioloop)) {
master_notify_state_change(clients_get_count() == 0 ?
LOGIN_STATE_FULL_LOGINS :
LOGIN_STATE_FULL_PRELOGINS);
}
}
void connection_queue_add(unsigned int connection_count)
{
unsigned int current_count;
if (process_per_connection)
return;
current_count = clients_get_count() + ssl_proxy_get_count() +
login_proxy_get_count();
if (current_count + connection_count + 1 >= max_connections) {
/* after this client we've reached max users count,
so stop listening for more. reserve +1 extra for SSL
connections. */
main_listen_stop();
if (current_count >= max_connections) {
/* already reached max. users count, kill few of the
oldest connections.
this happens when we've maxed out the login process
count and master has told us to start listening for
new connections even though we're full. */
client_destroy_oldest();
}
}
}
static void auth_connect_notify(struct auth_client *client ATTR_UNUSED,
bool connected, void *context ATTR_UNUSED)
{
if (connected)
clients_notify_auth_connected();
}
static void drop_privileges(void)
{
const char *value;
if (!is_inetd)
i_set_failure_internal();
else {
/* log to syslog */
value = getenv("SYSLOG_FACILITY");
i_set_failure_syslog(process_name, LOG_NDELAY,
value == NULL ? LOG_MAIL : atoi(value));
/* if we don't chroot, we must chdir */
value = getenv("LOGIN_DIR");
if (value != NULL) {
if (chdir(value) < 0)
i_error("chdir(%s) failed: %m", value);
}
}
/* Initialize SSL proxy so it can read certificate and private
key file. */
random_init();
ssl_proxy_init();
value = getenv("LISTEN_FDS");
listen_count = value == NULL ? 0 : atoi(value);
value = getenv("SSL_LISTEN_FDS");
ssl_listen_count = value == NULL ? 0 : atoi(value);
value = getenv("MAX_CONNECTIONS");
max_connections = value == NULL ? 1 : strtoul(value, NULL, 10);
/* set the number of fds we want to use. it may get increased or
decreased. leave a couple of extra fds for auth sockets and such */
restrict_fd_limit(LOGIN_MASTER_SOCKET_FD + 16 +
listen_count + ssl_listen_count + max_connections);
/* Refuse to run as root - we should never need it and it's
dangerous with SSL. */
restrict_access_by_env(TRUE);
/* make sure we can't fork() */
restrict_process_size((unsigned int)-1, 1);
}
static void main_init(void)
{
const char *value;
value = getenv("DOVECOT_VERSION");
if (value != NULL && strcmp(value, PACKAGE_VERSION) != 0) {
i_fatal("Dovecot version mismatch: "
"Master is v%s, login is v"PACKAGE_VERSION" "
"(if you don't care, set version_ignore=yes)", value);
}
lib_signals_init();
lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
lib_signals_ignore(SIGPIPE, TRUE);
disable_plaintext_auth = getenv("DISABLE_PLAINTEXT_AUTH") != NULL;
process_per_connection = getenv("PROCESS_PER_CONNECTION") != NULL;
verbose_proctitle = getenv("VERBOSE_PROCTITLE") != NULL;
verbose_ssl = getenv("VERBOSE_SSL") != NULL;
verbose_auth = getenv("VERBOSE_AUTH") != NULL;
greeting = getenv("GREETING");
if (greeting == NULL)
greeting = PACKAGE" ready.";
greeting_capability = getenv("GREETING_CAPABILITY") != NULL;
value = getenv("LOG_FORMAT_ELEMENTS");
if (value == NULL)
value = "user=<%u> method=%m rip=%r lip=%l %c : %$";
log_format_elements = t_strsplit(value, " ");
log_format = getenv("LOG_FORMAT");
if (log_format == NULL)
log_format = "%$: %s";
trusted_networks = getenv("TRUSTED_NETWORKS");
value = getenv("PROCESS_UID");
if (value == NULL)
i_fatal("BUG: PROCESS_UID environment not given");
login_process_uid = strtoul(value, NULL, 10);
if (login_process_uid == 0)
i_fatal("BUG: PROCESS_UID environment is 0");
/* capability default is set in imap/pop3-login */
value = getenv("CAPABILITY_STRING");
if (value != NULL && *value != '\0')
capability_string = value;
closing_down = FALSE;
main_refcount = 0;
auth_client = auth_client_new(login_process_uid);
auth_client_set_connect_notify(auth_client, auth_connect_notify, NULL);
clients_init();
if (!ssl_initialized && ssl_listen_count > 0) {
/* this shouldn't happen, master should have
disabled the ssl socket.. */
i_fatal("BUG: SSL initialization parameters not given "
"while they should have been");
}
if (!is_inetd) {
master_init(LOGIN_MASTER_SOCKET_FD);
main_listen_start();
}
}
static void main_deinit(void)
{
closing_down = TRUE;
main_listen_stop();
ssl_proxy_deinit();
login_proxy_deinit();
if (auth_client != NULL)
auth_client_free(&auth_client);
clients_deinit();
master_deinit();
lib_signals_deinit();
closelog();
}
int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
{
const char *group_name;
struct ip_addr remote_ip, local_ip;
unsigned int remote_port, local_port;
struct ssl_proxy *proxy = NULL;
struct client *client;
int i, fd = -1, master_fd = -1;
bool ssl = FALSE;
is_inetd = getenv("DOVECOT_MASTER") == NULL;
#ifdef DEBUG
if (!is_inetd && getenv("GDB") == NULL) {
const char *env;
i = LOGIN_MASTER_SOCKET_FD + 1;
env = getenv("LISTEN_FDS");
if (env != NULL) i += atoi(env);
env = getenv("SSL_LISTEN_FDS");
if (env != NULL) i += atoi(env);
fd_debug_verify_leaks(i + 1, 1024);
}
#endif
/* clear all allocated memory before freeing it. this makes the login
processes pretty safe to reuse for new connections since the
attacker won't be able to find anything interesting from the
memory. */
default_pool = system_clean_pool;
data_stack_set_clean_after_pop(TRUE);
/* NOTE: we start rooted, so keep the code minimal until
restrict_access_by_env() is called */
lib_init();
if (is_inetd) {
/* running from inetd. create master process before
dropping privileges. */
process_name = strrchr(argv[0], '/');
process_name = process_name == NULL ? argv[0] : process_name+1;
group_name = t_strcut(process_name, '-');
for (i = 1; i < argc; i++) {
if (strncmp(argv[i], "--group=", 8) == 0) {
group_name = argv[1]+8;
break;
}
}
master_fd = master_connect(group_name);
}
drop_privileges();
process_title_init(argv, envp);
ioloop = io_loop_create();
main_init();
if (is_inetd) {
if (net_getpeername(1, &remote_ip, &remote_port) < 0) {
i_fatal("%s can be started only through dovecot "
"master process, inetd or equivalent", argv[0]);
}
if (net_getsockname(1, &local_ip, &local_port) < 0) {
memset(&local_ip, 0, sizeof(local_ip));
local_port = 0;
}
fd = 1;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--ssl") == 0)
ssl = TRUE;
else if (strncmp(argv[i], "--group=", 8) != 0)
i_fatal("Unknown parameter: %s", argv[i]);
}
/* hardcoded imaps and pop3s ports to be SSL by default */
if (local_port == 993 || local_port == 995 || ssl) {
ssl = TRUE;
fd = ssl_proxy_new(fd, &remote_ip, &proxy);
if (fd == -1)
return 1;
}
master_init(master_fd);
closing_down = TRUE;
if (fd != -1) {
client = client_create(fd, ssl, &local_ip, &remote_ip);
client->proxy = proxy;
client->remote_port = remote_port;
client->local_port = local_port;
}
}
io_loop_run(ioloop);
main_deinit();
io_loop_destroy(&ioloop);
lib_deinit();
return 0;
}