commands.c revision 9deb15b8dec1a593940d72532ececc673c6b48ff
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2009-2010 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"
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> "
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen#define ERRSTR_TEMP_USERDB_FAIL \
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ERRSTR_TEMP_USERDB_FAIL_PREFIX "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, " ");
ad5130b3afda4cf30e6272d96d818f84d3ae4e55Timo Sirainen addr = argv[0] == NULL ? "" : argv[0];
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
ad5130b3afda4cf30e6272d96d818f84d3ae4e55Timo Sirainen for (argv++; *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
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;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen const char *args, *const *fields, *errstr, *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) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) :
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, address);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool_unref(&pool);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (ret < 0) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen client_send_line(client, "%s", errstr);
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,
98720d3b830e8ec762e9bdde94a71c0ef184595dTimo Sirainen dns_client_socket_path,
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;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen const char *address, *username, *detail, *prefix;
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, " ");
ad5130b3afda4cf30e6272d96d818f84d3ae4e55Timo Sirainen arg = argv[0] == NULL ? "" : argv[0];
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 }
ad5130b3afda4cf30e6272d96d818f84d3ae4e55Timo Sirainen argv++;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen memset(&rcpt, 0, sizeof(rcpt));
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen address = lmtp_unescape_address(t_strndup(arg + 4, len - 5));
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));
1e217aa0dad9bbfad64525396c3f226f170f985cTimo Sirainen input.module = input.service = "lmtp";
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) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen prefix = t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL_PREFIX,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen username);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen client_send_line(client, "%s%s", prefix, error);
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;
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo Sirainen uid_t old_uid;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char *error, *username;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen enum mail_error mail_error;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen int ret;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo Sirainen old_uid = geteuid();
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo 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,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen &client->state.dest_user) < 0) {
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 }
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo Sirainen if (old_uid == 0) {
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo Sirainen /* switch back to running as root, since that's what we're
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo Sirainen practically doing anyway. it's also important in case we
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo Sirainen lose e.g. config connection and need to reconnect to it. */
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo Sirainen if (seteuid(0) < 0)
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo Sirainen i_fatal("seteuid(0) failed: %m");
ca8c2190f161a28bb5020b6d6068d43ccf66b7d1Timo 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
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen inputs[0] = i_stream_create_from_data(state->added_headers,
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen strlen(state->added_headers));
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,
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen "Dovecot Delivery Mail",
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen MAILBOX_FLAG_NO_INDEX_FILES);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen if (mailbox_open_stream(box, input) < 0 ||
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen mailbox_sync(box, 0) < 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("Can't open delivery mail as raw: %s",
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mail_storage_get_last_error(box->storage, &error));
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen mailbox_free(&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 src_mail = client->state.raw_mail;
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen while (client_deliver_next(client, src_mail)) {
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen if (client->state.first_saved_mail == NULL ||
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen client->state.first_saved_mail == src_mail)
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen mail_user_unref(&client->state.dest_user);
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen else {
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen /* use the first saved message to save it elsewhere too.
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen this might allow hard linking the files. */
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen client->state.dest_user = NULL;
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen src_mail = client->state.first_saved_mail;
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen }
d80a44b0aab5f56e6044bd587ac3731c379aaa14Timo Sirainen }
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);
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen mailbox_free(&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
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainenstatic void client_proxy_finish(bool timeout, void *context)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct client *client = context;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen lmtp_proxy_deinit(&client->proxy);
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen if (timeout) {
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen client_destroy(client,
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen t_strdup_printf("421 4.4.2 %s", client->my_domain),
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen "Disconnected for inactivity");
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen } else {
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen client_input_data_finish(client);
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainenstatic const char *client_get_added_headers(struct client *client)
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen{
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen string_t *str = t_str_new(200);
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen const char *host, *rcpt_to = NULL;
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen if (array_count(&client->state.rcpt_to) == 1) {
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen const struct mail_recipient *rcpt =
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen array_idx(&client->state.rcpt_to, 0);
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen rcpt_to = rcpt->address;
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen }
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen str_printfa(str, "Return-Path: <%s>\r\n", client->state.mail_from);
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen if (rcpt_to != NULL)
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen str_printfa(str, "Delivered-To: <%s>\r\n", rcpt_to);
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");
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen if (rcpt_to != NULL)
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen str_printfa(str, "for <%s>", rcpt_to);
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{
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen struct client_state *state = &client->state;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen string_t *path;
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen ssize_t ret;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen int fd;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen if (state->mail_data_output != NULL) {
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* continue writing to file */
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen if (o_stream_send(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
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen state->mail_data_fd = fd;
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen state->mail_data_output = o_stream_create_fd_file(fd, 0, FALSE);
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen o_stream_cork(state->mail_data_output);
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen ret = o_stream_send(state->mail_data_output,
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen state->mail_data->data, state->mail_data->used);
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen if (ret != (ssize_t)state->mail_data->used)
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen return -1;
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 <=
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen CLIENT_MAIL_DATA_MAX_INMEMORY_SIZE &&
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen client->state.mail_data_output == NULL) {
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
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen client->state.added_headers =
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen p_strdup(client->state_pool, client_get_added_headers(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,
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen client->state.added_headers,
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}