commands.c revision f0a4f00d0312c101a69e2d5b2612d6300bb89367
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2009-2017 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"
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"
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"
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"
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch#include "lmtp-local.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "mail-deliver.h"
133a609acde637dd8f517903f9db978d96b7097eAki Tuomi#include "message-address.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"
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * EHLO command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
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
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * STARTTLS command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
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
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * MAIL command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_mail(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch struct smtp_address *address;
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch enum smtp_param_parse_error pperror;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch const char *error;
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
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch if (strncasecmp(args, "FROM:", 5) != 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch if (smtp_address_parse_path_full(pool_datastack_create(), args + 5,
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY,
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch &address, &error, &args) < 0) {
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, "501 5.5.4 Invalid FROM: %s", error);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch return 0;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch }
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch if (*args == ' ')
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch args++;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch else if (*args != '\0') {
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, "501 5.5.4 Invalid FROM: "
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch "Invalid character in path");
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch return 0;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch /* [SP Mail-parameters] */
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch if (smtp_params_mail_parse(client->state_pool, args,
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch SMTP_CAPABILITY_8BITMIME, FALSE,
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch &client->state.mail_params, &pperror, &error) < 0) {
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch switch (pperror) {
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch case SMTP_PARAM_PARSE_ERROR_BAD_SYNTAX:
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch client_send_line(client, "501 5.5.4 %s", error);
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch break;
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch case SMTP_PARAM_PARSE_ERROR_NOT_SUPPORTED:
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch client_send_line(client, "555 5.5.4 %s", error);
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch break;
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch default:
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch i_unreached();
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen }
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client->state.mail_from =
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch smtp_address_clone(client->state_pool, address);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.1.0 OK");
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_state_set(client, "MAIL FROM",
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch smtp_address_encode(address));
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
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * RCPT command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rcpt(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch struct smtp_address *address;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch const char *username, *detail;
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch struct smtp_params_rcpt params;
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch enum smtp_param_parse_error pperror;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen const char *error = NULL;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller char delim = '\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
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch if (strncasecmp(args, "TO:", 3) != 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch if (smtp_address_parse_path_full(pool_datastack_create(), args + 3,
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART,
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch &address, &error, &args) < 0) {
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, "501 5.5.4 Invalid TO: %s", error);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch return 0;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch }
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch if (*args == ' ')
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch args++;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch else if (*args != '\0') {
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, "501 5.5.4 Invalid TO: "
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch "Invalid character in path");
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch return 0;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch /* [SP Rcpt-parameters] */
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch if (smtp_params_rcpt_parse(client->state_pool, args,
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch SMTP_CAPABILITY_DSN, FALSE,
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch &params, &pperror, &error) < 0) {
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch switch (pperror) {
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch case SMTP_PARAM_PARSE_ERROR_BAD_SYNTAX:
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch client_send_line(client, "501 5.5.4 %s", error);
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch break;
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch case SMTP_PARAM_PARSE_ERROR_NOT_SUPPORTED:
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch client_send_line(client, "555 5.5.4 %s", error);
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch break;
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch default:
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch i_unreached();
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen }
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch return 0;
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen }
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch smtp_address_detail_parse_temp(
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client->unexpanded_lda_set->recipient_delimiter,
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch address, &username, &delim, &detail);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_state_set(client, "RCPT TO",
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch smtp_address_encode(address));
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen if (client->lmtp_set->lmtp_proxy) {
e4161404db08e61e835b330e8e12a4d0eb321ed3Stephan Bosch if (lmtp_proxy_rcpt(client, address, username, detail, delim,
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch &params) != 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return 0;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch return lmtp_local_rcpt(client, address, username, detail,
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch &params);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * QUIT command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
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
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * VRFY command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
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
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * RSET command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
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
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * NOOP command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
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
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * DATA command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
d41037c2b3e258e4e1fc73366d3fb191ffce64b6Stephan Boschstatic struct istream *cmd_data_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,
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi MAIL_READ_FULL_BLOCK_SIZE);
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 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);
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch const char *host, *rcpt_to = NULL;
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch /* headers for local deliveries only */
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch if (client->local != NULL)
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch lmtp_local_add_headers(client->local, str);
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)
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch 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 */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek 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
d41037c2b3e258e4e1fc73366d3fb191ffce64b6Stephan Bosch input = cmd_data_get_input(client);
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch if (lmtp_local_rcpt_count(client) != 0)
8a68f5bb807b5233e191641e7e7f993e707ae369Stephan Bosch lmtp_local_data(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
d8720e440375f80a2f55fe9c9650b1d3b2e37159Stephan Boschstatic int
d8720e440375f80a2f55fe9c9650b1d3b2e37159Stephan Boschcmd_data_input_add_file(struct client *client,
d8720e440375f80a2f55fe9c9650b1d3b2e37159Stephan Bosch 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);
d1ba8ecbb936ace90179d2292952546708d68f71Timo Sirainen if (o_stream_flush(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
7bb87935448ddcb2ead23022f556a595c4946bf8Stephan Boschcmd_data_input_add(struct client *client,
7bb87935448ddcb2ead23022f556a595c4946bf8Stephan Bosch 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 {
d8720e440375f80a2f55fe9c9650b1d3b2e37159Stephan Bosch return cmd_data_input_add_file(client, data, size);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data_handle(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
f0a4f00d0312c101a69e2d5b2612d6300bb89367Stephan Bosch struct istream *data_input = client->dot_input;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const unsigned char *data;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen size_t size;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen ssize_t ret;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen
f0a4f00d0312c101a69e2d5b2612d6300bb89367Stephan Bosch while ((ret = i_stream_read(data_input)) > 0 || ret == -2) {
f0a4f00d0312c101a69e2d5b2612d6300bb89367Stephan Bosch data = i_stream_get_data(data_input, &size);
7bb87935448ddcb2ead23022f556a595c4946bf8Stephan Bosch if (cmd_data_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 }
f0a4f00d0312c101a69e2d5b2612d6300bb89367Stephan Bosch i_stream_skip(data_input, size);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen if (ret == 0)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
f0a4f00d0312c101a69e2d5b2612d6300bb89367Stephan Bosch if (data_input->stream_errno != 0) {
85f8811e47003717620cbe066bb05494124308faTimo Sirainen /* client probably disconnected */
85f8811e47003717620cbe066bb05494124308faTimo Sirainen client_destroy(client, NULL, NULL);
85f8811e47003717620cbe066bb05494124308faTimo Sirainen return;
85f8811e47003717620cbe066bb05494124308faTimo Sirainen }
85f8811e47003717620cbe066bb05494124308faTimo Sirainen
3bb61142ca8dc0c71efd430fa8f805a4c7262aa8Timo Sirainen /* the ending "." line was seen. begin saving the mail. */
ced943b0a9b49a5be38516302fe1631c1883debaTimo Sirainen client_input_data_write(client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client_input_read(client) < 0)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_input_data_handle(client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_data(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (client->state.mail_from == NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch if ((lmtp_local_rcpt_count(client) +
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch lmtp_proxy_rcpt_count(client)) == 0) {
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
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * XCLIENT command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
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) {
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch const char *addr = *tmp + 5;
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch bool ipv6 = FALSE;
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch if (strncasecmp(addr, "IPV6:", 5) == 0) {
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch addr += 5;
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch ipv6 = TRUE;
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch }
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch if (net_addr2ip(addr, &remote_ip) < 0 ||
6ee910623ad15fd5fab17b18cc03204d9aded709Stephan Bosch (ipv6 && remote_ip.family != AF_INET6))
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}