deliver.c revision 77781e962bc3c861e9fa15fdcfb0334784f0312f
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek/* Copyright (C) 2005-2006 Timo Sirainen */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#define DEFAULT_CONFIG_FILE SYSCONFDIR"/dovecot.conf"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#define DEFAULT_AUTH_SOCKET_PATH PKG_RUNDIR"/auth-master"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek/* After buffer grows larger than this, create a temporary file to /tmp
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek where to read the mail. */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void sig_die(int signo, void *context __attr_unused__)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* warn about being killed because of some signal, except SIGINT (^C)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek which is too common at least while testing :) */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic struct mailbox *
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekmailbox_open_or_create_synced(struct mail_storage *storage, const char *name)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek (void)mail_storage_get_last_error(storage, &syntax, &temp);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* probably the mailbox just doesn't exist. try creating it. */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (mail_storage_mailbox_create(storage, name, FALSE) < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* and try opening again */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekint deliver_save(struct mail_storage *storage, const char *mailbox,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *const *keywords)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek box = mailbox_open_or_create_synced(storage, mailbox);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (mailbox_copy(t, mail, flags, kw, NULL) < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek msgid = mail_get_first_header(mail, "Message-ID");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_info(ret < 0 ? "msgid=%s: save failed to %s" :
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek "msgid=%s: saved mail to %s",
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekconst char *deliver_get_return_address(struct mail *mail)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *str;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek str = mail_get_first_header(mail, "Return-Path");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek (const unsigned char *)str,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return addr == NULL || addr->mailbox == NULL || addr->domain == NULL ?
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek static int count = 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return t_strdup_printf("<dovecot-%s-%s-%d@%s>",
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (def = setting_defs; def->name != NULL; def++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_fatal_status(EX_CONFIG, "open(%s) failed: %m", path);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek input = i_stream_create_file(fd, default_pool, 1024, TRUE);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek while ((line = i_stream_read_next_line(input)) != NULL) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* @UNSAFE: line is modified */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* skip whitespace */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* ignore comments or empty lines */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* strip away comments. pretty kludgy way really.. */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (*p == '\0')
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else if (*p == '#') {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* remove whitespace from end of line */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (setting_is_bool(key) && strcasecmp(value, "yes") != 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek env_put(t_strconcat(t_str_ucase(key), "=", value, NULL));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic const struct var_expand_table *
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekget_var_expand_table(const char *user, const char *home)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek static struct var_expand_table static_tab[] = {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek "/HOME_DIRECTORY_USED_BUT_NOT_GIVEN_BY_USERDB";
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekstatic const char *
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekexpand_mail_env(const char *env, const struct var_expand_table *table)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek const char *p;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* it's either type:data or just data */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek while (env != p) {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* expand home */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* expand %vars */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekstatic const char *address_sanitize(const char *address)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek const char *ret;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek pool = pool_alloconly_create("address sanitizer", 256);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek addr = message_address_parse(pool, (const unsigned char *)address,
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if (addr == NULL || addr->mailbox == NULL || addr->domain == NULL ||
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ret = t_strdup_printf("%s@%s", addr->mailbox, addr->domain);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic struct istream *create_mbox_stream(int fd, const char *envelope_sender)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek envelope_sender = address_sanitize(envelope_sender);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek mbox_hdr = mbox_from_create(envelope_sender, ioloop_time);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek input_list[0] = i_stream_create_from_data(default_pool, mbox_hdr,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek input_list[1] = i_stream_create_file(fd, default_pool, 4096, FALSE);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek input_list[2] = i_stream_create_from_data(default_pool, "\n", 1);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek input = i_stream_create_seekable(input_list, default_pool,
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek prefix = t_strdup_printf("deliver(%s)", username);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* log to file or stderr */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek i_set_failure_timestamp_format(getenv("LOG_TIMESTAMP"));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void print_help(void)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek"Usage: deliver [-c <config file>] [-d <destination user>] [-m <mailbox>]\n"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek" [-f <envelope sender>]\n");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *envelope_sender = DEFAULT_ENVELOPE_SENDER;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *home, *destination, *user, *mail_env, *value;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
#ifdef SIGXFSZ
env_clean();
if (i == argc) {
if (i == argc) {
if (i == argc) {
if (i == argc) {
print_help();
else if (process_euid != 0) {
if (ret != 0)
return ret;
(void)umask(i);
/* MAIL comes from userdb, MAIL_LOCATION from dovecot.conf */
TRUE);
if (ret <= 0) {
const char *error;
int ret;
if (temporary_error)
return EX_TEMPFAIL;
if (ret != 0)
lib_deinit();
return EX_OK;