commands.c revision 2e37d45867d081db150ab78dad303b9077aea24f
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2009-2011 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"
78a5b3e697af5db96fe0dffed600b0d6370bb8e5Timo Sirainen#include "mail-namespace.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
fcd443a32b01c4da131f36649d5a5fa5f8452dcfTimo Sirainen i_free(client->lhlo);
fcd443a32b01c4da131f36649d5a5fa5f8452dcfTimo Sirainen client->lhlo = i_strdup(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)
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen client->state.mail_body_7bit = TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else if (strcasecmp(*argv, "BODY=8BITMIME") == 0)
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen client->state.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 }
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen } else if (strcmp(key, "user") == 0 ||
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen strcmp(key, "destuser") == 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
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenstatic const char *
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenaddress_add_detail(struct client *client, const char *username,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen const char *detail)
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen{
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen const char *delim = client->set->recipient_delimiter;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen const char *domain;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen domain = strchr(username, '@');
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (domain == NULL)
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return t_strconcat(username, delim, detail, NULL);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen else {
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen username = t_strdup_until(username, domain);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return t_strconcat(username, delim, detail, domain, NULL);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen }
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen}
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenstatic bool client_proxy_rcpt(struct client *client, const char *address,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen const char *username, const char *detail)
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 }
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (strcmp(username, orig_username) != 0) {
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* username changed. change the address as well */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (*detail == '\0')
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen address = username;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen else
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen address = address_add_detail(client, username, detail);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen } else if (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);
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen return TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen if (array_count(&client->state.rcpt_to) != 0) {
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen client_send_line(client, "451 4.3.0 <%s> "
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen "Can't handle mixed proxy/non-proxy destinations",
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen address);
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen pool_unref(&pool);
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen return TRUE;
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo 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);
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen if (client->state.mail_body_8bitmime)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen args = " BODY=8BITMIME";
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen else if (client->state.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{
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen const char *p, *domain;
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
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen domain = strchr(address, '@');
f74f4098ee674df8e207e2bc3467e40c55d3b415Timo Sirainen p = strstr(address, client->set->recipient_delimiter);
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen if (p != NULL && (domain == NULL || p < domain)) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen /* user+detail@domain */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *username_r = t_strdup_until(*username_r, p);
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen if (domain == NULL)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *detail_r = p+1;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen else {
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen *detail_r = t_strdup_until(p+1, domain);
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen *username_r = t_strconcat(*username_r, domain, 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) {
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (client_proxy_rcpt(client, address, username, detail))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return 0;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen if (client->proxy != NULL) {
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen client_send_line(client, "451 4.3.0 <%s> "
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen "Can't handle mixed proxy/non-proxy destinations",
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen address);
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen return 0;
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen }
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo 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,
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen struct mail *src_mail, struct mail_deliver_session *session)
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,
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));
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen dctx.session = session;
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen dctx.pool = session->pool;
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;
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen if (*dctx.set->lda_original_recipient_header != '\0') {
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen dctx.dest_addr = mail_deliver_get_address(src_mail,
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen dctx.set->lda_original_recipient_header);
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen }
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen if (dctx.dest_addr == NULL)
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen dctx.dest_addr = rcpt->address;
9c45821d7448c6f63391d318a6dff785e46e58eeTimo Sirainen dctx.final_dest_addr = rcpt->address;
70af4db1c95a5ea3749213da539359b76abcfcd1Timo Sirainen dctx.dest_mailbox_name = *rcpt->detail != '\0' &&
70af4db1c95a5ea3749213da539359b76abcfcd1Timo Sirainen client->lmtp_set->lmtp_save_to_detail_mailbox ?
70af4db1c95a5ea3749213da539359b76abcfcd1Timo Sirainen rcpt->detail : "INBOX";
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 return ret;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainenstatic bool client_deliver_next(struct client *client, struct mail *src_mail,
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen struct mail_deliver_session *session)
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],
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen src_mail, session);
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
efb0def040a3e98da05ea77c170cd6711a9c8747Timo 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
4143cfa11582989252741398b5ee0a6041d3da15Timo Sirainen box = mailbox_alloc(client->raw_mail_user->namespaces->list,
4143cfa11582989252741398b5ee0a6041d3da15Timo Sirainen "Dovecot Delivery Mail",
4143cfa11582989252741398b5ee0a6041d3da15Timo 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",
11352dc3e4b29f3d2763c82f8ea4f99e8daf4fa3Timo Sirainen mailbox_get_last_error(box, &error));
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen mailbox_free(&box);
efb0def040a3e98da05ea77c170cd6711a9c8747Timo 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
4143cfa11582989252741398b5ee0a6041d3da15Timo Sirainen client->state.raw_box = box;
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{
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen struct mail_deliver_session *session;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mail *src_mail;
3bd374bc3ff357d7464920ec54cef46043aecf31Timo Sirainen uid_t old_uid, first_uid = (uid_t)-1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
efb0def040a3e98da05ea77c170cd6711a9c8747Timo Sirainen if (client_open_raw_mail(client, input) < 0)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen session = mail_deliver_session_init();
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen old_uid = geteuid();
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen src_mail = client->state.raw_mail;
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen while (client_deliver_next(client, src_mail, session)) {
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;
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen first_uid = geteuid();
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen i_assert(first_uid != 0);
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen }
d80a44b0aab5f56e6044bd587ac3731c379aaa14Timo Sirainen }
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen mail_deliver_session_deinit(&session);
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
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen /* just in case these functions are going to write anything,
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen change uid back to user's own one */
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen if (first_uid != old_uid) {
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen if (seteuid(0) < 0)
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen i_fatal("seteuid(0) failed: %m");
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen if (seteuid(first_uid) < 0)
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen i_fatal("seteuid() failed: %m");
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen }
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo 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 }
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen if (old_uid == 0) {
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen /* switch back to running as root, since that's what we're
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen practically doing anyway. it's also important in case we
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen lose e.g. config connection and need to reconnect to it. */
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen if (seteuid(0) < 0)
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen i_fatal("seteuid(0) failed: %m");
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo 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);
16b3aad0065ff383a3c8804912048b40b9047018Pascal Volk 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
16b3aad0065ff383a3c8804912048b40b9047018Pascal Volk rcpt_to = rcpt->address;
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen }
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen str_printfa(str, "Return-Path: <%s>\r\n", client->state.mail_from);
16b3aad0065ff383a3c8804912048b40b9047018Pascal Volk if (rcpt_to != NULL)
16b3aad0065ff383a3c8804912048b40b9047018Pascal Volk str_printfa(str, "Delivered-To: <%s>\r\n", rcpt_to);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
fcd443a32b01c4da131f36649d5a5fa5f8452dcfTimo Sirainen str_printfa(str, "Received: from %s", client->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");
16b3aad0065ff383a3c8804912048b40b9047018Pascal Volk if (rcpt_to != NULL)
16b3aad0065ff383a3c8804912048b40b9047018Pascal Volk 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
b5babd4ea611616f0b3b2b9fb5917c78d1999a7bTimo Sirainen /* move everything to a temporary file. */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen path = t_str_new(256);
4afd50dff16661684ad2acddad7284bcd8c564dbTimo Sirainen mail_user_set_get_temp_prefix(path, client->raw_mail_user->set);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen fd = safe_mkstemp_hostpid(path, 0600, (uid_t)-1, (gid_t)-1);
4afd50dff16661684ad2acddad7284bcd8c564dbTimo Sirainen if (fd == -1) {
4afd50dff16661684ad2acddad7284bcd8c564dbTimo Sirainen i_error("Temp file creation to %s failed: %m", str_c(path));
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return -1;
4afd50dff16661684ad2acddad7284bcd8c564dbTimo Sirainen }
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
85f8811e47003717620cbe066bb05494124308faTimo Sirainen if (!client->dot_input->eof) {
85f8811e47003717620cbe066bb05494124308faTimo Sirainen /* client probably disconnected */
85f8811e47003717620cbe066bb05494124308faTimo Sirainen client_destroy(client, NULL, NULL);
85f8811e47003717620cbe066bb05494124308faTimo Sirainen return;
85f8811e47003717620cbe066bb05494124308faTimo Sirainen }
85f8811e47003717620cbe066bb05494124308faTimo 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}