1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
9
#include "lib-signals.h"
10
#include "restrict-access.h"
11
#include "fd-close-on-exec.h"
12
#include "process-title.h"
14
#include "module-dir.h"
15
#include "dict-client.h"
17
#include "sieve-storage.h"
27
#define IS_STANDALONE() \
28
(getenv("LOGGED_IN") == NULL)
30
#define CRITICAL_MSG \
31
"Internal error occured. Refer to server log for more information."
32
#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
34
struct client_workaround_list {
36
enum client_workarounds num;
39
struct client_workaround_list client_workaround_list[] = {
43
struct ioloop *ioloop;
44
unsigned int managesieve_max_line_length;
45
const char *managesieve_implementation_string;
46
enum client_workarounds client_workarounds = 0;
47
const char *logout_format;
49
static struct io *log_io = NULL;
50
static struct module *modules = NULL;
51
static char log_prefix[128]; /* syslog() needs this to be permanent */
53
void (*hook_client_created)(struct client **client) = NULL;
55
static void sig_die(int signo, void *context ATTR_UNUSED)
57
/* warn about being killed because of some signal, except SIGINT (^C)
58
which is too common at least while testing :) */
60
i_warning("Killed with signal %d", signo);
64
static void log_error_callback(void *context ATTR_UNUSED)
69
static void parse_workarounds(void)
71
struct client_workaround_list *list;
72
const char *env, *const *str;
74
env = getenv("MANAGESIEVE_CLIENT_WORKAROUNDS");
78
for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) {
79
list = client_workaround_list;
80
for (; list->name != NULL; list++) {
81
if (strcasecmp(*str, list->name) == 0) {
82
client_workarounds |= list->num;
86
if (list->name == NULL)
87
i_fatal("Unknown client workaround: %s", *str);
91
static void open_logfile(void)
95
if (getenv("LOG_TO_MASTER") != NULL) {
96
i_set_failure_internal();
100
if (getenv("LOG_PREFIX") != NULL)
101
strncpy(log_prefix, getenv("LOG_PREFIX"), sizeof(log_prefix));
103
user = getenv("USER");
110
if (strlen(user) >= sizeof(log_prefix)-6) {
111
/* quite a long user name, cut it */
112
user = t_strndup(user, sizeof(log_prefix)-6-2);
113
user = t_strconcat(user, "..", NULL);
115
i_snprintf(log_prefix, sizeof(log_prefix), "imap(%s): ", user);
118
if (getenv("USE_SYSLOG") != NULL) {
119
const char *env = getenv("SYSLOG_FACILITY");
120
i_set_failure_syslog(log_prefix, LOG_NDELAY,
121
env == NULL ? LOG_MAIL : atoi(env));
123
/* log to file or stderr */
124
i_set_failure_file(getenv("LOGFILE"), log_prefix);
127
if (getenv("INFOLOGFILE") != NULL)
128
i_set_info_file(getenv("INFOLOGFILE"));
130
i_set_failure_timestamp_format(getenv("LOGSTAMP"));
133
static void drop_privileges(void)
137
version = getenv("DOVECOT_VERSION");
138
if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) {
139
i_fatal("Dovecot version mismatch: "
140
"Master is v%s, managesieve is v"PACKAGE_VERSION" "
141
"(if you don't care, set version_ignore=yes)", version);
144
/* Log file or syslog opening probably requires roots */
147
/* Most likely needed. Have to open /dev/urandom before possible
151
/* Load the plugins before chrooting. Their init() is called later. */
152
/* FIXME: MAIL_PLUGINS is a rather odd config value for a MANAGESIEVE
155
if (getenv("MAIL_PLUGINS") != NULL) {
156
const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
158
if (plugin_dir == NULL)
159
plugin_dir = MODULEDIR"/managesieve";
160
modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
164
restrict_access_by_env(!IS_STANDALONE());
167
static void internal_error()
172
tm = localtime(&ioloop_time);
174
printf("BYE \"%s\"\n",
175
strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
176
i_strdup(str) : i_strdup(CRITICAL_MSG));
179
static void main_init(void)
181
struct sieve_storage *storage;
182
struct client *client;
183
const char *user, *str, *sieve_storage, *mail;
186
lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
187
lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
188
lib_signals_ignore(SIGPIPE, TRUE);
189
lib_signals_ignore(SIGALRM, FALSE);
191
user = getenv("USER");
197
i_fatal("USER environment missing");
201
if (getenv("DEBUG") != NULL) {
204
home = getenv("HOME");
205
i_info("Effective uid=%s, gid=%s, home=%s",
206
dec2str(geteuid()), dec2str(getegid()),
207
home != NULL ? home : "(none)");
210
if (getenv("STDERR_CLOSE_SHUTDOWN") != NULL) {
211
/* If master dies, the log fd gets closed and we'll quit */
212
log_io = io_add(STDERR_FILENO, IO_ERROR,
213
log_error_callback, NULL);
217
dict_driver_register(&dict_driver_client);
221
module_dir_init(modules);
224
str = getenv("MANAGESIEVE_MAX_LINE_LENGTH");
225
managesieve_max_line_length = str != NULL ?
226
(unsigned int)strtoul(str, NULL, 10) :
227
DEFAULT_MANAGESIEVE_MAX_LINE_LENGTH;
229
logout_format = getenv("MANAGESIEVE_LOGOUT_FORMAT");
230
if (logout_format == NULL)
231
logout_format = "bytes=%i/%o";
233
str = getenv("MANAGESIEVE_IMPLEMENTATION_STRING");
234
managesieve_implementation_string = str != NULL ?
235
str : DEFAULT_MANAGESIEVE_IMPLEMENTATION_STRING;
239
mail = getenv("MAIL");
240
sieve_storage = getenv("SIEVE_STORAGE");
241
if ( (sieve_storage == NULL || *sieve_storage == '\0') &&
242
!(mail == NULL || *mail == '\0') ) {
243
storage = sieve_storage_create_from_mail(mail, user);
245
storage = sieve_storage_create(sieve_storage, user);
247
if (storage == NULL) {
251
if (sieve_storage != NULL && *sieve_storage != '\0')
252
i_fatal("Failed to create sieve storage with data: %s", sieve_storage);
253
else if (mail != NULL && *mail != '\0')
254
i_fatal("Failed to create sieve storage with mail-data: %s", mail);
258
home = getenv("HOME");
259
if (home == NULL) home = "not set";
261
i_fatal("SIEVE_STORAGE and MAIL environment missing and "
262
"autodetection failed (home %s)", home);
266
client = client_create(0, 1, storage);
268
client_send_ok(client, "Logged in.");
271
static void main_deinit(void)
277
module_dir_unload(&modules);
279
dict_driver_unregister(&dict_driver_client);
283
lib_signals_deinit();
287
int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
290
if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL)
291
fd_debug_verify_leaks(3, 1024);
293
if (IS_STANDALONE() && getuid() == 0 &&
294
net_getpeername(1, NULL, NULL) == 0) {
295
printf("NO \"managesieve binary must not be started from "
296
"inetd, use managesieve-login instead.\"\n");
300
/* NOTE: we start rooted, so keep the code minimal until
301
restrict_access_by_env() is called */
305
process_title_init(argv, envp);
306
ioloop = io_loop_create();
312
io_loop_destroy(&ioloop);