main.c revision 174a54c74848b8668acd72ddf36d9b4745e1ad5e
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen/* Copyright (C) 2002-2003 Timo Sirainen */
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "common.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "ioloop.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "file-lock.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "network.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "lib-signals.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "restrict-access.h"
aa78a2506ee69a6bd58cc706210ee79b62ec0954Timo Sirainen#include "fd-close-on-exec.h"
9e708a17f984ef7690ff2468ec19ad62c95b1ac2Timo Sirainen#include "process-title.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "randgen.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "module-dir.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "var-expand.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "dict-client.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include "mail-storage.h"
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include <stdio.h>
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include <stdlib.h>
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen#include <unistd.h>
9e708a17f984ef7690ff2468ec19ad62c95b1ac2Timo Sirainen#include <syslog.h>
8f1d14e3ada93a6d6ee64f73c6e6ae2364d8eba1Timo Sirainen
8f1d14e3ada93a6d6ee64f73c6e6ae2364d8eba1Timo Sirainen#define IS_STANDALONE() \
8f1d14e3ada93a6d6ee64f73c6e6ae2364d8eba1Timo Sirainen (getenv("LOGGED_IN") == NULL)
9e708a17f984ef7690ff2468ec19ad62c95b1ac2Timo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstruct client_workaround_list {
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen const char *name;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen enum client_workarounds num;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen};
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstruct client_workaround_list client_workaround_list[] = {
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen { "outlook-no-nuls", WORKAROUND_OUTLOOK_NO_NULS },
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen { "oe-ns-eoh", WORKAROUND_OE_NS_EOH },
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen { NULL, 0 }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen};
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstruct ioloop *ioloop;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenvoid (*hook_client_created)(struct client **client) = NULL;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstatic struct module *modules = NULL;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstatic char log_prefix[128]; /* syslog() needs this to be permanent */
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstatic struct io *log_io = NULL;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenenum client_workarounds client_workarounds = 0;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenbool enable_last_command = FALSE;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenbool no_flag_updates = FALSE;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenbool reuse_xuidl = FALSE;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenbool lock_session = FALSE;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenconst char *uidl_format, *logout_format;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenenum uidl_keys uidl_keymask;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstatic void sig_die(int signo, void *context __attr_unused__)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen{
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen which is too common at least while testing :) */
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (signo != SIGINT)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen i_warning("Killed with signal %d", signo);
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen io_loop_stop(ioloop);
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen}
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstatic void log_error_callback(void *context __attr_unused__)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen{
aa78a2506ee69a6bd58cc706210ee79b62ec0954Timo Sirainen io_loop_stop(ioloop);
aa78a2506ee69a6bd58cc706210ee79b62ec0954Timo Sirainen}
aa78a2506ee69a6bd58cc706210ee79b62ec0954Timo Sirainen
aa78a2506ee69a6bd58cc706210ee79b62ec0954Timo Sirainenstatic void parse_workarounds(void)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen{
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen struct client_workaround_list *list;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen const char *env, *const *str;
67b785ce2485243c490f0a8b0753ac4a5d347265Timo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen env = getenv("POP3_CLIENT_WORKAROUNDS");
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (env == NULL)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen return;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) {
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen list = client_workaround_list;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen for (; list->name != NULL; list++) {
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (strcasecmp(*str, list->name) == 0) {
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen client_workarounds |= list->num;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen break;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
9e708a17f984ef7690ff2468ec19ad62c95b1ac2Timo Sirainen if (list->name == NULL)
9e708a17f984ef7690ff2468ec19ad62c95b1ac2Timo Sirainen i_fatal("Unknown client workaround: %s", *str);
9e708a17f984ef7690ff2468ec19ad62c95b1ac2Timo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen}
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstatic enum uidl_keys parse_uidl_keymask(const char *format)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen{
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen enum uidl_keys mask = 0;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen for (; *format != '\0'; format++) {
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (format[0] == '%' && format[1] != '\0') {
b728c54e411fd1964195497572ab7066138206cbTimo Sirainen switch (var_get_key(++format)) {
b728c54e411fd1964195497572ab7066138206cbTimo Sirainen case 'v':
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen mask |= UIDL_UIDVALIDITY;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen break;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen case 'u':
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen mask |= UIDL_UID;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen break;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen case 'm':
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen mask |= UIDL_MD5;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen break;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen case 'f':
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen mask |= UIDL_FILE_NAME;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen break;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen return mask;
8f1d14e3ada93a6d6ee64f73c6e6ae2364d8eba1Timo Sirainen}
8f1d14e3ada93a6d6ee64f73c6e6ae2364d8eba1Timo Sirainen
8f1d14e3ada93a6d6ee64f73c6e6ae2364d8eba1Timo Sirainenstatic void open_logfile(void)
966e9213f116ae8423634433106b02c833d9376bTimo Sirainen{
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen const char *user;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (getenv("LOG_TO_MASTER") != NULL) {
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen i_set_failure_internal();
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen return;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (getenv("LOG_PREFIX") != NULL)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen strocpy(log_prefix, getenv("LOG_PREFIX"), sizeof(log_prefix));
9e708a17f984ef7690ff2468ec19ad62c95b1ac2Timo Sirainen else {
9e708a17f984ef7690ff2468ec19ad62c95b1ac2Timo Sirainen user = getenv("USER");
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (user == NULL) user = "??";
18d788657cff0fc3905b6a484d33c8c9fc2b9ebaTimo Sirainen if (strlen(user) >= sizeof(log_prefix)-6) {
aa78a2506ee69a6bd58cc706210ee79b62ec0954Timo Sirainen /* quite a long user name, cut it */
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen user = t_strndup(user, sizeof(log_prefix)-6-2);
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen user = t_strconcat(user, "..", NULL);
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen i_snprintf(log_prefix, sizeof(log_prefix), "pop3(%s): ", user);
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (getenv("USE_SYSLOG") != NULL) {
4f2a24a029bf3e088cc2f804e051a1430bdb4db3Timo Sirainen const char *env = getenv("SYSLOG_FACILITY");
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen i_set_failure_syslog(log_prefix, LOG_NDELAY,
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen env == NULL ? LOG_MAIL : atoi(env));
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen } else {
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen /* log to file or stderr */
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen i_set_failure_file(getenv("LOGFILE"), log_prefix);
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen }
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (getenv("INFOLOGFILE") != NULL)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen i_set_info_file(getenv("INFOLOGFILE"));
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
67b785ce2485243c490f0a8b0753ac4a5d347265Timo Sirainen i_set_failure_timestamp_format(getenv("LOGSTAMP"));
67b785ce2485243c490f0a8b0753ac4a5d347265Timo Sirainen}
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainenstatic void drop_privileges(void)
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen{
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen const char *version;
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen version = getenv("DOVECOT_VERSION");
548f87789cf9865572b7b86f7be5a9bbfa132f3fTimo Sirainen if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) {
i_fatal("Dovecot version mismatch: "
"Master is v%s, pop3 is v"PACKAGE_VERSION" "
"(if you don't care, set version_ignore=yes)", version);
}
/* Log file or syslog opening probably requires roots */
open_logfile();
/* Most likely needed. Have to open /dev/urandom before possible
chrooting. */
random_init();
/* 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());
}
static int main_init(void)
{
enum mail_storage_flags flags;
enum file_lock_method lock_method;
struct mail_storage *storage;
const char *mail;
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);
if (getenv("USER") == NULL)
i_fatal("USER environment missing");
if (getenv("DEBUG") != NULL) {
i_info("Effective uid=%s, gid=%s",
dec2str(geteuid()), dec2str(getegid()));
}
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);
}
dict_driver_register(&dict_driver_client);
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
clients_init();
module_dir_init(modules);
mail = getenv("MAIL");
if (mail == NULL) {
/* support also maildir-specific environment */
mail = getenv("MAILDIR");
if (mail != NULL)
mail = t_strconcat("maildir:", mail, NULL);
}
parse_workarounds();
enable_last_command = getenv("POP3_ENABLE_LAST") != NULL;
no_flag_updates = getenv("POP3_NO_FLAG_UPDATES") != NULL;
reuse_xuidl = getenv("POP3_REUSE_XUIDL") != NULL;
lock_session = getenv("POP3_LOCK_SESSION") != NULL;
uidl_format = getenv("POP3_UIDL_FORMAT");
if (uidl_format == NULL || *uidl_format == '\0')
i_fatal("Set pop3_uidl_format in config file");
logout_format = getenv("POP3_LOGOUT_FORMAT");
if (logout_format == NULL)
logout_format = "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s";
uidl_keymask = parse_uidl_keymask(uidl_format);
if (uidl_keymask == 0)
i_fatal("pop3_uidl_format setting doesn't contain any "
"%% variables.");
mail_storage_parse_env(&flags, &lock_method);
storage = mail_storage_create_with_data(mail, getenv("USER"),
flags, lock_method);
if (storage == NULL) {
/* failed */
if (mail != NULL && *mail != '\0')
i_fatal("Failed to create storage with data: %s", mail);
else {
const char *home;
home = getenv("HOME");
if (home == NULL) home = "not set";
i_fatal("MAIL environment missing and "
"autodetection failed (home %s)", home);
}
}
return client_create(0, 1, storage) != NULL;
}
static void main_deinit(void)
{
if (log_io != NULL)
io_remove(&log_io);
clients_deinit();
module_dir_unload(&modules);
mail_storage_deinit();
dict_driver_unregister(&dict_driver_client);
random_deinit();
lib_signals_deinit();
closelog();
}
int main(int argc __attr_unused__, char *argv[], char *envp[])
{
#ifdef DEBUG
if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL)
fd_debug_verify_leaks(3, 1024);
#endif
if (IS_STANDALONE() && getuid() == 0 &&
net_getpeername(1, NULL, NULL) == 0) {
printf("-ERR pop3 binary must not be started from "
"inetd, use pop3-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();
if (main_init())
io_loop_run(ioloop);
main_deinit();
io_loop_destroy(&ioloop);
lib_deinit();
return 0;
}