main.c revision f059a046515f4b2b15a6c2a10a6f12f6166e39a5
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "common.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "ioloop.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "randgen.h"
3343a61404603b21c246783a7963b77833095f31Timo Sirainen#include "restrict-access.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "restrict-process-size.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "process-title.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "master-auth.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "master-service.h"
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen#include "master-interface.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "client-common.h"
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainen#include "auth-client.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "ssl-proxy.h"
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen#include "login-proxy.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <stdlib.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <unistd.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <syslog.h>
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstruct auth_client *auth_client;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstruct master_auth *master_auth;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainenbool closing_down;
c000c8eca8f24b2a0c76393ec4bbf76a505a4983Timo Sirainenint anvil_fd = -1;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainenconst struct login_settings *global_login_settings;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainenvoid **global_other_settings;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
c000c8eca8f24b2a0c76393ec4bbf76a505a4983Timo Sirainenstatic bool ssl_connections = FALSE;
c000c8eca8f24b2a0c76393ec4bbf76a505a4983Timo Sirainen
c000c8eca8f24b2a0c76393ec4bbf76a505a4983Timo Sirainenstatic void client_connected(const struct master_service_connection *conn)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen{
3f190f4cbb9233a3a6830956cb5c7ae56a577b79Timo Sirainen struct client *client;
3f190f4cbb9233a3a6830956cb5c7ae56a577b79Timo Sirainen struct ssl_proxy *proxy;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct ip_addr local_ip;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const struct login_settings *set;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen unsigned int local_port;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen pool_t pool;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen int fd_ssl;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen void **other_sets;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen if (net_getsockname(conn->fd, &local_ip, &local_port) < 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen memset(&local_ip, 0, sizeof(local_ip));
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen local_port = 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen pool = pool_alloconly_create("login client", 3*1024);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen set = login_settings_read(master_service, pool, &local_ip,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen &conn->remote_ip, &other_sets);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (!ssl_connections && !conn->ssl) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen client = client_create(conn->fd, FALSE, pool, set, other_sets,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen &local_ip, &conn->remote_ip);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen } else {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen fd_ssl = ssl_proxy_new(conn->fd, &conn->remote_ip, set, &proxy);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (fd_ssl == -1) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen net_disconnect(conn->fd);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen pool_unref(&pool);
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen return;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen client = client_create(fd_ssl, TRUE, pool, set, other_sets,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen &local_ip, &conn->remote_ip);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen client->ssl_proxy = proxy;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ssl_proxy_set_client(proxy, client);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen client->remote_port = conn->remote_port;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen client->local_port = local_port;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen}
c000c8eca8f24b2a0c76393ec4bbf76a505a4983Timo Sirainen
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainenstatic void auth_connect_notify(struct auth_client *client ATTR_UNUSED,
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen bool connected, void *context ATTR_UNUSED)
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen{
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen if (connected)
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen clients_notify_auth_connected();
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen}
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainenstatic int anvil_connect(void)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen{
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen#define ANVIL_HANDSHAKE "VERSION\tanvil\t1\t0\n"
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen int i = 0, fd;
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi while ((fd = net_connect_unix("anvil")) == -1) {
d42eb03b3a4e79a2da22a1be2de59b95660af2beTimo Sirainen if (errno != EAGAIN || ++i == 3)
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen i_fatal("net_connect_unix(anvil) failed: %m");
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen sleep(1);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen }
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen net_set_nonblock(fd, FALSE);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (write(fd, ANVIL_HANDSHAKE, strlen(ANVIL_HANDSHAKE)) < 0)
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen i_fatal("write(anvil) failed: %m");
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen return fd;
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic void main_preinit(void)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen unsigned int max_fds;
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen random_init();
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen /* Initialize SSL proxy so it can read certificate and private
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen key file. */
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen ssl_proxy_init();
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen
c000c8eca8f24b2a0c76393ec4bbf76a505a4983Timo Sirainen /* set the number of fds we want to use. it may get increased or
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen decreased. leave a couple of extra fds for auth sockets and such.
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen worst case each connection can use:
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen - 1 for client
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen - 1 for login proxy
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen - 2 for client-side ssl proxy
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen - 2 for server-side ssl proxy (with login proxy)
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen */
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen max_fds = MASTER_LISTEN_FD_FIRST + 16 +
3d4c24127f4f83259c0f81851184abc34793dbe0Timo Sirainen master_service_get_socket_count(master_service) +
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen master_service_get_client_limit(master_service)*6;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen restrict_fd_limit(max_fds);
3d4c24127f4f83259c0f81851184abc34793dbe0Timo Sirainen io_loop_set_max_fd_count(current_ioloop, max_fds);
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen i_assert(strcmp(global_login_settings->ssl, "no") == 0 ||
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen ssl_initialized);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (global_login_settings->mail_max_userip_connections > 0)
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen anvil_fd = anvil_connect();
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen restrict_access_by_env(NULL, TRUE);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainenstatic void main_init(void)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* make sure we can't fork() */
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen restrict_process_size((unsigned int)-1, 1);
c000c8eca8f24b2a0c76393ec4bbf76a505a4983Timo Sirainen
424236b2b88a5a7bbde5cf6a6b32189ca3437629Timo Sirainen if (restrict_access_get_current_chroot() == NULL) {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen if (chdir("login") < 0)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_fatal("chdir(login) failed: %m");
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen }
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen master_service_set_avail_overflow_callback(master_service,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen client_destroy_oldest);
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen auth_client = auth_client_init("auth", (unsigned int)getpid(), FALSE);
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen auth_client_set_connect_notify(auth_client, auth_connect_notify, NULL);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen master_auth = master_auth_init(master_service, login_protocol);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen clients_init();
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen login_proxy_init();
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen}
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic void main_deinit(void)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen{
7501b9f694460101b41d1d708ebc3ec2b0400b1cTimo Sirainen ssl_proxy_deinit();
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen login_proxy_deinit();
7501b9f694460101b41d1d708ebc3ec2b0400b1cTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (auth_client != NULL)
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen auth_client_deinit(&auth_client);
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen clients_deinit();
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen master_auth_deinit(&master_auth);
7501b9f694460101b41d1d708ebc3ec2b0400b1cTimo Sirainen
7501b9f694460101b41d1d708ebc3ec2b0400b1cTimo Sirainen if (anvil_fd != -1) {
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen if (close(anvil_fd) < 0)
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen i_error("close(anvil) failed: %m");
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen }
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen}
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen
1b5366b2234892f8930a29351da06b193e385150Timo Sirainenint main(int argc, char *argv[], char *envp[])
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen{
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen enum master_service_flags service_flags =
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN |
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE;
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen const char *getopt_str;
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen pool_t set_pool;
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen int c;
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen master_service = master_service_init(login_process_name, service_flags,
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen argc, argv);
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen master_service_init_log(master_service, t_strconcat(
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen login_process_name, ": ", NULL));
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
e5afebd2df1d4990f7bec2a839260ff2e6d78168Timo Sirainen getopt_str = t_strconcat("DS", master_service_getopt_string(), NULL);
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen while ((c = getopt(argc, argv, getopt_str)) > 0) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen switch (c) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen case 'D':
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen restrict_access_allow_coredumps(TRUE);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen break;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen case 'S':
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen ssl_connections = TRUE;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen break;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen default:
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen if (!master_service_parse_option(master_service,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen c, optarg))
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen exit(FATAL_DEFAULT);
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen break;
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen }
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen login_process_preinit();
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen
3343a61404603b21c246783a7963b77833095f31Timo Sirainen process_title_init(argv, envp);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen set_pool = pool_alloconly_create("global login settings", 4096);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen global_login_settings =
3343a61404603b21c246783a7963b77833095f31Timo Sirainen login_settings_read(master_service, set_pool, NULL, NULL,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen &global_other_settings);
3343a61404603b21c246783a7963b77833095f31Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* main_preinit() needs to know the client limit, which is set by
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen this. so call it first. */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen master_service_init_finish(master_service);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen main_preinit();
main_init();
master_service_run(master_service, client_connected);
main_deinit();
pool_unref(&set_pool);
master_service_deinit(&master_service);
return 0;
}