main.c revision 0a53eb0283d7ec28c6105f61e118b96fce8ecb95
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "lib.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "ioloop.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "array.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "restrict-access.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "master-interface.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "master-service.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "master-service-settings.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "auth-connection.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "doveadm-connection.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "login-connection.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "notify-connection.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "director.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "director-host.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "director-connection.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "director-request.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include "mail-host.h"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#include <stdio.h>
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek#include <unistd.h>
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny#define AUTH_SOCKET_PATH "auth-login"
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zelenystatic struct director *director;
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zelenystatic struct notify_connection *notify_conn;
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekstatic char *auth_socket_path;
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozek
58dd26b1c5b60ee992dd5d1214bb168aebb42d54Jakub Hrozekstatic int director_client_connected(int fd, const struct ip_addr *ip)
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina{
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina if (director_host_lookup_ip(director, ip) == NULL) {
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina i_warning("Connection from %s: Server not listed in "
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina "director_servers, dropping", net_ip2addr(ip));
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina return -1;
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina }
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina director_connection_init_in(director, fd, ip);
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina return 0;
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina}
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březinastatic void client_connected(struct master_service_connection *conn)
cf1a8af5556b1d8eab68802918c881ae1a0b89ebPavel Březina{
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce struct auth_connection *auth;
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce const char *path, *name;
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce struct ip_addr ip;
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce unsigned int port, len;
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce if (conn->fifo) {
1f800ebb0f190854b8296146174f3d696a426333Simo Sorce if (notify_conn != NULL) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce i_error("Received another proxy-notify connection");
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce return;
1f800ebb0f190854b8296146174f3d696a426333Simo Sorce }
1f800ebb0f190854b8296146174f3d696a426333Simo Sorce master_service_client_connection_accept(conn);
07b92f78d1751d8a2a538a440e1fdb24c59021e0Pavel Březina notify_conn = notify_connection_init(director, conn->fd);
1f800ebb0f190854b8296146174f3d696a426333Simo Sorce return;
1f800ebb0f190854b8296146174f3d696a426333Simo Sorce }
850ca620611f65115ee95e1d919be8443f95c14cLukas Slebodnik
1f800ebb0f190854b8296146174f3d696a426333Simo Sorce if (net_getpeername(conn->fd, &ip, &port) == 0 &&
850ca620611f65115ee95e1d919be8443f95c14cLukas Slebodnik (IPADDR_IS_V4(&ip) || IPADDR_IS_V6(&ip))) {
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce /* TCP/IP connection - this is another director */
1f800ebb0f190854b8296146174f3d696a426333Simo Sorce if (director_client_connected(conn->fd, &ip) == 0)
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce master_service_client_connection_accept(conn);
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce return;
0232747f04b650796db56fd7b487aee8a96fab03Simo Sorce }
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek if (net_getunixname(conn->listen_fd, &path) < 0)
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek i_fatal("getunixname(%d) failed: %m", conn->listen_fd);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek name = strrchr(path, '/');
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek if (name == NULL)
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek name = path;
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek else
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek name++;
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek len = strlen(name);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek if (len > 6 && strcmp(name + len - 6, "-admin") == 0) {
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek /* doveadm connection */
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek master_service_client_connection_accept(conn);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek (void)doveadm_connection_init(director, conn->fd);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek } else {
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek /* login connection */
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek auth = auth_connection_init(auth_socket_path);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek if (auth_connection_connect(auth) == 0) {
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek master_service_client_connection_accept(conn);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek login_connection_init(director, conn->fd, auth);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek } else {
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek auth_connection_deinit(&auth);
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek }
33c865412732554ef255e93c4e7a58b0bce963c6Jakub Hrozek }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestatic unsigned int find_inet_listener_port(struct ip_addr *ip_r)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce unsigned int i, socket_count, port;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce socket_count = master_service_get_socket_count(master_service);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce for (i = 0; i < socket_count; i++) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce int fd = MASTER_LISTEN_FD_FIRST + i;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (net_getsockname(fd, ip_r, &port) == 0 && port > 0)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce return port;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce return 0;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestatic void director_state_changed(struct director *dir)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce struct director_request *const *requestp;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce bool ret;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina if (!dir->ring_synced ||
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina mail_host_get_by_hash(dir->mail_hosts, 0) == NULL)
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina return;
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina /* if there are any pending client requests, finish them now */
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina array_foreach(&dir->pending_requests, requestp) {
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina ret = director_request_continue(*requestp);
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina i_assert(ret);
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina }
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina array_clear(&dir->pending_requests);
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina if (dir->to_request != NULL)
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina timeout_remove(&dir->to_request);
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina}
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březinastatic void main_init(void)
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina{
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina const struct director_settings *set;
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina struct ip_addr listen_ip;
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina unsigned int listen_port;
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina set = master_service_settings_get_others(master_service)[0];
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina auth_socket_path = i_strconcat(set->base_dir,
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina "/"AUTH_SOCKET_PATH, NULL);
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina listen_port = find_inet_listener_port(&listen_ip);
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina if (listen_port == 0 && *set->director_servers != '\0') {
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina i_fatal("No inet_listeners defined for director service "
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina "(for standalone keep director_servers empty)");
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina }
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina
e1f68731525116ce686ffcdc07ad3a14e4fb1cd7Pavel Březina director = director_init(set, &listen_ip, listen_port,
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina director_state_changed);
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina director_host_add_from_string(director, set->director_servers);
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina if (mail_hosts_parse_and_add(director->mail_hosts,
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina set->director_mail_servers) < 0)
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina i_fatal("Invalid value for director_mail_servers setting");
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina director->orig_config_hosts = mail_hosts_dup(director->mail_hosts);
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina}
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březinastatic void main_deinit(void)
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina{
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina if (notify_conn != NULL)
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina notify_connection_deinit(&notify_conn);
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina director_deinit(&director);
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina doveadm_connections_deinit();
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina login_connections_deinit();
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina auth_connections_deinit();
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina i_free(auth_socket_path);
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina}
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březinaint main(int argc, char *argv[])
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina{
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina const struct setting_parser_info *set_roots[] = {
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina &director_setting_parser_info,
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina NULL
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina };
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina unsigned int test_port = 0;
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina const char *error;
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina bool debug = FALSE;
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina int c;
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina master_service = master_service_init("director",
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina MASTER_SERVICE_FLAG_NO_IDLE_DIE,
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina &argc, &argv, "Dt:");
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina while ((c = master_getopt(master_service)) > 0) {
0b81cc5d41ec6a1c58e610f402fd93a1fbda4affPavel Březina switch (c) {
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny case 'D':
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny debug = TRUE;
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny break;
b8dcd1216e5ea7065213c750a92dabfe01fa3b70Simo Sorce case 't':
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny if (str_to_uint(optarg, &test_port) < 0)
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose i_fatal("-t: Not a number: %s", optarg);
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek break;
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek default:
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny return FATAL_DEFAULT;
f91e4aacb78d33791efcd744000597d5254dac4bSimo Sorce }
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce if (master_service_settings_read_simple(master_service, set_roots,
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce &error) < 0)
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce i_fatal("Error reading configuration: %s", error);
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny master_service_init_log(master_service, "director: ");
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny restrict_access_by_env(NULL, FALSE);
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny restrict_access_allow_coredumps(TRUE);
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny master_service_init_finish(master_service);
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny main_init();
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny director->test_port = test_port;
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny director->debug = debug;
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny director_connect(director);
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny if (director->test_port != 0) {
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny /* we're testing, possibly writing to same log file.
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny make it clear which director we are. */
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny master_service_init_log(master_service,
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny t_strdup_printf("director(%s): ",
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny net_ip2addr(&director->self_ip)));
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny }
d3f2fd9cb21cc10dce663a2f7d0deda07074e44eJan Zeleny
d3f2fd9cb21cc10dce663a2f7d0deda07074e44eJan Zeleny master_service_run(master_service, client_connected);
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny main_deinit();
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny master_service_deinit(&master_service);
20d0bc6d587f346238062df4da5edfde815e59b1Jan Zeleny return 0;
b8dcd1216e5ea7065213c750a92dabfe01fa3b70Simo Sorce}
b8dcd1216e5ea7065213c750a92dabfe01fa3b70Simo Sorce