commands.c revision f74f4098ee674df8e207e2bc3467e40c55d3b415
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "lib.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "ioloop.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "array.h"
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen#include "str.h"
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen#include "strescape.h"
419be6cd72f6e11705576bbba683b29c32eaa762Timo Sirainen#include "hostpid.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "istream.h"
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen#include "istream-concat.h"
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen#include "ostream.h"
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen#include "istream-dot.h"
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen#include "safe-mkstemp.h"
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#include "master-service.h"
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen#include "rfc822-parser.h"
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen#include "message-date.h"
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#include "auth-master.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "mail-storage-service.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "index/raw/raw-storage.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "lda-settings.h"
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen#include "lmtp-settings.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "mail-deliver.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "main.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "client.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "commands.h"
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#include "lmtp-proxy.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#include <stdlib.h>
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error"
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#define ERRSTR_TEMP_USERDB_FAIL "451 4.3.0 <%s> Temporary user lookup failure"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*30)
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainenint cmd_lhlo(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen struct rfc822_parser_context parser;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen string_t *domain = t_str_new(128);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen const char *p;
89502bb187e8285b2a155559894ca80374ac3ae7Timo Sirainen int ret = 0;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (*args == '\0') {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client_send_line(client, "501 Missing hostname");
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return 0;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* domain / address-literal */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen rfc822_parser_init(&parser, (const unsigned char *)args, strlen(args),
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen NULL);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (*args != '[')
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen ret = rfc822_parse_dot_atom(&parser, domain);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen else {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen for (p = args+1; *p != ']'; p++) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (*p == '\\' || *p == '[')
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen break;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (strcmp(p, "]") != 0)
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen ret = -1;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (ret < 0) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_truncate(domain, 0);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_append(domain, "invalid");
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_state_reset(client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-%s", client->my_domain);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-8BITMIME");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-ENHANCEDSTATUSCODES");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 PIPELINING");
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client->state.lhlo = p_strdup(client->state_pool, str_c(domain));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_mail(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen const char *addr, *const *argv;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int len;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client->state.mail_from != NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL already given");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen argv = t_strsplit(args, " ");
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen if (argv == NULL)
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen addr = "";
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen else {
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen addr = argv[0];
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen argv++;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen len = strlen(addr);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (strncasecmp(addr, "FROM:<", 6) != 0 || addr[len-1] != '>') {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen for (; *argv != NULL; argv++) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (strcasecmp(*argv, "BODY=7BIT") == 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client->mail_body_7bit = TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else if (strcasecmp(*argv, "BODY=8BITMIME") == 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client->mail_body_8bitmime = TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else {
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen client_send_line(client,
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen "501 5.5.4 Unsupported options");
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen return 0;
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.mail_from =
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen p_strndup(client->state_pool, addr + 6, len - 7);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen p_array_init(&client->state.rcpt_to, client->state_pool, 64);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.1.0 OK");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenstatic bool rcpt_is_duplicate(struct client *client, const char *address)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen const struct mail_recipient *rcpt;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_foreach(&client->state.rcpt_to, rcpt) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (strcmp(rcpt->address, address) == 0)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return TRUE;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return FALSE;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic bool
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenclient_proxy_rcpt_parse_fields(struct lmtp_proxy_settings *set,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const char *const *args, const char **address)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const char *p, *key, *value;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen bool proxying = FALSE, port_set = FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen for (; *args != NULL; args++) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen p = strchr(*args, '=');
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (p == NULL) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen key = *args;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen value = "";
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen } else {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen key = t_strdup_until(*args, p);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen value = p + 1;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (strcmp(key, "proxy") == 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen proxying = TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else if (strcmp(key, "host") == 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen set->host = value;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen else if (strcmp(key, "port") == 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen set->port = atoi(value);
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen port_set = TRUE;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen } else if (strcmp(key, "proxy_timeout") == 0)
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen set->timeout_msecs = atoi(value)*1000;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen else if (strcmp(key, "protocol") == 0) {
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen if (strcmp(value, "lmtp") == 0)
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen set->protocol = LMTP_CLIENT_PROTOCOL_LMTP;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen else if (strcmp(value, "smtp") == 0) {
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen set->protocol = LMTP_CLIENT_PROTOCOL_SMTP;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen if (!port_set)
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen set->port = 25;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen } else {
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen i_error("proxy: Unknown protocol %s", value);
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen return FALSE;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen }
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen } else if (strcmp(key, "user") == 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* changing the username */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen *address = value;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen } else {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* just ignore it */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (proxying && set->host == NULL) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen i_error("proxy: host not given");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return proxying;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic bool
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenclient_proxy_is_ourself(const struct client *client,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const struct lmtp_proxy_settings *set)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct ip_addr ip;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (set->port != client->local_port)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (net_addr2ip(set->host, &ip) < 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (!net_ip_compare(&ip, &client->local_ip))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenstatic bool client_proxy_rcpt(struct client *client, const char *address,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char *username)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct auth_master_connection *auth_conn;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct lmtp_proxy_settings set;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct auth_user_info info;
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen struct mail_storage_service_input input;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char *args, *const *fields, *orig_username = username;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool_t pool;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen int ret;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen memset(&input, 0, sizeof(input));
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen input.module = input.service = "lmtp";
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen mail_storage_service_init_settings(storage_service, &input);
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen memset(&info, 0, sizeof(info));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen info.service = master_service_get_name(master_service);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen info.local_ip = client->local_ip;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen info.remote_ip = client->remote_ip;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen info.local_port = client->local_port;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen info.remote_port = client->remote_port;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool = pool_alloconly_create("auth lookup", 1024);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen auth_conn = mail_storage_service_get_auth_conn(storage_service);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen ret = auth_master_pass_lookup(auth_conn, username, &info,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool, &fields);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (ret <= 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool_unref(&pool);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (ret < 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_send_line(client, ERRSTR_TEMP_USERDB_FAIL,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen address);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen } else {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* user not found from passdb. try userdb also. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen memset(&set, 0, sizeof(set));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen set.port = client->local_port;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen set.protocol = LMTP_CLIENT_PROTOCOL_LMTP;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* not proxying this user */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool_unref(&pool);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (strcmp(username, orig_username) == 0 &&
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_proxy_is_ourself(client, &set)) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen i_error("Proxying to <%s> loops to itself", username);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, "554 5.4.6 <%s> "
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen "Proxying loops to itself", address);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool_unref(&pool);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (client->proxy == NULL) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client->proxy = lmtp_proxy_init(client->set->hostname,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client->output);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (client->mail_body_8bitmime)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen args = " BODY=8BITMIME";
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else if (client->mail_body_7bit)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen args = " BODY=7BIT";
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen args = "";
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen lmtp_proxy_mail_from(client->proxy, t_strdup_printf(
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen "<%s>%s", client->state.mail_from, args));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_send_line(client, ERRSTR_TEMP_REMOTE_FAILURE);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_send_line(client, "250 2.1.5 OK");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool_unref(&pool);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainenstatic const char *lmtp_unescape_address(const char *name)
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen{
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen string_t *str;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen const char *p;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*name != '"')
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen return name;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* quoted-string local-part. drop the quotes unless there's a
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen '@' character inside or there's an error. */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen str = t_str_new(128);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen for (p = name+1; *p != '"'; p++) {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '\0')
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen return name;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '\\') {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (p[1] == '\0') {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* error */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen return name;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen }
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen p++;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen }
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '@')
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen return name;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen str_append_c(str, *p);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen }
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen p++;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p != '@' && *p != '\0')
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen return name;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen str_append(str, p);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen return str_c(str);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen}
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenstatic void rcpt_address_parse(struct client *client, const char *address,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char **username_r, const char **detail_r)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen{
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char *p, *p2;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *username_r = address;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *detail_r = "";
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (*client->set->recipient_delimiter == '\0')
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen return;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
f74f4098ee674df8e207e2bc3467e40c55d3b415Timo Sirainen p = strstr(address, client->set->recipient_delimiter);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (p != NULL) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen /* user+detail@domain */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *username_r = t_strdup_until(*username_r, p);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen p2 = strchr(p, '@');
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (p2 == NULL)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *detail_r = p+1;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen else {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *detail_r = t_strdup_until(p+1, p2);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *username_r = t_strconcat(*username_r, p2, NULL);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen }
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen }
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen}
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rcpt(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mail_recipient rcpt;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen struct mail_storage_service_input input;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char *address, *username, *detail;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char *error = NULL, *arg, *const *argv;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int len;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen int ret = 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client->state.mail_from == NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen argv = t_strsplit(args, " ");
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen if (argv == NULL)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen arg = "";
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen else {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen arg = argv[0];
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen argv++;
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen }
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen len = strlen(arg);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (strncasecmp(arg, "TO:<", 4) != 0 || arg[len-1] != '>') {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen memset(&rcpt, 0, sizeof(rcpt));
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen address = lmtp_unescape_address(t_strndup(arg + 4, len - 5));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (rcpt_is_duplicate(client, address)) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.1.5 OK, ignoring duplicate");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen if (*argv != NULL) {
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen client_send_line(client, "501 5.5.4 Unsupported options");
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen return 0;
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen }
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt_address_parse(client, address, &username, &detail);
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen if (client->lmtp_set->lmtp_proxy) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (client_proxy_rcpt(client, address, username))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return 0;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen memset(&input, 0, sizeof(input));
e1e1aedb16e04237b024c052587e2338c44159afTimo Sirainen input.service = "lmtp";
e1e1aedb16e04237b024c052587e2338c44159afTimo Sirainen input.module = "lda";
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen input.username = username;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen input.local_ip = client->local_ip;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen input.remote_ip = client->remote_ip;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = mail_storage_service_lookup(storage_service, &input,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen &rcpt.service_user, &error);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (ret < 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("User lookup failed: %s", error);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, ERRSTR_TEMP_USERDB_FAIL, username);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (ret == 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen "550 5.1.1 <%s> User doesn't exist: %s",
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen address, username);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt.address = p_strdup(client->state_pool, address);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt.detail = p_strdup(client->state_pool, detail);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen array_append(&client->state.rcpt_to, &rcpt, 1);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.1.5 OK");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_quit(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
ca598afa51b9c8ffd7c1460ac3c8bfa313c6d4afTimo Sirainen client_destroy(client, "221 2.0.0", "Client quit");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_vrfy(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "252 2.3.3 Try RCPT instead");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rset(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_state_reset(client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.0.0 OK");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_noop(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.0.0 OK");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic int
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenclient_deliver(struct client *client, const struct mail_recipient *rcpt,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mail *src_mail)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mail_deliver_context dctx;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mail_storage *storage;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const struct mail_storage_service_input *input;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen void **sets;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char *error, *username;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen enum mail_error mail_error;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen int ret;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen input = mail_storage_service_user_get_input(rcpt->service_user);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen username = t_strdup(input->username);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
419be6cd72f6e11705576bbba683b29c32eaa762Timo Sirainen i_set_failure_prefix(t_strdup_printf("lmtp(%s, %s): ",
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen my_pid, username));
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (mail_storage_service_next(storage_service, rcpt->service_user,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen &client->state.dest_user,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen &error) < 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("%s", error);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt->address);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen sets = mail_storage_service_user_get_set(rcpt->service_user);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen memset(&dctx, 0, sizeof(dctx));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.pool = pool_alloconly_create("mail delivery", 1024);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.set = sets[1];
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen dctx.session_id = client->state.session_id;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.src_mail = src_mail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.src_envelope_sender = client->state.mail_from;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.dest_user = client->state.dest_user;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen dctx.dest_addr = rcpt->address;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen dctx.dest_mailbox_name = *rcpt->detail == '\0' ? "INBOX" : rcpt->detail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.save_dest_mail = array_count(&client->state.rcpt_to) > 1 &&
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.first_saved_mail == NULL;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (mail_deliver(&dctx, &storage) == 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (dctx.dest_mail != NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_assert(client->state.first_saved_mail == NULL);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.first_saved_mail = dctx.dest_mail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client_send_line(client, "250 2.0.0 <%s> %s Saved",
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt->address, client->state.session_id);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ret = 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen } else if (storage == NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* This shouldn't happen */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("BUG: Saving failed to unknown storage");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt->address);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ret = -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen } else {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen error = mail_storage_get_last_error(storage, &mail_error);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (mail_error == MAIL_ERROR_NOSPACE) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "%s <%s> %s",
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.set->quota_full_tempfail ?
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen "452 4.2.2" : "552 5.2.2",
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt->address, error);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen } else {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "451 4.2.0 <%s> %s",
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt->address, error);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ret = -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen pool_unref(&dctx.pool);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return ret;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic bool client_deliver_next(struct client *client, struct mail *src_mail)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const struct mail_recipient *rcpts;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int count;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen int ret;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen rcpts = array_get(&client->state.rcpt_to, &count);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen while (client->state.rcpt_idx < count) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ret = client_deliver(client, &rcpts[client->state.rcpt_idx],
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen src_mail);
419be6cd72f6e11705576bbba683b29c32eaa762Timo Sirainen i_set_failure_prefix(t_strdup_printf("lmtp(%s): ", my_pid));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.rcpt_idx++;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (ret == 0)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return TRUE;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* failed. try the next one. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client->state.dest_user != NULL)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_user_unref(&client->state.dest_user);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return FALSE;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_rcpt_fail_all(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen const struct mail_recipient *rcpt;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen array_foreach(&client->state.rcpt_to, rcpt) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt->address);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic struct istream *client_get_input(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen struct client_state *state = &client->state;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen struct istream *cinput, *inputs[3];
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen inputs[0] = i_stream_create_from_data(state->received_line,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen strlen(state->received_line));
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (state->mail_data_output != NULL) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen o_stream_unref(&state->mail_data_output);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen inputs[1] = i_stream_create_fd(state->mail_data_fd,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen MAIL_READ_FULL_BLOCK_SIZE,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen FALSE);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen i_stream_set_init_buffer_size(inputs[1],
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen MAIL_READ_FULL_BLOCK_SIZE);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen } else {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen inputs[1] = i_stream_create_from_data(state->mail_data->data,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen state->mail_data->used);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen inputs[2] = NULL;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen cinput = i_stream_create_concat(inputs);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen i_stream_unref(&inputs[0]);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen i_stream_unref(&inputs[1]);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return cinput;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic int client_open_raw_mail(struct client *client, struct istream *input)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen static const char *wanted_headers[] = {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen "From", "To", "Message-ID", "Subject", "Return-Path",
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen NULL
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen };
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct mailbox *box;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct raw_mailbox *raw_box;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen enum mail_error error;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.raw_box = box =
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen mailbox_alloc(client->raw_mail_user->namespaces->list,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen "Dovecot Delivery Mail", input,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen MAILBOX_FLAG_NO_INDEX_FILES);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (mailbox_open(box) < 0 ||
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mailbox_sync(box, 0, 0, NULL) < 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("Can't open delivery mail as raw: %s",
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mail_storage_get_last_error(box->storage, &error));
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mailbox_close(&box);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_rcpt_fail_all(client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen raw_box = (struct raw_mailbox *)box;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen raw_box->envelope_sender = client->state.mail_from;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.raw_trans = mailbox_transaction_begin(box, 0);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.raw_mail = mail_alloc(client->state.raw_trans,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen 0, headers_ctx);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mailbox_header_lookup_unref(&headers_ctx);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_set_seq(client->state.raw_mail, 1);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic void
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenclient_input_data_write_local(struct client *client, struct istream *input)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mail *src_mail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (client_open_raw_mail(client, input) < 0)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* save the message to the first recipient's mailbox */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen src_mail = client->state.raw_mail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (!client_deliver_next(client, src_mail))
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client->state.first_saved_mail == NULL)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_user_unref(&client->state.dest_user);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen else
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen src_mail = client->state.first_saved_mail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* use the first saved message to save it elsewhere too.
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen this might allow hard linking the files. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen while (client_deliver_next(client, src_mail))
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_user_unref(&client->state.dest_user);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client->state.first_saved_mail != NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mail *mail = client->state.first_saved_mail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mailbox_transaction_context *trans = mail->transaction;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mailbox *box = trans->box;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_user *user = box->storage->user;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_free(&mail);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mailbox_transaction_rollback(&trans);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mailbox_close(&box);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_user_unref(&user);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic void client_input_data_finish(struct client *client)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
4818cf6ae9cda663ad68823fd83b18ac380a8a4dTimo Sirainen client_io_reset(client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_state_reset(client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (i_stream_have_bytes_left(client->input))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_input_handle(client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic void client_proxy_finish(void *context)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct client *client = context;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen lmtp_proxy_deinit(&client->proxy);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_input_data_finish(client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainenstatic const char *client_get_received_line(struct client *client)
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen{
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen string_t *str = t_str_new(200);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen const char *host;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "Received: from %s", client->state.lhlo);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if ((host = net_ip2addr(&client->remote_ip)) != NULL)
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, " ([%s])", host);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "\r\n\tby %s ("PACKAGE_NAME") with LMTP id %s",
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client->my_domain, client->state.session_id);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_append(str, "\r\n\t");
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (array_count(&client->state.rcpt_to) == 1) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen const struct mail_recipient *rcpt =
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen array_idx(&client->state.rcpt_to, 0);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen str_printfa(str, "for <%s>", rcpt->address);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "; %s\r\n", message_date_create(ioloop_time));
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return str_c(str);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen}
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic bool client_input_data_write(struct client *client)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct istream *input;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen bool ret = TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen i_stream_destroy(&client->dot_input);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen input = client_get_input(client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_input_data_write_local(client, input);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (client->proxy != NULL) {
c234fb9700e0c24fa52eba3d1204ae76c173b061Timo Sirainen lmtp_proxy_start(client->proxy, input, NULL,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_proxy_finish, client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen ret = FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen i_stream_unref(&input);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return ret;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainenstatic int client_input_add_file(struct client *client,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen const unsigned char *data, size_t size)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen{
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen string_t *path;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen int fd;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (client->state.mail_data_output != NULL) {
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* continue writing to file */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (o_stream_send(client->state.mail_data_output,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen data, size) != (ssize_t)size)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return -1;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return 0;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen }
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* move everything to a temporary file. FIXME: it really shouldn't
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen be in /tmp.. */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen path = t_str_new(256);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen str_append(path, "/tmp/dovecot.lmtp.");
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen fd = safe_mkstemp_hostpid(path, 0600, (uid_t)-1, (gid_t)-1);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (fd == -1)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return -1;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* we just want the fd, unlink it */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (unlink(str_c(path)) < 0) {
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* shouldn't happen.. */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen i_error("unlink(%s) failed: %m", str_c(path));
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen (void)close(fd);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return -1;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen }
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen client->state.mail_data_fd = fd;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen client->state.mail_data_output = o_stream_create_fd_file(fd, 0, FALSE);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen o_stream_cork(client->state.mail_data_output);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (o_stream_send(client->state.mail_data_output,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen data, size) != (ssize_t)size)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return -1;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return 0;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen}
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainenstatic int
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenclient_input_add(struct client *client, const unsigned char *data, size_t size)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (client->state.mail_data->used + size <=
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen CLIENT_MAIL_DATA_MAX_INMEMORY_SIZE) {
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen buffer_append(client->state.mail_data, data, size);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return 0;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen } else {
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return client_input_add_file(client, data, size);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data_handle(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const unsigned char *data;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen size_t size;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen ssize_t ret;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen while ((ret = i_stream_read(client->dot_input)) > 0 || ret == -2) {
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen data = i_stream_get_data(client->dot_input, &size);
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen if (client_input_add(client, data, size) < 0) {
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen client_destroy(client, "451 4.3.0",
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen "Temporary internal failure");
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen return;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen i_stream_skip(client->dot_input, size);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen if (ret == 0)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (client_input_data_write(client))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_input_data_finish(client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client_input_read(client) < 0)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_input_data_handle(client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_data(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client->state.mail_from == NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (array_count(&client->state.rcpt_to) == 0 && client->proxy == NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "554 5.5.1 No valid recipients");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c234fb9700e0c24fa52eba3d1204ae76c173b061Timo Sirainen client->state.received_line =
c234fb9700e0c24fa52eba3d1204ae76c173b061Timo Sirainen p_strdup(client->state_pool, client_get_received_line(client));
c234fb9700e0c24fa52eba3d1204ae76c173b061Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_assert(client->state.mail_data == NULL);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.mail_data = buffer_create_dynamic(default_pool, 1024*64);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen i_assert(client->dot_input == NULL);
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen client->dot_input = i_stream_create_dot(client->input, TRUE);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "354 OK");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen io_remove(&client->io);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (array_count(&client->state.rcpt_to) == 0) {
4818cf6ae9cda663ad68823fd83b18ac380a8a4dTimo Sirainen timeout_remove(&client->to_idle);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen lmtp_proxy_start(client->proxy, client->dot_input,
c234fb9700e0c24fa52eba3d1204ae76c173b061Timo Sirainen client->state.received_line,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_proxy_finish, client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen i_stream_unref(&client->dot_input);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen } else {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client->io = io_add(client->fd_in, IO_READ,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_input_data, client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_input_data_handle(client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}