1
/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
3
/* This is getting pretty horrible. Especially the config file parsing.
4
Dovecot v2.0 should have a config file handling process which should help
8
#include "lib-signals.h"
13
#include "home-expand.h"
15
#include "fd-set-nonblock.h"
17
#include "istream-seekable.h"
18
#include "module-dir.h"
20
#include "str-sanitize.h"
21
#include "strescape.h"
22
#include "safe-mkstemp.h"
23
#include "mkdir-parents.h"
24
#include "eacces-error.h"
25
#include "close-keep-errno.h"
26
#include "var-expand.h"
27
#include "rfc822-parser.h"
28
#include "message-address.h"
29
#include "mail-namespace.h"
30
#include "raw-storage.h"
31
#include "imap-utf7.h"
33
#include "auth-client.h"
34
#include "mail-send.h"
35
#include "duplicate.h"
36
#include "mbox-from.h"
37
#include "../master/syslog-util.h"
38
#include "../master/syslog-util.c" /* ugly, ugly.. */
48
#define DEFAULT_CONFIG_FILE SYSCONFDIR"/dovecot.conf"
49
#define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail"
50
#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"
52
/* After buffer grows larger than this, create a temporary file to /tmp
53
where to read the mail. */
54
#define MAIL_MAX_MEMORY_BUFFER (1024*128)
56
static const char *wanted_headers[] = {
57
"From", "Message-ID", "Subject", "Return-Path",
61
struct deliver_settings *deliver_set;
62
deliver_mail_func_t *deliver_mail = NULL;
63
bool tried_default_save = FALSE;
65
/* FIXME: these two should be in some context struct instead of as globals.. */
66
static const char *default_mailbox_name = NULL;
67
static bool saved_mail = FALSE;
68
static char *explicit_envelope_sender = NULL;
70
static struct module *modules;
71
static struct ioloop *ioloop;
73
static pool_t plugin_pool;
74
static ARRAY_DEFINE(lda_envs, const char *);
75
static ARRAY_DEFINE(plugin_envs, const char *);
77
static void sig_die(const siginfo_t *si, void *context ATTR_UNUSED)
79
/* warn about being killed because of some signal, except SIGINT (^C)
80
which is too common at least while testing :) */
81
if (si->si_signo != SIGINT) {
82
i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
83
si->si_signo, dec2str(si->si_pid),
85
lib_signal_code_to_str(si->si_signo, si->si_code));
87
io_loop_stop(current_ioloop);
90
static const char *deliver_get_address(struct mail *mail, const char *header)
92
struct message_address *addr;
95
if (mail_get_first_header(mail, header, &str) <= 0)
97
addr = message_address_parse(pool_datastack_create(),
98
(const unsigned char *)str,
99
strlen(str), 1, FALSE);
100
return addr == NULL || addr->mailbox == NULL || addr->domain == NULL ||
101
*addr->mailbox == '\0' || *addr->domain == '\0' ?
102
NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL);
105
static const struct var_expand_table *
106
get_log_var_expand_table(struct mail *mail, const char *message)
108
static struct var_expand_table static_tab[] = {
110
{ 'm', NULL, "msgid" },
111
{ 's', NULL, "subject" },
112
{ 'f', NULL, "from" },
115
struct var_expand_table *tab;
118
tab = t_malloc(sizeof(static_tab));
119
memcpy(tab, static_tab, sizeof(static_tab));
121
tab[0].value = message;
122
(void)mail_get_first_header(mail, "Message-ID", &tab[1].value);
123
(void)mail_get_first_header_utf8(mail, "Subject", &tab[2].value);
124
tab[3].value = deliver_get_address(mail, "From");
125
for (i = 1; tab[i].key != '\0'; i++)
126
tab[i].value = str_sanitize(tab[i].value, 80);
131
deliver_log(struct mail *mail, const char *fmt, ...) ATTR_FORMAT(2, 3);
133
static void deliver_log(struct mail *mail, const char *fmt, ...)
140
msg = t_strdup_vprintf(fmt, args);
142
str = t_str_new(256);
143
var_expand(str, deliver_set->log_format,
144
get_log_var_expand_table(mail, msg));
145
i_info("%s", str_c(str));
149
static struct mailbox *
150
mailbox_open_or_create_synced(struct mail_namespace *namespaces,
151
struct mail_storage **storage_r,
154
struct mail_namespace *ns;
156
enum mail_error error;
157
enum mailbox_open_flags open_flags = MAILBOX_OPEN_FAST |
158
MAILBOX_OPEN_KEEP_RECENT | MAILBOX_OPEN_SAVEONLY |
159
MAILBOX_OPEN_POST_SESSION;
161
if (strcasecmp(name, "INBOX") == 0) {
162
/* deliveries to INBOX must always succeed,
163
regardless of ACLs */
164
open_flags |= MAILBOX_OPEN_IGNORE_ACLS;
167
ns = mail_namespace_find(namespaces, &name);
172
*storage_r = ns->storage;
175
/* delivering to a namespace prefix means we actually want to
176
deliver to the INBOX instead */
180
box = mailbox_open(storage_r, name, NULL, open_flags);
181
if (box != NULL || !deliver_set->mailbox_autocreate)
184
(void)mail_storage_get_last_error(*storage_r, &error);
185
if (error != MAIL_ERROR_NOTFOUND)
188
/* try creating it. */
189
if (mail_storage_mailbox_create(*storage_r, name, FALSE) < 0)
191
if (deliver_set->mailbox_autosubscribe) {
192
/* (try to) subscribe to it */
193
(void)mailbox_list_set_subscribed(ns->list, name, TRUE);
196
/* and try opening again */
197
box = mailbox_open(storage_r, name, NULL, open_flags);
201
if (mailbox_sync(box, 0, 0, NULL) < 0) {
208
static const char *mailbox_name_get_printable(const char *mailbox_mutf7)
210
string_t *str = t_str_new(128);
212
if (imap_utf7_to_utf8(mailbox_mutf7, str) < 0) {
213
str_truncate(str, 0);
214
str_append(str, mailbox_mutf7);
216
return str_sanitize(str_c(str), 80);
219
int deliver_save(struct mail_namespace *namespaces,
220
struct mail_storage **storage_r, const char *mailbox,
221
struct mail *mail, enum mail_flags flags,
222
const char *const *keywords)
225
struct mailbox_transaction_context *t;
226
struct mail_save_context *save_ctx;
227
struct mail_keywords *kw;
228
enum mail_error error;
229
const char *mailbox_name;
233
default_save = strcmp(mailbox, default_mailbox_name) == 0;
235
tried_default_save = TRUE;
237
mailbox_name = mailbox_name_get_printable(mailbox);
238
box = mailbox_open_or_create_synced(namespaces, storage_r, mailbox);
240
if (*storage_r == NULL) {
242
"save failed to %s: Unknown namespace",
247
strcmp((*storage_r)->ns->prefix, mailbox) == 0) {
248
/* silently store to the INBOX instead */
251
deliver_log(mail, "save failed to %s: %s", mailbox_name,
252
mail_storage_get_last_error(*storage_r, &error));
256
t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL);
258
kw = str_array_length(keywords) == 0 ? NULL :
259
mailbox_keywords_create_valid(box, keywords);
260
save_ctx = mailbox_save_alloc(t);
261
mailbox_save_set_flags(save_ctx, flags, kw);
262
if (mailbox_copy(&save_ctx, mail) < 0)
264
mailbox_keywords_free(box, &kw);
267
mailbox_transaction_rollback(&t);
269
ret = mailbox_transaction_commit(&t);
273
deliver_log(mail, "saved mail to %s", mailbox_name);
275
deliver_log(mail, "save failed to %s: %s", mailbox_name,
276
mail_storage_get_last_error(*storage_r, &error));
283
const char *deliver_get_return_address(struct mail *mail)
285
if (explicit_envelope_sender != NULL)
286
return explicit_envelope_sender;
288
return deliver_get_address(mail, "Return-Path");
291
const char *deliver_get_new_message_id(void)
293
static int count = 0;
295
return t_strdup_printf("<dovecot-%s-%s-%d@%s>",
296
dec2str(ioloop_timeval.tv_sec),
297
dec2str(ioloop_timeval.tv_usec),
298
count++, deliver_set->hostname);
301
#include "settings.h"
302
#include "../master/master-settings.h"
303
#include "../master/master-settings-defs.c"
305
#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
307
static bool setting_is_bool(const char *name)
309
const struct setting_def *def;
311
for (def = setting_defs; def->name != NULL; def++) {
312
if (strcmp(def->name, name) == 0)
313
return def->type == SET_BOOL;
315
if (strncmp(name, "NAMESPACE_", 10) == 0) {
316
return strstr(name, "_list") != NULL ||
317
strstr(name, "_inbox") != NULL ||
318
strstr(name, "_hidden") != NULL ||
319
strstr(name, "_subscriptions") != NULL;
321
if (strcmp(name, "quota_full_tempfail") == 0)
326
/* more ugly kludging because we have our own config parsing code.
327
hopefully this goes away in v1.2. */
331
} default_yes_settings[] = {
332
{ "dotlock_use_excl", TRUE },
333
{ "maildir_copy_with_hardlinks", TRUE },
334
{ "mbox_dirty_syncs", TRUE },
335
{ "mbox_lazy_writes", TRUE }
338
static void config_file_init(const char *path)
340
struct istream *input;
341
const char *key, *value, *str, *ukey;
342
char *line, *p, quote;
343
int fd, sections = 0;
344
bool lda_section = FALSE, pop3_section = FALSE, plugin_section = FALSE;
345
bool ns_section = FALSE, ns_location = FALSE, ns_list = FALSE;
346
bool ns_subscriptions = FALSE;
347
unsigned int i, ns_idx = 0;
350
plugin_pool = pool_alloconly_create("Plugin strings", 512);
351
i_array_init(&lda_envs, 16);
352
i_array_init(&plugin_envs, 16);
354
fd = open(path, O_RDONLY);
356
i_fatal_status(EX_TEMPFAIL, "open(%s) failed: %m", path);
358
input = i_stream_create_fd(fd, (size_t)-1, TRUE);
359
i_stream_set_return_partial_line(input, TRUE);
360
while ((line = i_stream_read_next_line(input)) != NULL) {
361
/* @UNSAFE: line is modified */
363
/* skip whitespace */
364
while (IS_WHITE(*line))
367
/* ignore comments or empty lines */
368
if (*line == '#' || *line == '\0')
371
/* strip away comments. pretty kludgy way really.. */
372
for (p = line; *p != '\0'; p++) {
373
if (*p == '\'' || *p == '"') {
375
for (p++; *p != quote && *p != '\0'; p++) {
376
if (*p == '\\' && p[1] != '\0')
381
} else if (*p == '#') {
387
/* remove whitespace from end of line */
389
while (IS_WHITE(line[len-1]))
393
if (strncmp(line, "!include_try ", 13) == 0)
395
if (strncmp(line, "!include ", 9) == 0) {
396
i_fatal_status(EX_TEMPFAIL, "Error in config file %s: "
397
"deliver doesn't support !include directive", path);
400
value = p = strchr(line, '=');
402
if (strchr(line, '{') != NULL) {
403
if (strcmp(line, "protocol lda {") == 0)
405
else if (strcmp(line, "plugin {") == 0)
406
plugin_section = TRUE;
407
else if (strcmp(line, "protocol pop3 {") == 0)
409
else if (strncmp(line, "namespace ", 10) == 0) {
413
env_put(t_strdup_printf(
414
"NAMESPACE_%u_TYPE=%s", ns_idx,
415
t_strcut(line, ' ')));
422
plugin_section = FALSE;
423
pop3_section = FALSE;
429
env_put(t_strdup_printf(
430
"NAMESPACE_%u=", ns_idx));
435
env_put(t_strdup_printf(
436
"NAMESPACE_%u_LIST=1", ns_idx));
438
if (ns_subscriptions)
439
ns_subscriptions = FALSE;
441
env_put(t_strdup_printf(
442
"NAMESPACE_%u_SUBSCRIPTIONS=1",
450
while (p > line && IS_WHITE(p[-1])) p--;
451
key = t_strdup_until(line, p);
453
if (sections > 0 && !lda_section && !plugin_section) {
455
if (strcmp(key, "pop3_uidl_format") != 0)
457
} else if (ns_section) {
458
if (strcmp(key, "separator") == 0) {
459
key = t_strdup_printf(
460
"NAMESPACE_%u_SEP", ns_idx);
461
} else if (strcmp(key, "location") == 0) {
463
key = t_strdup_printf("NAMESPACE_%u",
466
if (strcmp(key, "list") == 0)
468
if (strcmp(key, "subscriptions") == 0)
469
ns_subscriptions = TRUE;
470
key = t_strdup_printf("NAMESPACE_%u_%s",
474
/* unwanted section */
481
} while (IS_WHITE(*value));
485
((*value == '"' && value[len-1] == '"') ||
486
(*value == '\'' && value[len-1] == '\''))) {
487
value = str_unescape(p_strndup(unsafe_data_stack_pool,
490
ukey = t_str_ucase(key);
491
if (setting_is_bool(key) && strcasecmp(value, "yes") != 0) {
492
for (i = 0; i < N_ELEMENTS(default_yes_settings); i++) {
493
if (strcmp(default_yes_settings[i].name,
495
default_yes_settings[i].set = FALSE;
502
str = p_strconcat(plugin_pool, ukey, "=", value, NULL);
503
array_append(&lda_envs, &str, 1);
505
if (!plugin_section) {
506
env_put(t_strconcat(ukey, "=", value, NULL));
508
/* %variables need to be expanded.
509
store these for later. */
510
value = p_strconcat(plugin_pool,
511
ukey, "=", value, NULL);
512
array_append(&plugin_envs, &value, 1);
515
i_stream_unref(&input);
517
for (i = 0; i < N_ELEMENTS(default_yes_settings); i++) {
518
if (default_yes_settings[i].set) {
519
key = default_yes_settings[i].name;
520
env_put(t_strconcat(t_str_ucase(key), "=1", NULL));
525
static const struct var_expand_table *
526
get_var_expand_table(const char *user, const char *home)
528
static struct var_expand_table static_tab[] = {
529
{ 'u', NULL, "user" },
530
{ 'n', NULL, "username" },
531
{ 'd', NULL, "domain" },
532
{ 's', NULL, "service" },
533
{ 'h', NULL, "home" },
534
{ 'l', NULL, "lip" },
535
{ 'r', NULL, "rip" },
536
{ 'p', NULL, "pid" },
537
{ 'i', NULL, "uid" },
540
struct var_expand_table *tab;
542
tab = t_malloc(sizeof(static_tab));
543
memcpy(tab, static_tab, sizeof(static_tab));
546
tab[1].value = t_strcut(user, '@');
547
tab[2].value = strchr(user, '@');
548
if (tab[2].value != NULL) tab[2].value++;
549
tab[3].value = "DELIVER";
550
tab[4].value = home != NULL ? home :
551
"/HOME_DIRECTORY_USED_BUT_NOT_GIVEN_BY_USERDB";
554
tab[7].value = my_pid;
555
tab[8].value = dec2str(geteuid());
561
expand_mail_env(const char *env, const struct var_expand_table *table)
566
str = t_str_new(256);
568
/* it's either type:data or just data */
569
p = strchr(env, ':');
572
str_append_c(str, *env);
576
str_append_c(str, *env++);
579
if (env[0] == '~' && env[1] == '/') {
581
env = t_strconcat("%h", env+1, NULL);
585
var_expand(str, env, table);
589
static const char *escape_local_part(const char *local_part)
593
/* if local_part isn't dot-atom-text, we need to return quoted-string
594
dot-atom-text = 1*atext *("." 1*atext) */
595
for (p = local_part; *p != '\0'; p++) {
596
if (!IS_ATEXT(*p) && *p != '.')
599
if (*p != '\0' || *local_part == '.' ||
600
(p != local_part && p[-1] == '.'))
601
local_part = t_strdup_printf("\"%s\"", str_escape(local_part));
605
static const char *address_sanitize(const char *address)
607
struct message_address *addr;
608
const char *ret, *mailbox;
611
pool = pool_alloconly_create("address sanitizer", 256);
612
addr = message_address_parse(pool, (const unsigned char *)address,
613
strlen(address), 1, FALSE);
615
if (addr == NULL || addr->mailbox == NULL || addr->domain == NULL ||
616
*addr->mailbox == '\0')
617
ret = DEFAULT_ENVELOPE_SENDER;
619
mailbox = escape_local_part(addr->mailbox);
620
if (*addr->domain == '\0')
621
ret = t_strdup(mailbox);
623
ret = t_strdup_printf("%s@%s", mailbox, addr->domain);
629
static int deliver_create_dir(struct mail_user *user, const char *dir)
631
struct mail_namespace *ns;
636
ns = mail_namespace_find_inbox(user->namespaces);
638
ns = user->namespaces;
640
mailbox_list_get_dir_permissions(ns->list, NULL, &mode, &gid, &origin);
641
if (mkdir_parents_chgrp(dir, mode, gid, origin) == 0) {
643
} else if (errno == EACCES) {
644
i_error("%s", eacces_error_get_creating("mkdir_parents_chown",
648
i_error("mkdir_parents_chown(%s, gid=%s) failed: %m",
654
static int seekable_fd_callback(const char **path_r, void *context)
656
struct mail_user *user = context;
661
path = t_str_new(128);
662
str_append(path, mail_user_get_temp_prefix(user));
663
fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
664
if (fd == -1 && errno == ENOENT) {
666
p = strrchr(dir, '/');
668
dir = t_strdup_until(dir, p);
669
if (deliver_create_dir(user, dir) < 0)
671
fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
675
i_error("safe_mkstemp(%s) failed: %m", str_c(path));
679
/* we just want the fd, unlink it */
680
if (unlink(str_c(path)) < 0) {
681
/* shouldn't happen.. */
682
i_error("unlink(%s) failed: %m", str_c(path));
683
close_keep_errno(fd);
687
*path_r = str_c(path);
691
static struct istream *
692
create_raw_stream(struct mail_user *user, int fd, time_t *mtime_r)
694
struct istream *input, *input2, *input_list[2];
695
const unsigned char *data;
700
*mtime_r = (time_t)-1;
701
fd_set_nonblock(fd, FALSE);
703
input = i_stream_create_fd(fd, 4096, FALSE);
704
input->blocking = TRUE;
705
/* If input begins with a From-line, drop it */
706
ret = i_stream_read_data(input, &data, &size, 5);
707
if (ret > 0 && size >= 5 && memcmp(data, "From ", 5) == 0) {
708
/* skip until the first LF */
709
i_stream_skip(input, 5);
710
while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
711
for (i = 0; i < size; i++) {
716
(void)mbox_from_parse(data, i, mtime_r, &tz,
718
i_stream_skip(input, i + 1);
721
i_stream_skip(input, size);
725
if (sender != NULL && explicit_envelope_sender == NULL) {
726
/* use the envelope sender from From_-line, but only if it
727
hasn't been specified with -f already. */
728
explicit_envelope_sender = i_strdup(sender);
732
if (input->v_offset == 0) {
734
i_stream_ref(input2);
736
input2 = i_stream_create_limit(input, (uoff_t)-1);
738
i_stream_unref(&input);
740
input_list[0] = input2; input_list[1] = NULL;
741
input = i_stream_create_seekable(input_list, MAIL_MAX_MEMORY_BUFFER,
742
seekable_fd_callback, user);
743
i_stream_unref(&input2);
747
static void failure_exit_callback(int *status)
749
/* we want all our exit codes to be sysexits.h compatible.
750
if we failed because of a logging related error, we most likely
751
aren't writing to stderr, so try writing there to give some kind of
752
a clue what's wrong. FATAL_LOGOPEN failure already wrote to
753
stderr, so don't duplicate it. */
756
fputs("Failed to write to log file", stderr);
759
fputs("Internal logging error", stderr);
769
*status = EX_TEMPFAIL;
772
static void open_logfile(const char *username)
774
const char *prefix, *log_path, *stamp;
776
prefix = t_strdup_printf("deliver(%s): ", username);
777
log_path = home_expand(getenv("LOG_PATH"));
778
if (log_path == NULL || *log_path == '\0') {
779
const char *env = getenv("SYSLOG_FACILITY");
782
if (env == NULL || !syslog_facility_find(env, &facility))
784
i_set_failure_prefix(prefix);
785
i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
787
/* log to file or stderr */
788
i_set_failure_file(log_path, prefix);
791
log_path = home_expand(getenv("INFO_LOG_PATH"));
792
if (log_path != NULL && *log_path != '\0')
793
i_set_info_file(log_path);
795
stamp = getenv("LOG_TIMESTAMP");
797
stamp = DEFAULT_FAILURE_STAMP_FORMAT;
798
i_set_failure_timestamp_format(stamp);
801
static void print_help(void)
804
"Usage: deliver [-c <config file>] [-a <address>] [-d <username>] [-p <path>]\n"
805
" [-f <envelope sender>] [-m <mailbox>] [-n] [-s] [-e] [-k]\n");
808
void deliver_env_clean(bool preserve_home)
810
const char *tz, *home;
814
tz = t_strconcat("TZ=", tz, NULL);
815
home = preserve_home ? getenv("HOME") : NULL;
817
home = t_strconcat("HOME=", home, NULL);
819
/* Note that if the original environment was set with env_put(), the
820
environment strings will be invalid after env_clean(). That's why
821
we t_strconcat() them above. */
824
if (tz != NULL) env_put(tz);
825
if (home != NULL) env_put(home);
828
static void expand_envs(const char *user)
830
const struct var_expand_table *table;
831
const char *value, *const *envs, *home, *env_name;
832
unsigned int i, count;
835
home = getenv("HOME");
837
str = t_str_new(256);
838
table = get_var_expand_table(user, home);
839
envs = array_get(&plugin_envs, &count);
840
for (i = 0; i < count; i++) {
841
str_truncate(str, 0);
842
var_expand(str, envs[i], table);
845
/* add LDA envs again to make sure they override plugin settings */
846
envs = array_get(&lda_envs, &count);
847
for (i = 0; i < count; i++)
850
/* get the table again in case plugin envs provided the home
851
directory (yea, kludgy) */
853
home = getenv("HOME");
854
table = get_var_expand_table(user, home);
856
value = getenv("MAIL_LOCATION");
858
value = expand_mail_env(value, table);
859
env_put(t_strconcat("MAIL=", value, NULL));
862
env_name = t_strdup_printf("NAMESPACE_%u", i);
863
value = getenv(env_name);
867
value = expand_mail_env(value, table);
868
env_put(t_strconcat(env_name, "=", value, NULL));
870
env_name = t_strdup_printf("NAMESPACE_%u_PREFIX", i);
871
value = getenv(env_name);
873
str_truncate(str, 0);
874
var_expand(str, value, table);
875
env_put(t_strconcat(env_name, "=", str_c(str), NULL));
880
static void putenv_extra_fields(const ARRAY_TYPE(const_string) *extra_fields)
882
const char *const *fields;
884
unsigned int i, count;
886
fields = array_get(extra_fields, &count);
887
for (i = 0; i < count; i++) {
888
p = strchr(fields[i], '=');
890
env_put(t_strconcat(fields[i], "=1", NULL));
892
key = t_str_ucase(t_strdup_until(fields[i], p));
893
env_put(t_strconcat(key, p, NULL));
898
int main(int argc, char *argv[])
900
const char *config_path = DEFAULT_CONFIG_FILE;
901
const char *mailbox = "INBOX";
902
const char *auth_socket;
903
const char *home, *destaddr, *user, *value, *errstr, *path, *orig_user;
904
ARRAY_TYPE(const_string) extra_fields = ARRAY_INIT;
905
struct mail_user *mail_user, *raw_mail_user;
906
struct mail_namespace *raw_ns;
907
struct mail_storage *storage;
909
struct raw_mailbox *raw_box;
910
struct istream *input;
911
struct mailbox_transaction_context *t;
912
struct mailbox_header_lookup_ctx *headers_ctx;
916
bool stderr_rejection = FALSE;
917
bool keep_environment = FALSE;
918
bool user_auth = FALSE;
921
pool_t userdb_pool = NULL;
923
enum mail_error error;
925
if (getuid() != geteuid() && geteuid() == 0) {
926
/* running setuid - don't allow this if deliver is
927
executable by anyone */
930
if (stat(argv[0], &st) < 0) {
931
fprintf(stderr, "stat(%s) failed: %s\n",
932
argv[0], strerror(errno));
934
} else if ((st.st_mode & 1) != 0 && (st.st_mode & 04000) != 0) {
935
fprintf(stderr, "%s must not be both world-executable "
936
"and setuid-root. This allows root exploits. "
937
"See http://wiki.dovecot.org/LDA#multipleuids\n",
943
i_set_failure_exit_callback(failure_exit_callback);
946
ioloop = io_loop_create();
949
lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
950
lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
951
lib_signals_ignore(SIGPIPE, TRUE);
952
lib_signals_ignore(SIGALRM, FALSE);
954
lib_signals_ignore(SIGXFSZ, TRUE);
957
deliver_set = i_new(struct deliver_settings, 1);
958
deliver_set->mailbox_autocreate = TRUE;
960
destaddr = user = path = NULL;
961
for (i = 1; i < argc; i++) {
962
if (strcmp(argv[i], "-a") == 0) {
963
/* destination address */
966
i_fatal_status(EX_USAGE, "Missing -a argument");
968
} else if (strcmp(argv[i], "-d") == 0) {
969
/* destination user */
972
i_fatal_status(EX_USAGE, "Missing -d argument");
975
} else if (strcmp(argv[i], "-p") == 0) {
979
i_fatal_status(EX_USAGE, "Missing -p argument");
982
/* expand relative paths before we chdir */
983
if (getcwd(cwd, sizeof(cwd)) == NULL)
984
i_fatal("getcwd() failed: %m");
985
path = t_strconcat(cwd, "/", path, NULL);
987
} else if (strcmp(argv[i], "-e") == 0) {
988
stderr_rejection = TRUE;
989
} else if (strcmp(argv[i], "-c") == 0) {
990
/* config file path */
993
i_fatal_status(EX_USAGE,
994
"Missing config file path argument");
996
config_path = argv[i];
997
} else if (strcmp(argv[i], "-k") == 0) {
998
keep_environment = TRUE;
999
} else if (strcmp(argv[i], "-m") == 0) {
1000
/* destination mailbox */
1003
i_fatal_status(EX_USAGE, "Missing -m argument");
1004
/* Ignore -m "". This allows doing -m ${extension}
1005
in Postfix to handle user+mailbox */
1006
if (*argv[i] != '\0') {
1007
str = t_str_new(256);
1008
if (imap_utf8_to_utf7(argv[i], str) < 0) {
1009
i_fatal("Mailbox name not UTF-8: %s",
1012
mailbox = str_c(str);
1014
} else if (strcmp(argv[i], "-n") == 0) {
1015
deliver_set->mailbox_autocreate = FALSE;
1016
} else if (strcmp(argv[i], "-s") == 0) {
1017
deliver_set->mailbox_autosubscribe = TRUE;
1018
} else if (strcmp(argv[i], "-f") == 0) {
1019
/* envelope sender address */
1022
i_fatal_status(EX_USAGE, "Missing -f argument");
1023
explicit_envelope_sender =
1024
i_strdup(address_sanitize(argv[i]));
1025
} else if (argv[i][0] != '\0') {
1027
i_fatal_status(EX_USAGE,
1028
"Unknown argument: %s", argv[i]);
1033
user = getenv("USER");
1034
if (!keep_environment)
1035
deliver_env_clean(!user_auth);
1037
process_euid = geteuid();
1040
else if (process_euid != 0) {
1041
/* we're non-root. get our username and possibly our home. */
1044
home = getenv("HOME");
1045
if (user != NULL && home != NULL) {
1046
/* no need for a pw lookup */
1047
} else if ((pw = getpwuid(process_euid)) != NULL) {
1048
user = t_strdup(pw->pw_name);
1050
env_put(t_strconcat("HOME=", pw->pw_dir, NULL));
1051
} else if (user == NULL) {
1052
i_fatal_status(EX_USAGE,
1053
"Couldn't lookup our username (uid=%s)",
1054
dec2str(process_euid));
1057
i_fatal_status(EX_USAGE,
1058
"destination user parameter (-d user) not given");
1062
config_file_init(config_path);
1066
if (getenv("MAIL_DEBUG") != NULL)
1069
if (getenv("MAIL_PLUGINS") == NULL)
1072
const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
1073
const char *version;
1075
if (plugin_dir == NULL)
1076
plugin_dir = MODULEDIR"/lda";
1078
version = getenv("VERSION_IGNORE") != NULL ?
1079
NULL : PACKAGE_VERSION;
1080
modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
1085
auth_socket = getenv("AUTH_SOCKET_PATH");
1086
if (auth_socket == NULL) {
1087
const char *base_dir = getenv("BASE_DIR");
1088
if (base_dir == NULL)
1089
base_dir = PKG_RUNDIR;
1090
auth_socket = t_strconcat(base_dir, "/auth-master",
1094
userdb_pool = pool_alloconly_create("userdb lookup replys", 512);
1096
ret = auth_client_lookup_and_restrict(auth_socket,
1097
&user, process_euid,
1103
if (strcmp(user, orig_user) != 0) {
1104
/* auth lookup changed the user. */
1105
if (getenv("DEBUG") != NULL)
1106
i_info("userdb changed username to %s", user);
1107
i_set_failure_prefix(t_strdup_printf("deliver(%s): ",
1110
/* if user was changed, it was allocated from userdb_pool
1111
which we'll free soon. */
1112
user = t_strdup(user);
1116
if (userdb_pool != NULL) {
1117
putenv_extra_fields(&extra_fields);
1118
pool_unref(&userdb_pool);
1121
/* Fix namespaces with empty locations */
1123
value = getenv(t_strdup_printf("NAMESPACE_%u", i));
1127
if (*value == '\0') {
1128
env_put(t_strdup_printf("NAMESPACE_%u=%s", i,
1133
/* If possible chdir to home directory, so that core file
1134
could be written in case we crash. */
1135
home = getenv("HOME");
1137
if (chdir(home) < 0) {
1138
if (errno != ENOENT)
1139
i_error("chdir(%s) failed: %m", home);
1140
else if (getenv("DEBUG") != NULL)
1141
i_info("Home dir not found: %s", home);
1145
env_put(t_strconcat("USER=", user, NULL));
1148
deliver_set->hostname = getenv("HOSTNAME");
1149
if (deliver_set->hostname == NULL)
1150
deliver_set->hostname = my_hostname;
1151
deliver_set->postmaster_address = getenv("POSTMASTER_ADDRESS");
1152
if (deliver_set->postmaster_address == NULL) {
1153
i_fatal_status(EX_TEMPFAIL,
1154
"postmaster_address setting not given");
1156
deliver_set->sendmail_path = getenv("SENDMAIL_PATH");
1157
if (deliver_set->sendmail_path == NULL)
1158
deliver_set->sendmail_path = DEFAULT_SENDMAIL_PATH;
1159
deliver_set->rejection_subject = getenv("REJECTION_SUBJECT");
1160
if (deliver_set->rejection_subject == NULL)
1161
deliver_set->rejection_subject = DEFAULT_MAIL_REJECTION_SUBJECT;
1162
deliver_set->rejection_reason = getenv("REJECTION_REASON");
1163
if (deliver_set->rejection_reason == NULL) {
1164
deliver_set->rejection_reason =
1165
DEFAULT_MAIL_REJECTION_HUMAN_REASON;
1167
deliver_set->log_format = getenv("DELIVER_LOG_FORMAT");
1168
if (deliver_set->log_format == NULL)
1169
deliver_set->log_format = DEFAULT_LOG_FORMAT;
1171
dict_drivers_register_builtin();
1173
mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
1174
mail_storage_init();
1175
mail_storage_register_all();
1176
mailbox_list_register_all();
1178
module_dir_init(modules);
1180
mail_user = mail_user_init(user);
1181
mail_user_set_home(mail_user, home);
1182
if (mail_namespaces_init(mail_user) < 0)
1183
i_fatal("Namespace initialization failed");
1185
/* create a separate mail user for the internal namespace */
1186
raw_mail_user = mail_user_init(user);
1187
mail_user_set_home(raw_mail_user, NULL);
1188
raw_ns = mail_namespaces_init_empty(raw_mail_user);
1189
raw_ns->flags |= NAMESPACE_FLAG_NOQUOTA | NAMESPACE_FLAG_NOACL;
1191
if (mail_storage_create(raw_ns, "raw", "/tmp",
1192
MAIL_STORAGE_FLAG_FULL_FS_ACCESS,
1193
FILE_LOCK_METHOD_FCNTL, &errstr) < 0)
1194
i_fatal("Couldn't create internal raw storage: %s", errstr);
1196
input = create_raw_stream(mail_user, 0, &mtime);
1197
box = mailbox_open(&raw_ns->storage, "Dovecot Delivery Mail",
1198
input, MAILBOX_OPEN_NO_INDEX_FILES);
1199
i_stream_unref(&input);
1202
box = mailbox_open(&raw_ns->storage, path, NULL,
1203
MAILBOX_OPEN_NO_INDEX_FILES);
1206
i_fatal("Can't open delivery mail as raw: %s",
1207
mail_storage_get_last_error(raw_ns->storage, &error));
1209
if (mailbox_sync(box, 0, 0, NULL) < 0) {
1210
i_fatal("Can't sync delivery mail: %s",
1211
mail_storage_get_last_error(raw_ns->storage, &error));
1213
raw_box = (struct raw_mailbox *)box;
1214
raw_box->envelope_sender = explicit_envelope_sender != NULL ?
1215
explicit_envelope_sender : DEFAULT_ENVELOPE_SENDER;
1216
raw_box->mtime = mtime;
1218
t = mailbox_transaction_begin(box, 0);
1219
headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
1220
mail = mail_alloc(t, 0, headers_ctx);
1221
mail_set_seq(mail, 1);
1223
if (destaddr == NULL) {
1224
destaddr = deliver_get_address(mail, "Envelope-To");
1225
if (destaddr == NULL) {
1226
destaddr = strchr(user, '@') != NULL ? user :
1227
t_strconcat(user, "@",
1228
deliver_set->hostname, NULL);
1233
default_mailbox_name = mailbox;
1234
if (deliver_mail == NULL)
1237
if (deliver_mail(mail_user->namespaces, &storage, mail,
1238
destaddr, mailbox) <= 0) {
1239
/* if message was saved, don't bounce it even though
1240
the script failed later. */
1241
ret = saved_mail ? 0 : -1;
1243
/* success. message may or may not have been saved. */
1248
if (ret < 0 && !tried_default_save) {
1249
/* plugins didn't handle this. save into the default mailbox. */
1250
ret = deliver_save(mail_user->namespaces,
1251
&storage, mailbox, mail, 0, NULL);
1253
if (ret < 0 && strcasecmp(mailbox, "INBOX") != 0) {
1254
/* still didn't work. try once more to save it
1256
ret = deliver_save(mail_user->namespaces,
1257
&storage, "INBOX", mail, 0, NULL);
1261
const char *error_string;
1262
enum mail_error error;
1264
if (storage == NULL) {
1265
/* This shouldn't happen */
1266
i_error("BUG: Saving failed for unknown storage");
1270
error_string = mail_storage_get_last_error(storage, &error);
1272
if (stderr_rejection) {
1273
/* write to stderr also for tempfails so that MTA
1274
can log the reason if it wants to. */
1275
fprintf(stderr, "%s\n", error_string);
1278
if (error != MAIL_ERROR_NOSPACE ||
1279
getenv("QUOTA_FULL_TEMPFAIL") != NULL) {
1280
/* Saving to INBOX should always work unless
1281
we're over quota. If it didn't, it's probably a
1282
configuration problem. */
1286
/* we'll have to reply with permanent failure */
1287
deliver_log(mail, "rejected: %s",
1288
str_sanitize(error_string, 512));
1290
if (stderr_rejection)
1292
ret = mail_send_rejection(mail, user, error_string);
1294
return ret < 0 ? EX_TEMPFAIL : ret;
1295
/* ok, rejection sent */
1297
i_free(explicit_envelope_sender);
1300
mailbox_header_lookup_unref(&headers_ctx);
1301
mailbox_transaction_rollback(&t);
1302
mailbox_close(&box);
1304
mail_user_unref(&mail_user);
1305
mail_user_unref(&raw_mail_user);
1307
module_dir_unload(&modules);
1308
mail_storage_deinit();
1309
mail_users_deinit();
1312
dict_drivers_unregister_builtin();
1313
lib_signals_deinit();
1315
io_loop_destroy(&ioloop);