bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "lib.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"
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch#include "iostream-temp.h"
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch#include "master-service.h"
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch#include "settings-parser.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "lda-settings.h"
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch#include "mail-user.h"
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen#include "lmtp-settings.h"
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch#include "smtp-address.h"
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch#include "smtp-server.h"
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch#include "lmtp-proxy.h"
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch#include "lmtp-local.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "mail-deliver.h"
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch#include "mail-error.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "main.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "client.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "commands.h"
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * MAIL command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschint cmd_mail(void *conn_ctx,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_cmd_mail *data ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct client *client = (struct client *)conn_ctx;
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 }
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return 1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * RCPT command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschint cmd_rcpt(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_cmd_rcpt *data)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct client *client = (struct client *)conn_ctx;
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch const char *username, *detail;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller char delim = '\0';
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch int ret;
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch smtp_address_detail_parse_temp(
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client->unexpanded_lda_set->recipient_delimiter,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch data->path, &username, &delim, &detail);
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen if (client->lmtp_set->lmtp_proxy) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* proxied? */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if ((ret=lmtp_proxy_rcpt(client, cmd, data,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch username, detail, delim)) != 0)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return (ret < 0 ? -1 : 0);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* no */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* local delivery */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return lmtp_local_rcpt(client, cmd, data, username, detail);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch/*
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * DATA command
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch */
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschstatic void
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschcmd_data_create_added_headers(struct client *client,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_transaction *trans)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch size_t proxy_offset = 0;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch string_t *str;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch str = t_str_new(512);
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch /* headers for local deliveries only */
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch if (client->local != NULL)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch lmtp_local_add_headers(client->local, trans, str);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* headers for local and proxied messages */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch proxy_offset = str_len(str);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_server_transaction_write_trace_record(str, trans);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch client->state.added_headers_local =
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch p_strdup(client->state_pool, str_c(str));
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch client->state.added_headers_proxy =
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch client->state.added_headers_local + proxy_offset;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschstatic int
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschcmd_data_finish(struct client *client,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_cmd_ctx *cmd,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_transaction *trans)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct client_state *state = &client->state;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct istream *input_msg, *input_local, *input_proxy;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct istream *inputs[3];
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch client->state.data_end_timeval = ioloop_timeval;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* finish the message */
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch input_msg = iostream_temp_finish(&state->mail_data_output,
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch IO_BLOCK_SIZE);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* formulate prepended headers for both local and proxy delivery */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch cmd_data_create_added_headers(client, cmd, trans);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* construct message streams for local and proxy delivery */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch input_local = input_proxy = NULL;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (client->local != NULL) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch inputs[0] = i_stream_create_from_data(
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch state->added_headers_local,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch strlen(state->added_headers_local));
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch inputs[1] = input_msg;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch inputs[2] = NULL;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch input_local = i_stream_create_concat(inputs);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch i_stream_set_name(input_local, "<lmtp DATA local>");
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch i_stream_unref(&inputs[0]);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch }
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (client->proxy != NULL) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch inputs[0] = i_stream_create_from_data(
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch state->added_headers_proxy,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch strlen(state->added_headers_proxy));
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch inputs[1] = input_msg;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch inputs[2] = NULL;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch input_proxy = i_stream_create_concat(inputs);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch i_stream_set_name(input_proxy, "<lmtp DATA proxy>");
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch i_stream_unref(&inputs[0]);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch }
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch i_stream_unref(&input_msg);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* local delivery */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (client->local != NULL) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch lmtp_local_data(client, cmd, trans, input_local);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch i_stream_unref(&input_local);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch }
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* proxy delivery */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (client->proxy != NULL) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch lmtp_proxy_data(client, cmd, trans, input_proxy);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch i_stream_unref(&input_proxy);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch }
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return 0;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch}
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschint cmd_data_continue(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_transaction *trans)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch{
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct client *client = (struct client *)conn_ctx;
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch struct client_state *state = &client->state;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct istream *data_input = (struct istream *)trans->context;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const unsigned char *data;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen size_t size;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen ssize_t ret;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch i_assert(state->mail_data_output != NULL);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
f0a4f00d0312c101a69e2d5b2612d6300bb89367Stephan Bosch while ((ret = i_stream_read(data_input)) > 0 || ret == -2) {
f0a4f00d0312c101a69e2d5b2612d6300bb89367Stephan Bosch data = i_stream_get_data(data_input, &size);
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch if (o_stream_send(state->mail_data_output,
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch data, size) != (ssize_t)size) {
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch i_error("write(%s) failed: %s",
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch o_stream_get_name(state->mail_data_output),
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch o_stream_get_error(state->mail_data_output));
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_server_reply(cmd, 451, "4.3.0",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch "Temporary internal failure");
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return -1;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
f0a4f00d0312c101a69e2d5b2612d6300bb89367Stephan Bosch i_stream_skip(data_input, size);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (ret == 0)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return 0;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (ret < 0 && data_input->stream_errno != 0) {
85f8811e47003717620cbe066bb05494124308faTimo Sirainen /* client probably disconnected */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return -1;
85f8811e47003717620cbe066bb05494124308faTimo Sirainen }
85f8811e47003717620cbe066bb05494124308faTimo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* the ending "." line was seen. finish delivery. */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return cmd_data_finish(client, cmd, trans);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschint cmd_data_begin(void *conn_ctx,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_cmd_ctx *cmd,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_transaction *trans,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct istream *data_input)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen{
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct client *client = (struct client *)conn_ctx;
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch string_t *path;
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch i_assert(client->state.mail_data_output == NULL);
c234fb9700e0c24fa52eba3d1204ae76c173b061Timo Sirainen
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch path = t_str_new(256);
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch mail_user_set_get_temp_prefix(path, client->raw_mail_user->set);
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch client->state.mail_data_output =
b8b2cc4e58aef3759ed071d78afaa8319266afc4Stephan Bosch iostream_temp_create_named(str_c(path), 0, "(lmtp data)");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch cmd->context = (void*)client;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch trans->context = (void*)data_input;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}