main.c revision 69b22a0c0c84087e5bdeec71faae7ea77295240f
1923N/A/* Copyright (c) 2010-2011 Dovecot authors, see the included COPYING file */
12N/A
1923N/A#include "lib.h"
1923N/A#include "ioloop.h"
1923N/A#include "array.h"
1923N/A#include "restrict-access.h"
1923N/A#include "master-interface.h"
1923N/A#include "master-service.h"
1923N/A#include "master-service-settings.h"
1923N/A#include "auth-connection.h"
293N/A#include "doveadm-connection.h"
1923N/A#include "login-connection.h"
1923N/A#include "notify-connection.h"
1923N/A#include "director.h"
1923N/A#include "director-host.h"
1923N/A#include "director-connection.h"
1923N/A#include "director-request.h"
1923N/A#include "mail-host.h"
1923N/A
1923N/A#include <stdio.h>
1923N/A#include <unistd.h>
1923N/A
1923N/A#define AUTH_SOCKET_PATH "auth-login"
1923N/A#define AUTH_USERDB_SOCKET_PATH "auth-userdb"
1923N/A
1923N/Astatic struct director *director;
12N/Astatic struct notify_connection *notify_conn;
12N/A
12N/Astatic int director_client_connected(int fd, const struct ip_addr *ip)
12N/A{
12N/A if (director_host_lookup_ip(director, ip) == NULL) {
293N/A i_warning("Connection from %s: Server not listed in "
293N/A "director_servers, dropping", net_ip2addr(ip));
293N/A return -1;
293N/A }
293N/A
293N/A director_connection_init_in(director, fd, ip);
293N/A return 0;
12N/A}
12N/A
12N/Astatic void client_connected(struct master_service_connection *conn)
12N/A{
1923N/A struct auth_connection *auth;
1923N/A const char *socket_path;
1923N/A struct ip_addr ip;
1923N/A unsigned int local_port, len;
1923N/A bool userdb;
1923N/A
1923N/A if (conn->fifo) {
1923N/A if (notify_conn != NULL) {
1923N/A i_error("Received another proxy-notify connection");
1923N/A return;
1923N/A }
1923N/A master_service_client_connection_accept(conn);
1923N/A notify_conn = notify_connection_init(director, conn->fd);
1923N/A return;
1923N/A }
1923N/A
1923N/A if (net_getpeername(conn->fd, &ip, NULL) == 0 &&
1923N/A net_getsockname(conn->fd, NULL, &local_port) == 0 &&
1923N/A (IPADDR_IS_V4(&ip) || IPADDR_IS_V6(&ip))) {
1923N/A /* TCP/IP connection */
1923N/A if (local_port == director->set->director_doveadm_port) {
1923N/A master_service_client_connection_accept(conn);
1923N/A (void)doveadm_connection_init(director, conn->fd);
1923N/A } else {
1923N/A if (director_client_connected(conn->fd, &ip) == 0)
1923N/A master_service_client_connection_accept(conn);
1923N/A }
12N/A return;
293N/A }
293N/A
293N/A len = strlen(conn->name);
1923N/A if (len > 6 && strcmp(conn->name + len - 6, "-admin") == 0) {
1923N/A /* doveadm connection */
1923N/A master_service_client_connection_accept(conn);
1923N/A (void)doveadm_connection_init(director, conn->fd);
1923N/A return;
1923N/A }
12N/A
12N/A /* a) userdb connection, probably for lmtp proxy
12N/A b) login connection
12N/A Both of them are handled exactly the same, except for which
12N/A auth socket they connect to. */
1923N/A userdb = len > 7 && strcmp(conn->name + len - 7, "-userdb") == 0;
1923N/A socket_path = userdb ? AUTH_USERDB_SOCKET_PATH : AUTH_SOCKET_PATH;
1923N/A auth = auth_connection_init(socket_path);
293N/A if (auth_connection_connect(auth) == 0) {
293N/A master_service_client_connection_accept(conn);
293N/A login_connection_init(director, conn->fd, auth, userdb);
293N/A } else {
293N/A auth_connection_deinit(&auth);
293N/A }
293N/A}
293N/A
293N/Astatic unsigned int
293N/Afind_inet_listener_port(struct ip_addr *ip_r,
293N/A const struct director_settings *set)
1923N/A{
105N/A unsigned int i, socket_count, port;
105N/A
105N/A socket_count = master_service_get_socket_count(master_service);
105N/A for (i = 0; i < socket_count; i++) {
105N/A int fd = MASTER_LISTEN_FD_FIRST + i;
105N/A
105N/A if (net_getsockname(fd, ip_r, &port) == 0 && port > 0 &&
105N/A port != set->director_doveadm_port)
105N/A return port;
105N/A }
105N/A return 0;
105N/A}
105N/A
105N/Astatic void director_state_changed(struct director *dir)
105N/A{
105N/A struct director_request *const *requestp;
105N/A bool ret;
1923N/A
1923N/A if (!dir->ring_synced ||
1923N/A mail_host_get_by_hash(dir->mail_hosts, 0) == NULL)
293N/A return;
293N/A
293N/A /* if there are any pending client requests, finish them now */
293N/A array_foreach(&dir->pending_requests, requestp) {
1923N/A ret = director_request_continue(*requestp);
105N/A i_assert(ret);
105N/A }
293N/A array_clear(&dir->pending_requests);
293N/A
1923N/A if (dir->to_request != NULL)
293N/A timeout_remove(&dir->to_request);
1923N/A}
1923N/A
1923N/Astatic void main_preinit(void)
1923N/A{
1923N/A const struct director_settings *set;
1923N/A struct ip_addr listen_ip;
1923N/A unsigned int listen_port;
1923N/A
1923N/A set = master_service_settings_get_others(master_service)[0];
1923N/A
1923N/A listen_port = find_inet_listener_port(&listen_ip, set);
1923N/A if (listen_port == 0 && *set->director_servers != '\0') {
1923N/A i_fatal("No inet_listeners defined for director service "
1923N/A "(for standalone keep director_servers empty)");
1923N/A }
1923N/A
1923N/A director = director_init(set, &listen_ip, listen_port,
1923N/A director_state_changed);
1923N/A director_host_add_from_string(director, set->director_servers);
1923N/A director_find_self(director);
1923N/A if (mail_hosts_parse_and_add(director->mail_hosts,
1923N/A set->director_mail_servers) < 0)
1923N/A i_fatal("Invalid value for director_mail_servers setting");
1923N/A director->orig_config_hosts = mail_hosts_dup(director->mail_hosts);
1923N/A
1923N/A restrict_access_by_env(NULL, FALSE);
1923N/A restrict_access_allow_coredumps(TRUE);
1923N/A}
1923N/A
1923N/Astatic void main_deinit(void)
1923N/A{
1923N/A if (notify_conn != NULL)
1923N/A notify_connection_deinit(&notify_conn);
1923N/A director_deinit(&director);
1923N/A doveadm_connections_deinit();
1923N/A login_connections_deinit();
1923N/A auth_connections_deinit();
1923N/A}
1923N/A
1923N/Aint main(int argc, char *argv[])
1923N/A{
1923N/A const struct setting_parser_info *set_roots[] = {
1923N/A &director_setting_parser_info,
1923N/A NULL
1923N/A };
1923N/A const enum master_service_flags service_flags =
1923N/A MASTER_SERVICE_FLAG_NO_IDLE_DIE |
1923N/A MASTER_SERVICE_FLAG_UPDATE_PROCTITLE;
1923N/A unsigned int test_port = 0;
1923N/A const char *error;
1923N/A bool debug = FALSE;
1923N/A int c;
1923N/A
1923N/A master_service = master_service_init("director", service_flags,
1923N/A &argc, &argv, "Dt:");
1923N/A while ((c = master_getopt(master_service)) > 0) {
1923N/A switch (c) {
1923N/A case 'D':
1923N/A debug = TRUE;
1923N/A break;
1923N/A case 't':
1923N/A if (str_to_uint(optarg, &test_port) < 0)
1923N/A i_fatal("-t: Not a number: %s", optarg);
1923N/A break;
1923N/A default:
1923N/A return FATAL_DEFAULT;
1923N/A }
1923N/A }
1923N/A if (master_service_settings_read_simple(master_service, set_roots,
1923N/A &error) < 0)
1923N/A i_fatal("Error reading configuration: %s", error);
1923N/A
1923N/A master_service_init_log(master_service, "director: ");
1923N/A
1923N/A main_preinit();
1923N/A master_service_init_finish(master_service);
1923N/A director->test_port = test_port;
1923N/A director->debug = debug;
1923N/A director_connect(director);
1923N/A
1923N/A if (director->test_port != 0) {
1923N/A /* we're testing, possibly writing to same log file.
1923N/A make it clear which director we are. */
1923N/A master_service_init_log(master_service,
1923N/A t_strdup_printf("director(%s): ",
1923N/A net_ip2addr(&director->self_ip)));
1923N/A }
1923N/A
1923N/A master_service_run(master_service, client_connected);
1923N/A main_deinit();
1923N/A
1923N/A master_service_deinit(&master_service);
1923N/A return 0;
1923N/A}
1923N/A