Mercurial > dovecot > original-hg > dovecot-1.2
view src/auth/main.c @ 2708:f1e9f3ec8135 HEAD
Buffer API change: we no longer support limited sized buffers where
writes past limit wouldn't kill the process. They weren't used hardly
anywhere, they could have hidden bugs and the code for handling them was too
complex.
This also changed base64 and hex-binary APIs.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 08 Oct 2004 20:51:47 +0300 |
parents | ec268f32e69e |
children | ea37520d92e3 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "common.h" #include "buffer.h" #include "ioloop.h" #include "network.h" #include "lib-signals.h" #include "restrict-access.h" #include "fd-close-on-exec.h" #include "randgen.h" #include "mech.h" #include "userdb.h" #include "passdb.h" #include "password-scheme.h" #include "auth-master-connection.h" #include "auth-client-connection.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <syslog.h> #include <pwd.h> #include <grp.h> #include <sys/stat.h> struct ioloop *ioloop; int verbose = FALSE, verbose_debug = FALSE; int standalone = FALSE; static buffer_t *masters_buf; static void sig_quit(int signo __attr_unused__) { io_loop_stop(ioloop); } static void open_logfile(void) { if (getenv("LOG_TO_MASTER") != NULL) { i_set_failure_internal(); return; } if (getenv("USE_SYSLOG") != NULL) i_set_failure_syslog("dovecot-auth", LOG_NDELAY, LOG_MAIL); else { /* log to file or stderr */ i_set_failure_file(getenv("LOGFILE"), "dovecot-auth"); } if (getenv("INFOLOGFILE") != NULL) i_set_info_file(getenv("INFOLOGFILE")); i_set_failure_timestamp_format(getenv("LOGSTAMP")); } static void drop_privileges(void) { unsigned int seed; verbose = getenv("VERBOSE") != NULL; verbose_debug = getenv("VERBOSE_DEBUG") != NULL; open_logfile(); /* Open /dev/urandom before chrooting */ random_init(); random_fill(&seed, sizeof(seed)); srand(seed); /* Initialize databases so their configuration files can be readable only by root. Also load all modules here. */ userdb_preinit(); passdb_preinit(); password_schemes_init(); /* Password lookups etc. may require roots, allow it. */ restrict_access_by_env(FALSE); } static uid_t get_uid(const char *user) { struct passwd *pw; if (user == NULL) return (uid_t)-1; if ((pw = getpwnam(user)) == NULL) i_fatal("User doesn't exist: %s", user); return pw->pw_uid; } static gid_t get_gid(const char *group) { struct group *gr; if (group == NULL) return (gid_t)-1; if ((gr = getgrnam(group)) == NULL) i_fatal("Group doesn't exist: %s", group); return gr->gr_gid; } static int create_unix_listener(const char *env) { const char *path, *mode, *user, *group; mode_t old_umask; unsigned int mask; uid_t uid; gid_t gid; int fd, i; path = getenv(env); if (path == NULL) return -1; mode = getenv(t_strdup_printf("%s_MODE", env)); if (mode == NULL) mask = 0177; /* default to 0600 */ else { if (sscanf(mode, "%o", &mask) != 1) i_fatal("%s: Invalid mode %s", env, mode); mask = (mask ^ 0777) & 0777; } old_umask = umask(mask); for (i = 0; i < 5; i++) { fd = net_listen_unix(path); if (fd != -1) break; if (errno != EADDRINUSE) i_fatal("net_listen_unix(%s) failed: %m", path); /* see if it really exists */ if (net_connect_unix(path) != -1 || errno != ECONNREFUSED) i_fatal("Socket already exists: %s", path); /* delete and try again */ if (unlink(path) < 0) i_fatal("unlink(%s) failed: %m", path); } umask(old_umask); user = getenv(t_strdup_printf("%s_USER", env)); group = getenv(t_strdup_printf("%s_GROUP", env)); uid = get_uid(user); gid = get_gid(group); if (chown(path, uid, gid) < 0) { i_fatal("chown(%s, %s, %s) failed: %m", path, dec2str(uid), dec2str(gid)); } return fd; } static void add_extra_listeners(void) { struct auth_master_connection *master; const char *str, *client_path, *master_path; int client_fd, master_fd; unsigned int i; for (i = 1;; i++) { t_push(); client_path = getenv(t_strdup_printf("AUTH_%u", i)); master_path = getenv(t_strdup_printf("AUTH_%u_MASTER", i)); if (client_path == NULL && master_path == NULL) { t_pop(); break; } str = t_strdup_printf("AUTH_%u", i); client_fd = create_unix_listener(str); str = t_strdup_printf("AUTH_%u_MASTER", i); master_fd = create_unix_listener(str); master = auth_master_connection_create(-1, getpid()); if (master_fd != -1) { auth_master_connection_add_listener(master, master_fd, master_path, FALSE); } if (client_fd != -1) { auth_master_connection_add_listener(master, client_fd, client_path, TRUE); } auth_client_connections_init(master); buffer_append(masters_buf, &master, sizeof(master)); t_pop(); } } static void main_init(int nodaemon) { struct auth_master_connection *master, **master_p; size_t i, size; const char *env; unsigned int pid; userdb_init(); passdb_init(); lib_init_signals(sig_quit); mech_init(); masters_buf = buffer_create_dynamic(default_pool, 64); env = getenv("AUTH_PROCESS"); standalone = env == NULL; if (standalone) { /* starting standalone */ if (getenv("AUTH_1") == NULL) { i_fatal("dovecot-auth is usually started through " "dovecot master process. If you wish to run " "it standalone, you'll need to set AUTH_* " "environment variables (AUTH_1 isn't set)."); } if (!nodaemon) { switch (fork()) { case -1: i_fatal("fork() failed: %m"); case 0: break; default: exit(0); } if (setsid() < 0) i_fatal("setsid() failed: %m"); if (chdir("/") < 0) i_fatal("chdir(/) failed: %m"); } } else { pid = atoi(env); if (pid == 0) i_fatal("AUTH_PROCESS can't be 0"); master = auth_master_connection_create(MASTER_SOCKET_FD, pid); auth_master_connection_add_listener(master, LOGIN_LISTEN_FD, NULL, TRUE); auth_client_connections_init(master); buffer_append(masters_buf, &master, sizeof(master)); } add_extra_listeners(); /* everything initialized, notify masters that all is well */ master_p = buffer_get_modifyable_data(masters_buf, &size); size /= sizeof(*master_p); for (i = 0; i < size; i++) auth_master_connection_send_handshake(master_p[i]); } static void main_deinit(void) { struct auth_master_connection **master; size_t i, size; if (lib_signal_kill != 0) i_warning("Killed with signal %d", lib_signal_kill); auth_failure_buf_flush(); master = buffer_get_modifyable_data(masters_buf, &size); size /= sizeof(*master); for (i = 0; i < size; i++) auth_master_connection_destroy(master[i]); password_schemes_deinit(); passdb_deinit(); userdb_deinit(); mech_deinit(); random_deinit(); closelog(); } int main(int argc, char *argv[]) { #ifdef DEBUG if (getenv("GDB") == NULL) fd_debug_verify_leaks(4, 1024); #endif /* NOTE: we start rooted, so keep the code minimal until restrict_access_by_env() is called */ lib_init(); drop_privileges(); ioloop = io_loop_create(system_pool); main_init(argc > 1 && strcmp(argv[1], "-F") == 0); io_loop_run(ioloop); main_deinit(); io_loop_destroy(ioloop); lib_deinit(); return 0; }