commands.c revision f6008a666d9c3df66fd8a437369133e8519b4e24
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2009-2016 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"
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen#include "hex-dec.h"
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen#include "time-util.h"
18458233e89c8467e30d8b93b1823128f26bc174Timo Sirainen#include "var-expand.h"
ffaa309c211897ab875bbe0b093bc7e709bb1e5dTimo Sirainen#include "restrict-access.h"
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen#include "settings-parser.h"
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen#include "anvil-client.h"
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#include "master-service.h"
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen#include "master-service-ssl.h"
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen#include "iostream-ssl.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#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
a50f8b9c6196b0f0bb0a7aac3ae9c12b1c42b93bTimo Sirainen#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*125)
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainenstatic void client_input_data_write(struct client *client);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo 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
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_reset(client, "LHLO");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-%s", client->my_domain);
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen if (master_service_ssl_is_enabled(master_service) &&
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen client->ssl_iostream == NULL)
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen client_send_line(client, "250-STARTTLS");
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen if (client_is_trusted(client))
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen client_send_line(client, "250-XCLIENT ADDR PORT TTL TIMEOUT");
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));
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_set(client, "LHLO", "");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainenint cmd_starttls(struct client *client)
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen{
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen struct ostream *plain_output = client->output;
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen const char *error;
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen if (client->ssl_iostream != NULL) {
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen o_stream_nsend_str(client->output,
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen "443 5.5.1 TLS is already active.\r\n");
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen return 0;
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen }
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen if (master_service_ssl_init(master_service,
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen &client->input, &client->output,
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen &client->ssl_iostream, &error) < 0) {
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen i_error("TLS initialization failed: %s", error);
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen o_stream_nsend_str(client->output,
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen "454 4.7.0 Internal error, TLS not available.\r\n");
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen return 0;
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen }
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen o_stream_nsend_str(plain_output,
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen "220 2.0.0 Begin TLS negotiation now.\r\n");
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen if (ssl_iostream_handshake(client->ssl_iostream) < 0) {
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen client_destroy(client, NULL, NULL);
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen return -1;
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen }
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen return 0;
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen}
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainenstatic int parse_address(const char *str, const char **address_r,
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen const char **rest_r)
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen{
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen const char *start;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (*str++ != '<')
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen return -1;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen start = str;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (*str == '"') {
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen /* "quoted-string"@domain */
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen for (str++; *str != '"'; str++) {
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (*str == '\\')
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen str++;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (*str == '\0')
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen return -1;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen }
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen str++;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen }
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen for (; *str != '>'; str++) {
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (*str == '\0' || *str == ' ')
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen return -1;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen }
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen *address_r = t_strdup_until(start, str);
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (*str++ != '>')
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen return -1;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (*str == ' ')
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen str++;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen else if (*str != '\0')
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen return -1;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen *rest_r = str;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen return 0;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen}
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainenstatic const char *
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainenparse_xtext(struct client *client, const char *value)
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen{
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen const char *p;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen string_t *str;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen unsigned int i;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen p = strchr(value, '+');
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen if (p == NULL)
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen return p_strdup(client->state_pool, value);
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen /*
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen hexchar = ASCII "+" immediately followed by two upper case
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen hexadecimal digits
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen */
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen str = t_str_new(128);
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen for (i = 0; value[i] != '\0'; i++) {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen if (value[i] == '+' && value[i+1] != '\0' && value[i+2] != '\0') {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen str_append_c(str, hex2dec((const void *)(value+i+1), 2));
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen i += 2;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen } else {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen str_append_c(str, value[i]);
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen }
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen }
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen return p_strdup(client->state_pool, str_c(str));
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen}
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainenstatic void lmtp_anvil_init(void)
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen{
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen if (anvil == NULL) {
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen const char *path = t_strdup_printf("%s/anvil", base_dir);
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen anvil = anvil_client_init(path, NULL, 0);
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen }
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen}
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_mail(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen const char *addr, *const *argv;
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
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (strncasecmp(args, "FROM:", 5) != 0 ||
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen parse_address(args + 5, &addr, &args) < 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen argv = t_strsplit(args, " ");
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen for (; *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
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen client->state.mail_from = p_strdup(client->state_pool, addr);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen p_array_init(&client->state.rcpt_to, client->state_pool, 64);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.1.0 OK");
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_set(client, "MAIL FROM", client->state.mail_from);
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen if (client->lmtp_set->lmtp_user_concurrency_limit > 0) {
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen /* connect to anvil before dropping privileges */
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen lmtp_anvil_init();
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen }
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen client->state.mail_from_timeval = ioloop_timeval;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic bool
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainenclient_proxy_rcpt_parse_fields(struct lmtp_proxy_rcpt_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) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (net_str2port(value, &set->port) < 0) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch i_error("proxy: Invalid port number %s", value);
009217abb57a24a4076092e8e4e165545747839eStephan Bosch return FALSE;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch }
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen port_set = TRUE;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch } else if (strcmp(key, "proxy_timeout") == 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_uint(value, &set->timeout_msecs) < 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch i_error("proxy: Invalid proxy_timeout value %s", value);
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch return FALSE;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch }
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch set->timeout_msecs *= 1000;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch } 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,
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen const struct lmtp_proxy_rcpt_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 *
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Welleraddress_add_detail(const char *username, char delim_c,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen const char *detail)
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen{
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen const char *domain;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller const char delim[] = {delim_c, '\0'};
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,
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller const char *username, const char *detail, char delim,
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen const struct lmtp_recipient_params *params)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct auth_master_connection *auth_conn;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen struct lmtp_proxy_rcpt_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;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen set.params = *params;
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
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller address = address_add_detail(username, delim, 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
9508ac436fff0e1dcea975855c139cd251deb703Timo Sirainen if (client->proxy_ttl <= 1) {
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen i_error("Proxying to <%s> appears to be looping (TTL=0)",
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen username);
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen client_send_line(client, "554 5.4.6 <%s> "
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen "Proxying appears to be looping (TTL=0)",
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen username);
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen pool_unref(&pool);
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen return TRUE;
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo 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) {
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen struct lmtp_proxy_settings proxy_set;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen memset(&proxy_set, 0, sizeof(proxy_set));
32efae185f1f86167b3f00ea84f8502940c6c677Timo Sirainen proxy_set.my_hostname = client->my_domain;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen proxy_set.dns_client_socket_path = dns_client_socket_path;
d163fac99c7ca5b2ce2edfa83a1b2922cf66aeacTimo Sirainen proxy_set.session_id = client->state.session_id;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen proxy_set.source_ip = client->remote_ip;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen proxy_set.source_port = client->remote_port;
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen proxy_set.proxy_ttl = client->proxy_ttl-1;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen client->proxy = lmtp_proxy_init(&proxy_set, 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,
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller const char **username_r, char *delim_r,
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller const char **detail_r)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen{
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen const char *p, *domain;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller size_t idx;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *username_r = address;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *detail_r = "";
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
32efae185f1f86167b3f00ea84f8502940c6c677Timo Sirainen if (*client->unexpanded_lda_set->recipient_delimiter == '\0')
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen return;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen domain = strchr(address, '@');
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller /* first character that matches the recipient_delimiter */
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller idx = strcspn(address, client->unexpanded_lda_set->recipient_delimiter);
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller p = address[idx] != '\0' ? address + idx : NULL;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen if (p != NULL && (domain == NULL || p < domain)) {
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller *delim_r = *p;
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
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainenstatic void lmtp_address_translate(struct client *client, const char **address)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen{
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen const char *transpos = client->lmtp_set->lmtp_address_translate;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen const char *p, *nextstr, *addrpos = *address;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen unsigned int len;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen string_t *username, *domain, *dest = NULL;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if (*transpos == '\0')
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen return;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen username = t_str_new(64);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen domain = t_str_new(64);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* check that string matches up to the first '%' */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen p = strchr(transpos, '%');
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if (p == NULL)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen len = strlen(transpos);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen else
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen len = p-transpos;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if (strncmp(transpos, addrpos, len) != 0)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen return;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen transpos += len;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen addrpos += len;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen while (*transpos != '\0') {
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen switch (transpos[1]) {
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen case 'n':
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen case 'u':
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen dest = username;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen break;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen case 'd':
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen dest = domain;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen break;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen default:
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen return;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen }
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen transpos += 2;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* find where the next string starts */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if (*transpos == '\0') {
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen str_append(dest, addrpos);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen break;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen }
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen p = strchr(transpos, '%');
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if (p == NULL)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen nextstr = transpos;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen else
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen nextstr = t_strdup_until(transpos, p);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen p = strstr(addrpos, nextstr);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if (p == NULL)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen return;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen str_append_n(dest, addrpos, p-addrpos);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen len = strlen(nextstr);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen transpos += len;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen addrpos = p + len;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen }
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen str_append_c(username, '@');
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if (domain != NULL)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen str_append_str(username, domain);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen *address = str_c(username);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen}
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainenstatic void
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainenclient_send_line_overquota(struct client *client,
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen const struct mail_recipient *rcpt, const char *error)
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen{
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen struct lda_settings *lda_set =
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen mail_storage_service_user_get_set(rcpt->service_user)[1];
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen client_send_line(client, "%s <%s> %s", lda_set->quota_full_tempfail ?
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen "452 4.2.2" : "552 5.2.2", rcpt->address, error);
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen}
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainenstatic int
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainenlmtp_rcpt_to_is_over_quota(struct client *client,
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen const struct mail_recipient *rcpt)
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen{
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen struct mail_user *user;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen struct mail_namespace *ns;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen struct mailbox *box;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen struct mailbox_status status;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen const char *errstr;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen enum mail_error error;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen int ret;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen if (!client->lmtp_set->lmtp_rcpt_check_quota)
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen return 0;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen ret = mail_storage_service_next(storage_service,
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen rcpt->service_user, &user);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen if (ret < 0)
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen return -1;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen ns = mail_namespace_find_inbox(user->namespaces);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen box = mailbox_alloc(ns->list, "INBOX", 0);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen ret = mailbox_get_status(box, STATUS_CHECK_OVER_QUOTA, &status);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen if (ret < 0) {
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen errstr = mailbox_get_last_error(box, &error);
2ed2459dbd183bb371da4a0aecb2d2b74ae7c815Timo Sirainen if (error == MAIL_ERROR_NOQUOTA) {
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen client_send_line_overquota(client, rcpt, errstr);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen ret = 1;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen }
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen }
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen mailbox_free(&box);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen mail_user_unref(&user);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen return ret;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen}
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainenstatic void rcpt_anvil_lookup_callback(const char *reply, void *context)
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen{
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen struct mail_recipient *rcpt = context;
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen i_assert(rcpt->client->state.anvil_queries > 0);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen rcpt->anvil_query = NULL;
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen if (reply == NULL) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen /* lookup failed */
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen } else if (str_to_uint(reply, &rcpt->parallel_count) < 0) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen i_error("Invalid reply from anvil: %s", reply);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen }
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen if (--rcpt->client->state.anvil_queries == 0 &&
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen rcpt->client->state.anvil_pending_data_write) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen /* DATA command was finished, but we were still waiting on
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen anvil before handling any users */
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen client_input_data_write(rcpt->client);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen }
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen}
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rcpt(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen struct mail_recipient *rcpt;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen struct mail_storage_service_input input;
f6008a666d9c3df66fd8a437369133e8519b4e24Timo Sirainen const char *params, *address, *username, *detail;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen const char *const *argv;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen const char *error = NULL;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller char delim = '\0';
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
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (strncasecmp(args, "TO:", 3) != 0 ||
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen parse_address(args + 3, &address, &params) < 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen rcpt = p_new(client->state_pool, struct mail_recipient, 1);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen rcpt->client = client;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen address = lmtp_unescape_address(address);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen argv = t_strsplit(params, " ");
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen for (; *argv != NULL; argv++) {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen if (strncasecmp(*argv, "ORCPT=", 6) == 0) {
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen rcpt->params.dsn_orcpt = parse_xtext(client, *argv + 6);
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen } else {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen client_send_line(client, "501 5.5.4 Unsupported options");
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen return 0;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen }
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen }
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller rcpt_address_parse(client, address, &username, &delim, &detail);
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_set(client, "RCPT TO", address);
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen if (client->lmtp_set->lmtp_proxy) {
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller if (client_proxy_rcpt(client, address, username, detail, delim,
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen &rcpt->params))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return 0;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen /* Use a unique session_id for each mail delivery. This is especially
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen important for stats process to not see duplicate sessions. */
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen if (array_count(&client->state.rcpt_to) == 0)
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen rcpt->session_id = client->state.session_id;
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen else {
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen rcpt->session_id =
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen p_strdup_printf(client->state_pool, "%s:%u",
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen client->state.session_id,
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen array_count(&client->state.rcpt_to)+1);
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen }
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo 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;
d16cbc7557bc2e9f790c9c907212eb5df57a4ab2Timo Sirainen input.local_port = client->local_port;
d16cbc7557bc2e9f790c9c907212eb5df57a4ab2Timo Sirainen input.remote_port = client->remote_port;
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen input.session_id = rcpt->session_id;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = mail_storage_service_lookup(storage_service, &input,
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen &rcpt->service_user, &error);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (ret < 0) {
f6008a666d9c3df66fd8a437369133e8519b4e24Timo Sirainen i_error("Failed to lookup user %s: %s", username, error);
f6008a666d9c3df66fd8a437369133e8519b4e24Timo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, address);
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 }
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen if (client->proxy != NULL) {
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen /* NOTE: if this restriction is ever removed, we'll also need
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen to send different message bodies to local and proxy
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen (with and without Return-Path: header) */
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen client_send_line(client, "451 4.3.0 <%s> "
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen "Can't handle mixed proxy/non-proxy destinations",
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen address);
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen mail_storage_service_user_free(&rcpt->service_user);
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen return 0;
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen lmtp_address_translate(client, &address);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen rcpt->address = p_strdup(client->state_pool, address);
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen rcpt->detail = p_strdup(client->state_pool, detail);
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen if ((ret = lmtp_rcpt_to_is_over_quota(client, rcpt)) != 0) {
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen if (ret < 0) {
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen rcpt->address);
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen }
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen mail_storage_service_user_free(&rcpt->service_user);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen return 0;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen }
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen array_append(&client->state.rcpt_to, &rcpt, 1);
191a22ee13135fd752fcf03a43ef2f1b070937f5Timo Sirainen client_send_line(client, "250 2.1.5 OK");
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen if (client->lmtp_set->lmtp_user_concurrency_limit > 0) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen const char *query = t_strconcat("LOOKUP\t",
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen master_service_get_name(master_service),
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen "/", str_tabescape(username), NULL);
2010ab3fb1f5b758dae4c5e4e033c617d552985bTimo Sirainen client->state.anvil_queries++;
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen rcpt->anvil_query = anvil_client_query(anvil, query,
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen rcpt_anvil_lookup_callback, rcpt);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_quit(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen client_send_line(client, "221 2.0.0 OK");
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen /* don't log the (state name) for successful QUITs */
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen i_info("Disconnect from %s: Successful quit", client_remote_id(client));
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen client->disconnected = TRUE;
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen client_destroy(client, NULL, NULL);
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{
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_reset(client, "RSET");
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
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainenstatic bool orcpt_get_valid_rfc822(const char *orcpt, const char **addr_r)
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen{
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen if (orcpt == NULL || strncasecmp(orcpt, "rfc822;", 7) != 0)
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen return FALSE;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen /* FIXME: we should verify the address further */
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen *addr_r = orcpt + 7;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen return TRUE;
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen}
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic int
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenclient_deliver(struct client *client, const struct mail_recipient *rcpt,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo 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;
7ffa9e9809f10884a9167c19c09c980e3c1792b1Timo Sirainen const struct mail_storage_settings *mail_set;
8c30a8e508dd05b63c9b1fa7ae9c637d132dac6fTimo Sirainen struct lda_settings *lda_set;
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen struct mail_namespace *ns;
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen struct setting_parser_context *set_parser;
da0420f1b5d5f5ab1079d1204d70dd51866ce025Timo Sirainen struct timeval delivery_time_started;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen void **sets;
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen const char *line, *error, *username;
18458233e89c8467e30d8b93b1823128f26bc174Timo Sirainen string_t *str;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen enum mail_error mail_error;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen int ret;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen i_assert(client->state.anvil_queries == 0);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen input = mail_storage_service_user_get_input(rcpt->service_user);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen username = t_strdup(input->username);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
f24f2b5e17ea1ce029b5627a1dc50ba80f02c9c7Timo Sirainen if (client->lmtp_set->lmtp_user_concurrency_limit > 0 &&
f24f2b5e17ea1ce029b5627a1dc50ba80f02c9c7Timo Sirainen rcpt->parallel_count >= client->lmtp_set->lmtp_user_concurrency_limit) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen client_send_line(client, ERRSTR_TEMP_USERDB_FAIL_PREFIX
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen "Too many concurrent deliveries for user",
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen rcpt->address);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen return -1;
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen }
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen
7ffa9e9809f10884a9167c19c09c980e3c1792b1Timo Sirainen mail_set = mail_storage_service_user_get_mail_set(rcpt->service_user);
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen set_parser = mail_storage_service_user_get_settings_parser(rcpt->service_user);
7ffa9e9809f10884a9167c19c09c980e3c1792b1Timo Sirainen if (client->proxy_timeout_secs > 0 &&
7ffa9e9809f10884a9167c19c09c980e3c1792b1Timo Sirainen (mail_set->mail_max_lock_timeout == 0 ||
7ffa9e9809f10884a9167c19c09c980e3c1792b1Timo Sirainen mail_set->mail_max_lock_timeout > client->proxy_timeout_secs)) {
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen /* set lock timeout waits to be less than when proxy has
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen advertised that it's going to timeout the connection.
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen this avoids duplicate deliveries in case the delivery
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen succeeds after the proxy has already disconnected from us. */
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen line = t_strdup_printf("mail_max_lock_timeout=%u",
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen client->proxy_timeout_secs <= 1 ? 1 :
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen client->proxy_timeout_secs-1);
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen if (settings_parse_line(set_parser, line) < 0)
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen i_unreached();
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen }
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen
da0420f1b5d5f5ab1079d1204d70dd51866ce025Timo Sirainen /* get the timestamp before user is created, since it starts the I/O */
da0420f1b5d5f5ab1079d1204d70dd51866ce025Timo Sirainen io_loop_time_refresh();
da0420f1b5d5f5ab1079d1204d70dd51866ce025Timo Sirainen delivery_time_started = ioloop_timeval;
da0420f1b5d5f5ab1079d1204d70dd51866ce025Timo Sirainen
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_set(client, "DATA", username);
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("lmtp(%s, %s): ", my_pid, username);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (mail_storage_service_next(storage_service, rcpt->service_user,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo 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 }
18458233e89c8467e30d8b93b1823128f26bc174Timo Sirainen str = t_str_new(256);
18458233e89c8467e30d8b93b1823128f26bc174Timo Sirainen var_expand(str, client->state.dest_user->set->mail_log_prefix,
18458233e89c8467e30d8b93b1823128f26bc174Timo Sirainen mail_user_var_expand_table(client->state.dest_user));
18458233e89c8467e30d8b93b1823128f26bc174Timo Sirainen i_set_failure_prefix("%s", str_c(str));
18458233e89c8467e30d8b93b1823128f26bc174Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen sets = mail_storage_service_user_get_set(rcpt->service_user);
8c30a8e508dd05b63c9b1fa7ae9c637d132dac6fTimo Sirainen lda_set = sets[1];
8c30a8e508dd05b63c9b1fa7ae9c637d132dac6fTimo Sirainen settings_var_expand(&lda_setting_parser_info, lda_set, client->pool,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mail_user_var_expand_table(client->state.dest_user));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen memset(&dctx, 0, sizeof(dctx));
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen dctx.session = session;
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen dctx.pool = session->pool;
8c30a8e508dd05b63c9b1fa7ae9c637d132dac6fTimo Sirainen dctx.set = lda_set;
d25877a69c21fcd004f77bbfb1b8d0895d78e4ddTimo Sirainen dctx.timeout_secs = LDA_SUBMISSION_TIMEOUT_SECS;
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen dctx.session_id = rcpt->session_id;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen dctx.src_mail = src_mail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.src_envelope_sender = client->state.mail_from;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen dctx.dest_user = client->state.dest_user;
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen dctx.session_time_msecs =
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen timeval_diff_msecs(&client->state.data_end_timeval,
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen &client->state.mail_from_timeval);
da0420f1b5d5f5ab1079d1204d70dd51866ce025Timo Sirainen dctx.delivery_time_started = delivery_time_started;
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen if (orcpt_get_valid_rfc822(rcpt->params.dsn_orcpt, &dctx.dest_addr)) {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen /* used ORCPT */
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen } else if (*dctx.set->lda_original_recipient_header != '\0') {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo 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;
bfd8127fc0836b181b1ae65680bd6e3806b64fd1Timo Sirainen if (*rcpt->detail == '\0' ||
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen !client->lmtp_set->lmtp_save_to_detail_mailbox)
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen dctx.dest_mailbox_name = "INBOX";
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen else {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen ns = mail_namespace_find_inbox(dctx.dest_user->namespaces);
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen dctx.dest_mailbox_name =
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen t_strconcat(ns->prefix, rcpt->detail, NULL);
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen }
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen dctx.save_dest_mail = array_count(&client->state.rcpt_to) > 1 &&
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen client->state.first_saved_mail == NULL;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen if (client->lmtp_set->lmtp_user_concurrency_limit > 0) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen master_service_anvil_send(master_service, t_strconcat(
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen "CONNECT\t", my_pid, "\t", master_service_get_name(master_service),
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen "/", username, "\n", NULL));
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (mail_deliver(&dctx, &storage) == 0) {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen if (dctx.dest_mail != NULL) {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen i_assert(client->state.first_saved_mail == NULL);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen client->state.first_saved_mail = dctx.dest_mail;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client_send_line(client, "250 2.0.0 <%s> %s Saved",
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen rcpt->address, rcpt->session_id);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ret = 0;
1ee1a73bde20380ba39d572681397ad05dcdf9a1Timo Sirainen } else if (dctx.tempfail_error != NULL) {
1ee1a73bde20380ba39d572681397ad05dcdf9a1Timo Sirainen client_send_line(client, "451 4.2.0 <%s> %s",
1ee1a73bde20380ba39d572681397ad05dcdf9a1Timo Sirainen rcpt->address, dctx.tempfail_error);
1ee1a73bde20380ba39d572681397ad05dcdf9a1Timo Sirainen ret = -1;
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen } else if (storage != NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen error = mail_storage_get_last_error(storage, &mail_error);
2ed2459dbd183bb371da4a0aecb2d2b74ae7c815Timo Sirainen if (mail_error == MAIL_ERROR_NOQUOTA) {
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen client_send_line_overquota(client, rcpt, 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;
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen } else {
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen /* This shouldn't happen */
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen i_error("BUG: Saving failed to unknown storage");
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen rcpt->address);
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen ret = -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen if (client->lmtp_set->lmtp_user_concurrency_limit > 0) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen master_service_anvil_send(master_service, t_strconcat(
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen "DISCONNECT\t", my_pid, "\t", master_service_get_name(master_service),
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen "/", username, "\n", NULL));
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return ret;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainenstatic bool client_deliver_next(struct client *client, struct mail *src_mail,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mail_deliver_session *session)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen struct mail_recipient *const *rcpts;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen unsigned int count;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen int ret;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen rcpts = array_get(&client->state.rcpt_to, &count);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen while (client->state.rcpt_idx < count) {
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen ret = client_deliver(client, rcpts[client->state.rcpt_idx],
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen src_mail, session);
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_set(client, "DATA", "");
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("lmtp(%s): ", my_pid);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen client->state.rcpt_idx++;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen if (ret == 0)
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen return TRUE;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen /* failed. try the next one. */
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen if (client->state.dest_user != NULL)
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mail_user_unref(&client->state.dest_user);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen return FALSE;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
efb0def040a3e98da05ea77c170cd6711a9c8747Timo Sirainenstatic void client_rcpt_fail_all(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen struct mail_recipient *const *rcptp;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen array_foreach(&client->state.rcpt_to, rcptp) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen (*rcptp)->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);
ed74f1121a4b8e814427fbce8325108e39e1c805Timo Sirainen i_stream_set_name(cinput, "<lmtp DATA>");
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;
8aa60989067046e35c4809a616b46473fce0113eTimo Sirainen struct mailbox_transaction_context *trans;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen enum mail_error error;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
15dd1857d40544e2c356d4f1c87c42a0579c665cTimo Sirainen if (raw_mailbox_alloc_stream(client->raw_mail_user, input,
15dd1857d40544e2c356d4f1c87c42a0579c665cTimo Sirainen (time_t)-1, client->state.mail_from,
15dd1857d40544e2c356d4f1c87c42a0579c665cTimo Sirainen &box) < 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
8aa60989067046e35c4809a616b46473fce0113eTimo Sirainen trans = mailbox_transaction_begin(box, 0);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
8aa60989067046e35c4809a616b46473fce0113eTimo Sirainen client->state.raw_mail = mail_alloc(trans, 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;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mail *src_mail;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo 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();
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen src_mail = client->state.raw_mail;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen while (client_deliver_next(client, src_mail, session)) {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen if (client->state.first_saved_mail == NULL ||
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen client->state.first_saved_mail == src_mail)
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mail_user_unref(&client->state.dest_user);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen else {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen /* use the first saved message to save it elsewhere too.
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen this might allow hard linking the files. */
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen client->state.dest_user = NULL;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen src_mail = client->state.first_saved_mail;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen first_uid = geteuid();
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen i_assert(first_uid != 0);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen }
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen }
44f3f472a49078312432b785fddcfe7b95928391Timo Sirainen mail_deliver_session_deinit(&session);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen if (client->state.first_saved_mail != NULL) {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mail *mail = client->state.first_saved_mail;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mailbox_transaction_context *trans = mail->transaction;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mailbox *box = trans->box;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mail_user *user = box->storage->user;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen /* just in case these functions are going to write anything,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen change uid back to user's own one */
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen if (first_uid != old_uid) {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen if (seteuid(0) < 0)
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen i_fatal("seteuid(0) failed: %m");
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen if (seteuid(first_uid) < 0)
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen i_fatal("seteuid() failed: %m");
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen }
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mail_free(&mail);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mailbox_transaction_rollback(&trans);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mailbox_free(&box);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mail_user_unref(&user);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen }
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo 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");
ffaa309c211897ab875bbe0b093bc7e709bb1e5dTimo Sirainen /* enable core dumping again. we need to chdir also to
ffaa309c211897ab875bbe0b093bc7e709bb1e5dTimo Sirainen root-owned directory to get core dumps. */
ffaa309c211897ab875bbe0b093bc7e709bb1e5dTimo Sirainen restrict_access_allow_coredumps(TRUE);
de05e7b6a2fae2e2a799f4bd94803fcb1290d463Timo Sirainen if (chdir(base_dir) < 0)
de05e7b6a2fae2e2a799f4bd94803fcb1290d463Timo Sirainen i_error("chdir(%s) failed: %m", base_dir);
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic void client_input_data_finish(struct client *client)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
4818cf6ae9cda663ad68823fd83b18ac380a8a4dTimo Sirainen client_io_reset(client);
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_reset(client, "DATA finished");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (i_stream_have_bytes_left(client->input))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_input_handle(client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
701c9fc6dc06415bbf15490125e001d9db8c7cbdTimo Sirainenstatic void client_proxy_finish(void *context)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct client *client = context;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen lmtp_proxy_deinit(&client->proxy);
701c9fc6dc06415bbf15490125e001d9db8c7cbdTimo Sirainen client_input_data_finish(client);
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);
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen void **sets;
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen const struct lmtp_settings *lmtp_set;
16b3aad0065ff383a3c8804912048b40b9047018Pascal Volk const char *host, *rcpt_to = NULL;
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen if (array_count(&client->state.rcpt_to) == 1) {
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen struct mail_recipient *const *rcptp =
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen array_idx(&client->state.rcpt_to, 0);
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen sets = mail_storage_service_user_get_set((*rcptp)->service_user);
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen lmtp_set = sets[2];
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen switch (lmtp_set->parsed_lmtp_hdr_delivery_address) {
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen case LMTP_HDR_DELIVERY_ADDRESS_NONE:
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen break;
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen case LMTP_HDR_DELIVERY_ADDRESS_FINAL:
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen rcpt_to = (*rcptp)->address;
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen break;
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen case LMTP_HDR_DELIVERY_ADDRESS_ORIGINAL:
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen if (!orcpt_get_valid_rfc822((*rcptp)->params.dsn_orcpt,
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen &rcpt_to))
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen rcpt_to = (*rcptp)->address;
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen break;
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen }
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen }
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen
7f250fe7eede5f1d17c5e177c7f2dc0dd742e224Timo Sirainen /* don't set Return-Path when proxying so it won't get added twice */
7f250fe7eede5f1d17c5e177c7f2dc0dd742e224Timo Sirainen if (array_count(&client->state.rcpt_to) > 0) {
7f250fe7eede5f1d17c5e177c7f2dc0dd742e224Timo Sirainen str_printfa(str, "Return-Path: <%s>\r\n",
7f250fe7eede5f1d17c5e177c7f2dc0dd742e224Timo Sirainen client->state.mail_from);
7f250fe7eede5f1d17c5e177c7f2dc0dd742e224Timo Sirainen if (rcpt_to != NULL)
a192134d1aaf3ff73bff040c7cd9ab3e9a8fe1ddTimo Sirainen str_printfa(str, "Delivered-To: %s\r\n", rcpt_to);
7f250fe7eede5f1d17c5e177c7f2dc0dd742e224Timo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
fcd443a32b01c4da131f36649d5a5fa5f8452dcfTimo Sirainen str_printfa(str, "Received: from %s", client->lhlo);
39622d42aa198b19fb77d203e78a2418de68f740Timo Sirainen host = net_ip2addr(&client->remote_ip);
39622d42aa198b19fb77d203e78a2418de68f740Timo Sirainen if (host[0] != '\0')
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, " ([%s])", host);
0dc719a06fc1bbe11238762f9beb0c1faa4a2b75Timo Sirainen str_append(str, "\r\n");
0dc719a06fc1bbe11238762f9beb0c1faa4a2b75Timo Sirainen if (client->ssl_iostream != NULL) {
0dc719a06fc1bbe11238762f9beb0c1faa4a2b75Timo Sirainen str_printfa(str, "\t(using %s)\r\n",
0dc719a06fc1bbe11238762f9beb0c1faa4a2b75Timo Sirainen ssl_iostream_get_security_string(client->ssl_iostream));
0dc719a06fc1bbe11238762f9beb0c1faa4a2b75Timo Sirainen }
5a6ad44f13668817043427f98616c1f7a5cc2606Timo Sirainen str_printfa(str, "\tby %s 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
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainenstatic void client_input_data_write(struct client *client)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct istream *input;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
fb340f9dfd8ca3a66ef6830c047333a220e8f9b3Timo Sirainen /* stop handling client input until saving/proxying is finished */
fb340f9dfd8ca3a66ef6830c047333a220e8f9b3Timo Sirainen if (client->to_idle != NULL)
fb340f9dfd8ca3a66ef6830c047333a220e8f9b3Timo Sirainen timeout_remove(&client->to_idle);
701c9fc6dc06415bbf15490125e001d9db8c7cbdTimo Sirainen io_remove(&client->io);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen i_stream_destroy(&client->dot_input);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen client->state.data_end_timeval = ioloop_timeval;
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen input = client_get_input(client);
701c9fc6dc06415bbf15490125e001d9db8c7cbdTimo Sirainen if (array_count(&client->state.rcpt_to) != 0)
701c9fc6dc06415bbf15490125e001d9db8c7cbdTimo Sirainen client_input_data_write_local(client, input);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (client->proxy != NULL) {
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_set(client, "DATA", "proxying");
5b946df482ca0e5278ee93eea0d53f2cf09fadc1Timo Sirainen lmtp_proxy_start(client->proxy, input,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_proxy_finish, client);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen } else {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen client_input_data_finish(client);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen i_stream_unref(&input);
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;
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 */
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen if (i_unlink(str_c(path)) < 0) {
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* shouldn't happen.. */
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&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);
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen o_stream_set_name(state->mail_data_output, str_c(path));
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen o_stream_cork(state->mail_data_output);
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen o_stream_nsend(state->mail_data_output,
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen state->mail_data->data, state->mail_data->used);
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen o_stream_nsend(client->state.mail_data_output, data, size);
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen if (o_stream_nfinish(client->state.mail_data_output) < 0) {
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen i_error("write(%s) failed: %s", str_c(path),
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen o_stream_get_error(client->state.mail_data_output));
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return -1;
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen }
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
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen if (client->state.anvil_queries == 0)
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen client_input_data_write(client);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen else
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen client->state.anvil_pending_data_write = TRUE;
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");
75e2c45e2e60ba22728b7520818aa0a191f8ca3dTimo Sirainen /* send the DATA reply immediately before we start handling any data */
75e2c45e2e60ba22728b7520818aa0a191f8ca3dTimo Sirainen o_stream_uncork(client->output);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen io_remove(&client->io);
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_set(client, "DATA", "");
701c9fc6dc06415bbf15490125e001d9db8c7cbdTimo Sirainen client->io = io_add(client->fd_in, IO_READ, client_input_data, client);
701c9fc6dc06415bbf15490125e001d9db8c7cbdTimo Sirainen client_input_data_handle(client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainenint cmd_xclient(struct client *client, const char *args)
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen{
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen const char *const *tmp;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen struct ip_addr remote_ip;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t remote_port = 0;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch unsigned int ttl = UINT_MAX, timeout_secs = 0;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen bool args_ok = TRUE;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen if (!client_is_trusted(client)) {
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen client_send_line(client, "550 You are not from trusted IP");
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen return 0;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen }
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen remote_ip.family = 0;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) {
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen if (strncasecmp(*tmp, "ADDR=", 5) == 0) {
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen if (net_addr2ip(*tmp + 5, &remote_ip) < 0)
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen args_ok = FALSE;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen } else if (strncasecmp(*tmp, "PORT=", 5) == 0) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (net_str2port(*tmp + 5, &remote_port) < 0)
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen args_ok = FALSE;
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen } else if (strncasecmp(*tmp, "TTL=", 4) == 0) {
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen if (str_to_uint(*tmp + 4, &ttl) < 0)
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen args_ok = FALSE;
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen } else if (strncasecmp(*tmp, "TIMEOUT=", 8) == 0) {
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen if (str_to_uint(*tmp + 8, &timeout_secs) < 0)
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen args_ok = FALSE;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen }
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen }
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen if (!args_ok) {
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen client_send_line(client, "501 Invalid parameters");
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen return 0;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen }
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen /* args ok, set them and reset the state */
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen client_state_reset(client, "XCLIENT");
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen if (remote_ip.family != 0)
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen client->remote_ip = remote_ip;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen if (remote_port != 0)
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen client->remote_port = remote_port;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (ttl != UINT_MAX)
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen client->proxy_ttl = ttl;
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen client->proxy_timeout_secs = timeout_secs;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen client_send_line(client, "220 %s %s", client->my_domain,
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen client->lmtp_set->login_greeting);
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen return 0;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen}