deliver.c revision 77781e962bc3c861e9fa15fdcfb0334784f0312f
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek/* Copyright (C) 2005-2006 Timo Sirainen */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "lib.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "lib-signals.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "file-lock.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "ioloop.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "hostpid.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "home-expand.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "env-util.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "fd-set-nonblock.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "istream.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "istream-seekable.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "module-dir.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "str.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "str-sanitize.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "var-expand.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "message-address.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "dict-client.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "mbox-from.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "auth-client.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "mail-send.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "duplicate.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "deliver.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include <stdio.h>
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include <stdlib.h>
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include <unistd.h>
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include <fcntl.h>
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include <pwd.h>
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include <syslog.h>
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
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#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek/* After buffer grows larger than this, create a temporary file to /tmp
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek where to read the mail. */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek#define MAIL_MAX_MEMORY_BUFFER (1024*128)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekstruct deliver_settings *deliver_set;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekdeliver_mail_func_t *deliver_mail = NULL;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic struct module *modules;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic struct ioloop *ioloop;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void sig_die(int signo, void *context __attr_unused__)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* warn about being killed because of some signal, except SIGINT (^C)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek which is too common at least while testing :) */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (signo != SIGINT)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_warning("Killed with signal %d", signo);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek io_loop_stop(ioloop);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek}
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic int sync_quick(struct mailbox *box)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mailbox_sync_context *ctx;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mailbox_sync_rec sync_rec;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ctx = mailbox_sync_init(box, 0);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek while (mailbox_sync_next(ctx, &sync_rec) > 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return mailbox_sync_deinit(&ctx, 0, NULL);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic struct mailbox *
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekmailbox_open_or_create_synced(struct mail_storage *storage, const char *name)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mailbox *box;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek bool syntax, temp;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek MAILBOX_OPEN_KEEP_RECENT);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (box != NULL)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return box;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek (void)mail_storage_get_last_error(storage, &syntax, &temp);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (syntax || temp)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return NULL;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
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 return NULL;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* and try opening again */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek MAILBOX_OPEN_KEEP_RECENT);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (box == NULL)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return NULL;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (sync_quick(box) < 0) {
04868f1573f4b26ef34610b6d7069172f93bd8abJakub Hrozek mailbox_close(&box);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return NULL;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return box;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekint deliver_save(struct mail_storage *storage, const char *mailbox,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail *mail, enum mail_flags flags,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *const *keywords)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mailbox *box;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mailbox_transaction_context *t;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mail_keywords *kw;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *msgid;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek int ret = 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek box = mailbox_open_or_create_synced(storage, mailbox);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (box == NULL)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek kw = strarray_length(keywords) == 0 ? NULL :
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mailbox_keywords_create(t, keywords);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (mailbox_copy(t, mail, flags, kw, NULL) < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ret = -1;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mailbox_keywords_free(t, &kw);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (ret < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mailbox_transaction_rollback(&t);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek else
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ret = mailbox_transaction_commit(&t, 0);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
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 Hrozek msgid == NULL ? "" : str_sanitize(msgid, 80),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek str_sanitize(mailbox_get_name(box), 80));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek mailbox_close(&box);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return ret;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekconst char *deliver_get_return_address(struct mail *mail)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct message_address *addr;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *str;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek str = mail_get_first_header(mail, "Return-Path");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek addr = str == NULL ? NULL :
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek message_address_parse(pool_datastack_create(),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek (const unsigned char *)str,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek strlen(str), 1, FALSE);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return addr == NULL || addr->mailbox == NULL || addr->domain == NULL ?
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekconst char *deliver_get_new_message_id(void)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek static int count = 0;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return t_strdup_printf("<dovecot-%s-%s-%d@%s>",
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek dec2str(ioloop_timeval.tv_sec),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek dec2str(ioloop_timeval.tv_usec),
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek count++, deliver_set->hostname);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "settings.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "../master/master-settings.h"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#include "../master/master-settings-defs.c"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic bool setting_is_bool(const char *name)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const struct setting_def *def;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (def = setting_defs; def->name != NULL; def++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (strcmp(def->name, name) == 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return def->type == SET_BOOL;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return FALSE;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void config_file_init(const char *path)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct istream *input;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *key, *value;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek char *line, *p, quote;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek int fd, sections = 0, lda_section = FALSE;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek size_t len;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek fd = open(path, O_RDONLY);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (fd < 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_fatal_status(EX_CONFIG, "open(%s) failed: %m", path);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek t_push();
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
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* skip whitespace */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek while (IS_WHITE(*line))
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek line++;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* ignore comments or empty lines */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (*line == '#' || *line == '\0')
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek continue;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* strip away comments. pretty kludgy way really.. */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (p = line; *p != '\0'; p++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (*p == '\'' || *p == '"') {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek quote = *p;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek for (p++; *p != quote && *p != '\0'; p++) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (*p == '\\' && p[1] != '\0')
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek p++;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (*p == '\0')
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek break;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else if (*p == '#') {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek *p = '\0';
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek break;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* remove whitespace from end of line */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek len = strlen(line);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek while (IS_WHITE(line[len-1]))
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek len--;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek line[len] = '\0';
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek value = p = strchr(line, '=');
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (value == NULL) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (strchr(line, '{') != NULL) {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (strcmp(line, "protocol lda {") == 0 ||
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek strcmp(line, "plugin {") == 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek lda_section = TRUE;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek sections++;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (*line == '}') {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek sections--;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek lda_section = FALSE;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek continue;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (sections > 0 && !lda_section)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek continue;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek while (p > line && p[-1] == ' ') p--;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek key = t_strdup_until(line, p);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek do {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek value++;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } while (*value == ' ');
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (setting_is_bool(key) && strcasecmp(value, "yes") != 0)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek continue;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek env_put(t_strconcat(t_str_ucase(key), "=", value, NULL));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_stream_unref(&input);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek t_pop();
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic const struct var_expand_table *
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekget_var_expand_table(const char *user, const char *home)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek static struct var_expand_table static_tab[] = {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 'u', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 'n', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 'd', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 's', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 'h', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 'l', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 'r', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 'p', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { 'i', NULL },
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek { '\0', NULL }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek };
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct var_expand_table *tab;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek tab = t_malloc(sizeof(static_tab));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek memcpy(tab, static_tab, sizeof(static_tab));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek tab[0].value = user;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek tab[1].value = t_strcut(user, '@');
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek tab[2].value = strchr(user, '@');
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (tab[2].value != NULL) tab[2].value++;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek tab[3].value = "DELIVER";
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek tab[4].value = home != NULL ? home :
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek "/HOME_DIRECTORY_USED_BUT_NOT_GIVEN_BY_USERDB";
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek tab[5].value = NULL;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek tab[6].value = NULL;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek tab[7].value = my_pid;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek tab[8].value = dec2str(geteuid());
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek return tab;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek}
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekstatic const char *
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekexpand_mail_env(const char *env, const struct var_expand_table *table)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek{
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek string_t *str;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek const char *p;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek str = t_str_new(256);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* it's either type:data or just data */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek p = strchr(env, ':');
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if (p != NULL) {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek while (env != p) {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek str_append_c(str, *env);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek env++;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek }
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek str_append_c(str, *env++);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek }
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if (env[0] == '~' && env[1] == '/') {
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* expand home */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek env = t_strconcat("%h", env+1, NULL);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek }
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek /* expand %vars */
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek var_expand(str, env, table);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek return str_c(str);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek}
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozekstatic const char *address_sanitize(const char *address)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek{
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct message_address *addr;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek const char *ret;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek pool_t pool;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek pool = pool_alloconly_create("address sanitizer", 256);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek addr = message_address_parse(pool, (const unsigned char *)address,
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek strlen(address), 1, FALSE);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek if (addr == NULL || addr->mailbox == NULL || addr->domain == NULL ||
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek *addr->mailbox == '\0')
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek ret = DEFAULT_ENVELOPE_SENDER;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek else if (*addr->domain == '\0')
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ret = t_strdup(addr->mailbox);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek else
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek ret = t_strdup_printf("%s@%s", addr->mailbox, addr->domain);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek pool_unref(pool);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek return ret;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek}
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic struct istream *create_mbox_stream(int fd, const char *envelope_sender)
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek{
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek const char *mbox_hdr;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct istream *input_list[4], *input;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek fd_set_nonblock(fd, FALSE);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek envelope_sender = address_sanitize(envelope_sender);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek mbox_hdr = mbox_from_create(envelope_sender, ioloop_time);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek input_list[0] = i_stream_create_from_data(default_pool, mbox_hdr,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek strlen(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_list[3] = NULL;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek input = i_stream_create_seekable(input_list, default_pool,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek MAIL_MAX_MEMORY_BUFFER,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek "/tmp/dovecot.deliver.");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_stream_unref(&input_list[0]);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_stream_unref(&input_list[1]);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_stream_unref(&input_list[2]);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek return input;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void open_logfile(const char *username)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *prefix, *log_path;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek prefix = t_strdup_printf("deliver(%s)", username);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek log_path = getenv("LOG_PATH");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (log_path == NULL || *log_path == '\0') {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *env = getenv("SYSLOG_FACILITY");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_set_failure_syslog(prefix, LOG_NDELAY,
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek env == NULL ? LOG_MAIL : atoi(env));
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek } else {
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek /* log to file or stderr */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_set_failure_file(log_path, prefix);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek log_path = getenv("INFO_LOG_PATH");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (log_path != NULL && *log_path != '\0')
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek i_set_info_file(log_path);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek i_set_failure_timestamp_format(getenv("LOG_TIMESTAMP"));
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekstatic void print_help(void)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek printf(
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek"Usage: deliver [-c <config file>] [-d <destination user>] [-m <mailbox>]\n"
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek" [-f <envelope sender>]\n");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek}
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekint main(int argc, char *argv[])
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek{
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *config_path = DEFAULT_CONFIG_FILE;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *envelope_sender = DEFAULT_ENVELOPE_SENDER;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *mailbox = "INBOX";
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *auth_socket, *env_tz;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const char *home, *destination, *user, *mail_env, *value;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const struct var_expand_table *table;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek enum mail_storage_flags flags;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek enum file_lock_method lock_method;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct mail_storage *storage, *mbox_storage;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct mailbox *box;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct istream *input;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek struct mailbox_transaction_context *t;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek struct mail *mail;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek uid_t process_euid;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek int i, ret;
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek lib_init();
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek ioloop = io_loop_create(default_pool);
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek
5a4239490c7fb7d732180a9d40f27f0247c56631Jakub Hrozek lib_signals_init();
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
lib_signals_ignore(SIGPIPE, TRUE);
lib_signals_ignore(SIGALRM, FALSE);
#ifdef SIGXFSZ
lib_signals_ignore(SIGXFSZ, TRUE);
#endif
/* Clean up environment. */
env_tz = getenv("TZ");
home = getenv("HOME");
env_clean();
if (env_tz != NULL)
env_put(t_strconcat("TZ=", env_tz, NULL));
if (home != NULL)
env_put(t_strconcat("HOME=", home, NULL));
destination = NULL;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-d") == 0) {
/* destination user */
i++;
if (i == argc) {
i_fatal_status(EX_USAGE,
"Missing destination argument");
}
destination = argv[i];
} else if (strcmp(argv[i], "-c") == 0) {
/* config file path */
i++;
if (i == argc) {
i_fatal_status(EX_USAGE,
"Missing config file path argument");
}
config_path = argv[i];
} else if (strcmp(argv[i], "-m") == 0) {
/* destination mailbox */
i++;
if (i == argc) {
i_fatal_status(EX_USAGE,
"Missing mailbox argument");
}
mailbox = argv[i];
} else if (strcmp(argv[i], "-f") == 0) {
/* envelope sender address */
i++;
if (i == argc) {
i_fatal_status(EX_USAGE,
"Missing envelope argument");
}
envelope_sender = argv[i];
} else {
print_help();
i_fatal_status(EX_USAGE,
"Unknown argument: %s", argv[1]);
}
}
process_euid = geteuid();
if (destination != NULL)
user = destination;
else if (process_euid != 0) {
/* we're non-root. get our username and possibly our home. */
struct passwd *pw;
pw = getpwuid(process_euid);
if (pw != NULL) {
user = t_strdup(pw->pw_name);
if (getenv("HOME") == NULL)
env_put(t_strconcat("HOME=", pw->pw_dir, NULL));
} else {
i_fatal("Couldn't lookup our username (uid=%s)",
dec2str(process_euid));
}
} else {
i_fatal_status(EX_USAGE,
"destination user parameter (-d user) not given");
}
config_file_init(config_path);
open_logfile(user);
if (getenv("MAIL_DEBUG") != NULL)
env_put("DEBUG=1");
if (destination != NULL) {
auth_socket = getenv("AUTH_SOCKET_PATH");
if (auth_socket == NULL)
auth_socket = DEFAULT_AUTH_SOCKET_PATH;
ret = auth_client_put_user_env(ioloop, auth_socket,
destination, process_euid);
if (ret != 0)
return ret;
/* If possible chdir to home directory, so that core file
could be written in case we crash. */
home = getenv("HOME");
if (home != NULL) {
if (chdir(home) < 0) {
if (errno != ENOENT)
i_error("chdir(%s) failed: %m", home);
else if (getenv("DEBUG") != NULL)
i_info("Home dir not found: %s", home);
}
}
} else {
destination = user;
}
value = getenv("UMASK");
if (value == NULL || sscanf(value, "%i", &i) != 1 || i < 0)
i = 0077;
(void)umask(i);
deliver_set = i_new(struct deliver_settings, 1);
deliver_set->hostname = getenv("HOSTNAME");
if (deliver_set->hostname == NULL)
deliver_set->hostname = my_hostname;
deliver_set->postmaster_address = getenv("POSTMASTER_ADDRESS");
if (deliver_set->postmaster_address == NULL) {
i_fatal_status(EX_CONFIG,
"postmaster_address setting not given");
}
deliver_set->sendmail_path = getenv("SENDMAIL_PATH");
if (deliver_set->sendmail_path == NULL)
deliver_set->sendmail_path = DEFAULT_SENDMAIL_PATH;
dict_driver_register(&dict_driver_client);
duplicate_init();
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
/* MAIL comes from userdb, MAIL_LOCATION from dovecot.conf */
mail_env = getenv("MAIL");
if (mail_env == NULL)
mail_env = getenv("MAIL_LOCATION");
if (mail_env == NULL) {
/* Keep this for backwards compatibility */
mail_env = getenv("DEFAULT_MAIL_ENV");
}
if (mail_env != NULL) {
table = get_var_expand_table(destination, getenv("HOME"));
mail_env = expand_mail_env(mail_env, table);
}
if (getenv("MAIL_PLUGINS") == NULL)
modules = NULL;
else {
const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
if (plugin_dir == NULL)
plugin_dir = MODULEDIR"/lda";
modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
TRUE);
}
/* FIXME: how should we handle namespaces? */
mail_storage_parse_env(&flags, &lock_method);
storage = mail_storage_create_with_data(mail_env, destination,
flags, lock_method);
if (storage == NULL) {
i_fatal_status(EX_CONFIG,
"Failed to create storage for '%s' with mail '%s'",
destination, mail_env == NULL ? "(null)" : mail_env);
}
mbox_storage = mail_storage_create("mbox", "/tmp", destination, 0,
FILE_LOCK_METHOD_FCNTL);
input = create_mbox_stream(0, envelope_sender);
box = mailbox_open(mbox_storage, "Dovecot Delivery Mail", input,
MAILBOX_OPEN_NO_INDEX_FILES |
MAILBOX_OPEN_MBOX_ONE_MSG_ONLY);
if (box == NULL)
i_fatal("Can't open delivery mail as mbox");
if (sync_quick(box) < 0)
i_fatal("Can't sync delivery mail");
t = mailbox_transaction_begin(box, 0);
mail = mail_alloc(t, 0, NULL);
if (mail_set_seq(mail, 1) < 0)
i_fatal("mail_set_seq() failed");
ret = deliver_mail == NULL ? 0 :
deliver_mail(storage, mail, destination, mailbox);
if (ret <= 0) {
/* plugins didn't handle this. save into INBOX. */
i_stream_seek(input, 0);
if (deliver_save(storage, mailbox, mail, 0, NULL) < 0) {
const char *error;
bool syntax, temporary_error;
int ret;
error = mail_storage_get_last_error(storage, &syntax,
&temporary_error);
if (temporary_error)
return EX_TEMPFAIL;
/* we'll have to reply with permanent failure */
ret = mail_send_rejection(mail, destination, error);
if (ret != 0)
return ret < 0 ? EX_TEMPFAIL : ret;
/* ok, rejection sent */
}
}
i_stream_unref(&input);
mail_free(&mail);
mailbox_transaction_rollback(&t);
mailbox_close(&box);
mail_storage_destroy(&mbox_storage);
mail_storage_destroy(&storage);
module_dir_unload(&modules);
mail_storage_deinit();
duplicate_deinit();
dict_driver_unregister(&dict_driver_client);
lib_signals_deinit();
io_loop_destroy(&ioloop);
lib_deinit();
return EX_OK;
}