main.c revision bbadd5331f534017cf62d5183003b3d9fdad079e
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "auth-common.h"
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch#include "array.h"
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch#include "ioloop.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "network.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "lib-signals.h"
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch#include "restrict-access.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "child-wait.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "sql-api.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "module-dir.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "randgen.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "process-title.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "settings-parser.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "master-service.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "master-service-settings.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "master-interface.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "password-scheme.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "passdb-cache.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "mech.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "auth.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "auth-penalty.h"
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch#include "auth-request-handler.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "auth-worker-server.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "auth-worker-client.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "auth-master-connection.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "auth-client-connection.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include <unistd.h>
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#define AUTH_PENALTY_ANVIL_PATH "anvil-auth-penalty"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschenum auth_socket_type {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch AUTH_SOCKET_UNKNOWN = 0,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch AUTH_SOCKET_CLIENT,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch AUTH_SOCKET_LOGIN_CLIENT,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch AUTH_SOCKET_MASTER,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch AUTH_SOCKET_USERDB
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch};
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschbool worker = FALSE, shutdown_request = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschtime_t process_start_time;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstruct auth_penalty *auth_penalty;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic pool_t auth_set_pool;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic struct module *modules = NULL;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic struct mechanisms_register *mech_reg;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic ARRAY_DEFINE(listen_fd_types, enum auth_socket_type);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvoid auth_refresh_proctitle(void)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!global_auth_settings->verbose_proctitle)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch process_title_set(t_strdup_printf(
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "[%u wait, %u passdb, %u userdb]",
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen auth_request_state_count[AUTH_REQUEST_STATE_NEW] +
dc78180b54a05d5736d0e0e444cba0332265eb62Phil Carmody auth_request_state_count[AUTH_REQUEST_STATE_MECH_CONTINUE] +
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen auth_request_state_count[AUTH_REQUEST_STATE_FINISHED],
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen auth_request_state_count[AUTH_REQUEST_STATE_PASSDB],
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request_state_count[AUTH_REQUEST_STATE_USERDB]));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic const char *const *read_global_settings(void)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch struct master_service_settings_output set_output;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch const char **services;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_set_pool = pool_alloconly_create("auth settings", 8192);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch global_auth_settings =
auth_settings_read(NULL, auth_set_pool, &set_output);
/* strdup() the service names, because they're allocated from
set parser pool, and we'll later clear it. */
count = str_array_length(set_output.specific_services);
services = p_new(auth_set_pool, const char *, count + 1);
for (i = 0; i < count; i++) {
services[i] = p_strdup(auth_set_pool,
set_output.specific_services[i]);
}
return services;
}
static void main_preinit(void)
{
struct module_dir_load_settings mod_set;
const char *const *services;
/* Open /dev/urandom before chrooting */
random_init();
/* Load built-in SQL drivers (if any) */
sql_drivers_init();
sql_drivers_register_all();
/* Initialize databases so their configuration files can be readable
only by root. Also load all modules here. */
passdbs_init();
userdbs_init();
services = read_global_settings();
memset(&mod_set, 0, sizeof(mod_set));
mod_set.version = master_service_get_version_string(master_service);
mod_set.require_init_funcs = TRUE;
mod_set.debug = global_auth_settings->debug;
modules = module_dir_load(AUTH_MODULE_DIR, NULL, &mod_set);
module_dir_init(modules);
auth_penalty = auth_penalty_init(AUTH_PENALTY_ANVIL_PATH);
mech_init(global_auth_settings);
mech_reg = mech_register_init(global_auth_settings);
auths_preinit(global_auth_settings, auth_set_pool,
mech_reg, services);
/* Password lookups etc. may require roots, allow it. */
restrict_access_by_env(NULL, FALSE);
restrict_access_allow_coredumps(TRUE);
}
static void main_init(void)
{
i_array_init(&listen_fd_types, 8);
process_start_time = ioloop_time;
/* If auth caches aren't used, just ignore these signals */
lib_signals_ignore(SIGHUP, TRUE);
lib_signals_ignore(SIGUSR2, TRUE);
child_wait_init();
password_schemes_init();
auth_worker_server_init();
auths_init();
auth_request_handler_init();
auth_master_connections_init();
auth_client_connections_init();
if (worker) {
/* workers have only a single connection from the master
auth process */
master_service_set_client_limit(master_service, 1);
} else {
/* caching is handled only by the main auth process */
passdb_cache_init(global_auth_settings);
}
auth_refresh_proctitle();
}
static void main_deinit(void)
{
if (auth_worker_client != NULL)
auth_worker_client_destroy(&auth_worker_client);
else
auth_request_handler_flush_failures(TRUE);
auth_client_connections_deinit();
auth_master_connections_deinit();
auth_worker_server_deinit();
auths_deinit();
auth_request_handler_deinit();
passdb_cache_deinit();
mech_register_deinit(&mech_reg);
mech_deinit(global_auth_settings);
auth_penalty_deinit(&auth_penalty);
/* allow modules to unregister their dbs/drivers/etc. before freeing
the whole data structures containing them. */
module_dir_unload(&modules);
userdbs_deinit();
passdbs_deinit();
password_schemes_deinit();
sql_drivers_deinit();
random_deinit();
array_free(&listen_fd_types);
pool_unref(&auth_set_pool);
}
static void worker_connected(const struct master_service_connection *conn)
{
if (auth_worker_client != NULL) {
i_error("Auth workers can handle only a single client");
(void)close(conn->fd);
return;
}
(void)auth_worker_client_create(auth_find_service(NULL), conn->fd);
}
static void client_connected(const struct master_service_connection *conn)
{
enum auth_socket_type *type;
const char *path, *name, *suffix;
struct auth *auth;
type = array_idx_modifiable(&listen_fd_types, conn->listen_fd);
if (*type == AUTH_SOCKET_UNKNOWN) {
/* figure out if this is a server or network socket by
checking the socket path name. */
if (net_getunixname(conn->listen_fd, &path) < 0)
i_fatal("getsockname(%d) failed: %m", conn->listen_fd);
name = strrchr(path, '/');
if (name == NULL)
name = path;
else
name++;
suffix = strrchr(name, '-');
if (suffix == NULL)
suffix = name;
else
suffix++;
if (strcmp(suffix, "login") == 0)
*type = AUTH_SOCKET_LOGIN_CLIENT;
else if (strcmp(suffix, "master") == 0)
*type = AUTH_SOCKET_MASTER;
else if (strcmp(suffix, "userdb") == 0)
*type = AUTH_SOCKET_USERDB;
else
*type = AUTH_SOCKET_CLIENT;
}
auth = auth_find_service(NULL);
switch (*type) {
case AUTH_SOCKET_MASTER:
(void)auth_master_connection_create(auth, conn->fd, FALSE);
break;
case AUTH_SOCKET_USERDB:
(void)auth_master_connection_create(auth, conn->fd, TRUE);
break;
case AUTH_SOCKET_LOGIN_CLIENT:
(void)auth_client_connection_create(auth, conn->fd, TRUE);
break;
case AUTH_SOCKET_CLIENT:
(void)auth_client_connection_create(auth, conn->fd, FALSE);
break;
default:
i_unreached();
}
}
int main(int argc, char *argv[])
{
int c;
master_service = master_service_init("auth", 0, &argc, &argv, "w");
master_service_init_log(master_service, "auth: ");
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'w':
worker = TRUE;
break;
default:
return FATAL_DEFAULT;
}
}
main_preinit();
master_service_init_finish(master_service);
main_init();
master_service_run(master_service, worker ? worker_connected :
client_connected);
main_deinit();
master_service_deinit(&master_service);
return 0;
}