Mercurial > dovecot > original-hg > dovecot-1.2
view src/imap/main.c @ 9266:cd29b745c8dd HEAD
configure: clock_gettime()'s -lrt adding dropped everything else from $LIBS.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 27 Jul 2009 06:32:42 -0400 |
parents | 8f376b8ce81d |
children | 00cd9aacd03c |
line wrap: on
line source
/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */ #include "common.h" #include "ioloop.h" #include "network.h" #include "ostream.h" #include "str.h" #include "base64.h" #include "istream.h" #include "lib-signals.h" #include "restrict-access.h" #include "fd-close-on-exec.h" #include "process-title.h" #include "module-dir.h" #include "dict.h" #include "mail-storage.h" #include "commands.h" #include "imap-fetch.h" #include "mail-namespace.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <syslog.h> #define IS_STANDALONE() \ (getenv("IMAPLOGINTAG") == NULL) struct client_workaround_list { const char *name; enum client_workarounds num; }; static struct client_workaround_list client_workaround_list[] = { { "delay-newmail", WORKAROUND_DELAY_NEWMAIL }, { "outlook-idle", 0 }, /* only for backwards compatibility */ { "netscape-eoh", WORKAROUND_NETSCAPE_EOH }, { "tb-extra-mailbox-sep", WORKAROUND_TB_EXTRA_MAILBOX_SEP }, { NULL, 0 } }; struct ioloop *ioloop; unsigned int imap_max_line_length; enum client_workarounds client_workarounds = 0; const char *logout_format; const char *imap_id_send, *imap_id_log; static struct io *log_io = NULL; static struct module *modules = NULL; static char log_prefix[128]; /* syslog() needs this to be permanent */ void (*hook_client_created)(struct client **client) = NULL; string_t *capability_string; static void sig_die(const siginfo_t *si, void *context ATTR_UNUSED) { /* warn about being killed because of some signal, except SIGINT (^C) which is too common at least while testing :) */ if (si->si_signo != SIGINT) { i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)", si->si_signo, dec2str(si->si_pid), dec2str(si->si_uid), lib_signal_code_to_str(si->si_signo, si->si_code)); } io_loop_stop(ioloop); } static void log_error_callback(void *context ATTR_UNUSED) { /* the log fd is closed, don't die when trying to log later */ i_set_failure_ignore_errors(TRUE); io_loop_stop(ioloop); } static void parse_workarounds(void) { struct client_workaround_list *list; const char *env, *const *str; env = getenv("IMAP_CLIENT_WORKAROUNDS"); if (env == NULL) return; for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) { list = client_workaround_list; for (; list->name != NULL; list++) { if (strcasecmp(*str, list->name) == 0) { client_workarounds |= list->num; break; } } if (list->name == NULL) i_fatal("Unknown client workaround: %s", *str); } } static void open_logfile(void) { const char *user; if (getenv("LOG_TO_MASTER") != NULL) { i_set_failure_internal(); return; } if (getenv("LOG_PREFIX") != NULL) i_strocpy(log_prefix, getenv("LOG_PREFIX"), sizeof(log_prefix)); else { user = getenv("USER"); if (user == NULL) { if (IS_STANDALONE()) user = getlogin(); if (user == NULL) user = "??"; } if (strlen(user) >= sizeof(log_prefix)-6) { /* quite a long user name, cut it */ user = t_strndup(user, sizeof(log_prefix)-6-2); user = t_strconcat(user, "..", NULL); } i_snprintf(log_prefix, sizeof(log_prefix), "imap(%s): ", user); } if (getenv("USE_SYSLOG") != NULL) { const char *env = getenv("SYSLOG_FACILITY"); i_set_failure_syslog(log_prefix, LOG_NDELAY, env == NULL ? LOG_MAIL : atoi(env)); } else { /* log to file or stderr */ i_set_failure_file(getenv("LOGFILE"), log_prefix); } if (getenv("INFOLOGFILE") != NULL) i_set_info_file(getenv("INFOLOGFILE")); i_set_failure_timestamp_format(getenv("LOGSTAMP")); } static void drop_privileges(void) { const char *version; version = getenv("DOVECOT_VERSION"); if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) { i_fatal("Dovecot version mismatch: " "Master is v%s, imap is v"PACKAGE_VERSION" " "(if you don't care, set version_ignore=yes)", version); } /* Log file or syslog opening probably requires roots */ open_logfile(); /* Load the plugins before chrooting. Their init() is called later. */ if (getenv("MAIL_PLUGINS") != NULL) { const char *plugin_dir = getenv("MAIL_PLUGIN_DIR"); if (plugin_dir == NULL) plugin_dir = MODULEDIR"/imap"; modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"), TRUE, version); } restrict_access_by_env(!IS_STANDALONE()); restrict_access_allow_coredumps(TRUE); } static void main_init(void) { struct client *client; struct ostream *output; struct mail_user *user; const char *username, *home, *str, *tag; lib_signals_init(); lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL); lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL); lib_signals_ignore(SIGPIPE, TRUE); lib_signals_ignore(SIGALRM, FALSE); username = getenv("USER"); if (username == NULL && IS_STANDALONE()) username = getlogin(); if (username == NULL) { if (getenv("DOVECOT_MASTER") == NULL) i_fatal("USER environment missing"); else { i_fatal("login_executable setting must be imap-login, " "not imap"); } } home = getenv("HOME"); if (getenv("DEBUG") != NULL) { i_info("Effective uid=%s, gid=%s, home=%s", dec2str(geteuid()), dec2str(getegid()), home != NULL ? home : "(none)"); } if (getenv("STDERR_CLOSE_SHUTDOWN") != NULL) { /* If master dies, the log fd gets closed and we'll quit */ log_io = io_add(STDERR_FILENO, IO_ERROR, log_error_callback, NULL); } capability_string = str_new(default_pool, sizeof(CAPABILITY_STRING)+32); str_append(capability_string, CAPABILITY_STRING); dict_drivers_register_builtin(); mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL); mail_storage_init(); mail_storage_register_all(); mailbox_list_register_all(); clients_init(); commands_init(); imap_fetch_handlers_init(); module_dir_init(modules); if (getenv("DUMP_CAPABILITY") != NULL) { printf("%s\n", str_c(capability_string)); exit(0); } str = getenv("IMAP_CAPABILITY"); if (str != NULL && *str != '\0') { /* Overrides all capabilities */ str_truncate(capability_string, 0); str_append(capability_string, str); } str = getenv("IMAP_MAX_LINE_LENGTH"); imap_max_line_length = str != NULL ? (unsigned int)strtoul(str, NULL, 10) : DEFAULT_IMAP_MAX_LINE_LENGTH; logout_format = getenv("IMAP_LOGOUT_FORMAT"); if (logout_format == NULL) logout_format = "bytes=%i/%o"; imap_id_send = getenv("IMAP_ID_SEND"); imap_id_log = getenv("IMAP_ID_LOG"); parse_workarounds(); user = mail_user_init(username); mail_user_set_home(user, home); if (mail_namespaces_init(user) < 0) i_fatal("Namespace initialization failed"); client = client_create(0, 1, user); output = client->output; o_stream_ref(output); o_stream_cork(output); /* IMAPLOGINTAG environment is compatible with mailfront */ tag = getenv("IMAPLOGINTAG"); if (tag == NULL) { client_send_line(client, t_strconcat( "* PREAUTH [CAPABILITY ", str_c(capability_string), "] " "Logged in as ", user->username, NULL)); } else { client_send_line(client, t_strconcat( tag, " OK [CAPABILITY ", str_c(capability_string), "] Logged in", NULL)); } str = getenv("CLIENT_INPUT"); if (str != NULL) T_BEGIN { buffer_t *buf = t_base64_decode_str(str); if (buf->used > 0) { if (!i_stream_add_data(client->input, buf->data, buf->used)) i_panic("Couldn't add client input to stream"); (void)client_handle_input(client); } } T_END; o_stream_uncork(output); o_stream_unref(&output); } static void main_deinit(void) { if (log_io != NULL) io_remove(&log_io); clients_deinit(); module_dir_unload(&modules); imap_fetch_handlers_deinit(); commands_deinit(); mail_storage_deinit(); mail_users_deinit(); dict_drivers_unregister_builtin(); str_free(&capability_string); lib_signals_deinit(); closelog(); } int main(int argc ATTR_UNUSED, char *argv[], char *envp[]) { #ifdef DEBUG if (!IS_STANDALONE() && getenv("GDB") == NULL) fd_debug_verify_leaks(3, 1024); #endif if (IS_STANDALONE() && getuid() == 0 && net_getpeername(1, NULL, NULL) == 0) { printf("* BAD [ALERT] imap binary must not be started from " "inetd, use imap-login instead.\n"); return 1; } /* NOTE: we start rooted, so keep the code minimal until restrict_access_by_env() is called */ lib_init(); drop_privileges(); process_title_init(argv, envp); ioloop = io_loop_create(); /* fake that we're running, so we know if client was destroyed while initializing */ io_loop_set_running(ioloop); main_init(); if (io_loop_is_running(ioloop)) io_loop_run(ioloop); main_deinit(); io_loop_destroy(&ioloop); lib_deinit(); return 0; }