bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "lib.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "array.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "str.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "strfuncs.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "guid.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "base64.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "message-date.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-address.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-server-private.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_transaction *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_transaction_create(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_address *mail_from,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_params_mail *params,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct timeval *timestamp)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_transaction *trans;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool_t pool;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch guid_128_t guid;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch string_t *id;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* create new transaction */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool = pool_alloconly_create("smtp server transaction", 512);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch trans = p_new(pool, struct smtp_server_transaction, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch trans->pool = pool;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch trans->conn = conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* generate transaction ID */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch id = t_str_new(30);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch guid_128_generate(guid);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch base64_encode(guid, sizeof(guid), id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(str_c(id)[str_len(id)-2] == '=');
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_truncate(id, str_len(id)-2); /* drop trailing "==" */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch trans->id = p_strdup(pool, str_c(id));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch trans->mail_from = smtp_address_clone(trans->pool, mail_from);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_params_mail_copy(pool, &trans->params, params);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch trans->timestamp = *timestamp;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return trans;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_transaction_free(struct smtp_server_transaction **_trans)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_transaction *trans = *_trans;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool_unref(&trans->pool);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch *_trans = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Boschstruct smtp_server_recipient *
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Boschsmtp_server_transaction_find_rcpt_duplicate(
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch struct smtp_server_transaction *trans,
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch struct smtp_server_recipient *rcpt)
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch{
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch struct smtp_server_recipient *const *rcptp;
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch i_assert(array_is_created(&trans->rcpt_to));
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch array_foreach(&trans->rcpt_to, rcptp) {
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch struct smtp_server_recipient *drcpt = *rcptp;
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch if (drcpt == rcpt)
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch continue;
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch if (smtp_address_equals(drcpt->path, rcpt->path) &&
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch smtp_params_rcpt_equals(&drcpt->params, &rcpt->params))
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch return drcpt;
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch }
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch return NULL;
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch}
499ca6dc5d746fd7a7efc6d497deede89553669fStephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_recipient *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_transaction_add_rcpt(struct smtp_server_transaction *trans,
5d5ad796fc34170333bb52c05614425a0dd7e182Stephan Bosch const struct smtp_address *rcpt_to,
5d5ad796fc34170333bb52c05614425a0dd7e182Stephan Bosch const struct smtp_params_rcpt *params)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_recipient *rcpt;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch rcpt = p_new(trans->pool, struct smtp_server_recipient, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch rcpt->path = smtp_address_clone(trans->pool, rcpt_to);
5d5ad796fc34170333bb52c05614425a0dd7e182Stephan Bosch smtp_params_rcpt_copy(trans->pool, &rcpt->params, params);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!array_is_created(&trans->rcpt_to))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch p_array_init(&trans->rcpt_to, trans->pool, 8);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_append(&trans->rcpt_to, &rcpt, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return rcpt;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_transaction_has_rcpt(struct smtp_server_transaction *trans)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return (array_is_created(&trans->rcpt_to) &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_count(&trans->rcpt_to) > 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
6d76b99eb61df1cbe13cf76d0aac81507cbd1d21Stephan Boschunsigned int
6d76b99eb61df1cbe13cf76d0aac81507cbd1d21Stephan Boschsmtp_server_transaction_rcpt_count(struct smtp_server_transaction *trans)
6d76b99eb61df1cbe13cf76d0aac81507cbd1d21Stephan Bosch{
6d76b99eb61df1cbe13cf76d0aac81507cbd1d21Stephan Bosch if (!array_is_created(&trans->rcpt_to))
6d76b99eb61df1cbe13cf76d0aac81507cbd1d21Stephan Bosch return 0;
6d76b99eb61df1cbe13cf76d0aac81507cbd1d21Stephan Bosch return array_count(&trans->rcpt_to);
6d76b99eb61df1cbe13cf76d0aac81507cbd1d21Stephan Bosch}
6d76b99eb61df1cbe13cf76d0aac81507cbd1d21Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_transaction_fail_data(struct smtp_server_transaction *trans,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_cmd_ctx *data_cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int status, const char *enh_code,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *fmt, va_list args)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_recipient *const *rcpts;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *msg;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int count, i;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch msg = t_strdup_vprintf(fmt, args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch rcpts = array_get(&trans->rcpt_to, &count);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch for (i = 0; i < count; i++) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply_index(data_cmd, i,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch status, enh_code, "<%s> %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_address_encode(rcpts[i]->path), msg);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_transaction_write_trace_record(string_t *str,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_transaction *trans)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = trans->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_helo_data *helo_data = &conn->helo;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *host, *secstr, *rcpt_to = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (array_count(&trans->rcpt_to) == 1) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_recipient *const *rcpts =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_idx(&trans->rcpt_to, 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch rcpt_to = smtp_address_encode(rcpts[0]->path);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* from */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "Received: from ");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (helo_data->domain_valid)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, helo_data->domain);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "unknown");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch host = "";
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->remote_ip.family != 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch host = net_ip2addr(&conn->remote_ip);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (host[0] != '\0') {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, " ([");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, host);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "])");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* (using) */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch secstr = smtp_server_connection_get_security_string(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (secstr != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "\r\n\t(using ");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, secstr);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, ")");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* by, with */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "\r\n\tby ");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, conn->set.hostname);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, " with ");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, smtp_server_connection_get_protocol_name(conn));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* id */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "\r\n\tid ");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, trans->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* (envelope-from) */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "\r\n\t(envelope-from <");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_address_write(str, trans->mail_from);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, ">)");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* for */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (rcpt_to != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "\r\n\tfor <");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, rcpt_to);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, ">");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "; ");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* date */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, message_date_create(trans->timestamp.tv_sec));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_printfa(str, "\r\n");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}