bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "lib.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "str.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "array.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-parser.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-address.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-reply.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-syntax.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-server-private.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/* RCPT command */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic bool
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschcmd_rcpt_check_state(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch struct smtp_server_transaction *trans = conn->state.trans;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch if (conn->state.pending_mail_cmds == 0 && trans == NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (command->hook_replied != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->state.pending_rcpt_cmds--;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->hook_replied = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 503, "5.5.0", "MAIL needed first");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch if (conn->set.max_recipients > 0 && trans != NULL &&
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch smtp_server_transaction_rcpt_count(trans) >=
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch conn->set.max_recipients) {
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch smtp_server_reply(cmd,
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch 451, "4.5.3", "Too many recipients");
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch return FALSE;
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void cmd_rcpt_completed(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_cmd_rcpt *data =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch (struct smtp_server_cmd_rcpt *)command->data;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_transaction *trans = conn->state.trans;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_recipient *rcpt;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->state.pending_rcpt_cmds--;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(smtp_server_command_is_replied(command));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_command_replied_success(command))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* success */
5d5ad796fc34170333bb52c05614425a0dd7e182Stephan Bosch rcpt = smtp_server_transaction_add_rcpt(trans, data->path,
5d5ad796fc34170333bb52c05614425a0dd7e182Stephan Bosch &data->params);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch rcpt->context = data->trans_context;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (data->hook_finished != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch data->hook_finished(cmd, trans, rcpt,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_count(&trans->rcpt_to) - 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch data->hook_finished = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void cmd_rcpt_replied(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(smtp_server_command_is_replied(command));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_command_replied_success(command)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* failure; substitute our own error if predictable */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch (void)cmd_rcpt_check_state(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void cmd_rcpt_recheck(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(conn->state.pending_mail_cmds == 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* all preceeding commands have finished and now the transaction state
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch is clear. This provides the opportunity to re-check the transaction
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch state and abort the pending proxied mail command if it is bound to
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch fail */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!cmd_rcpt_check_state(cmd))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* Advance state */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_RCPT_TO);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_cmd_rcpt(struct smtp_server_cmd_ctx *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *params)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_settings *set = &conn->set;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch enum smtp_capability caps = set->capabilities;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_callbacks *callbacks = conn->callbacks;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_cmd_rcpt *rcpt_data;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_address *path;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch enum smtp_param_parse_error pperror;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *error;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* rcpt = "RCPT TO:" ( "<Postmaster@" Domain ">" /
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "<Postmaster>" / Forward-path ) [SP Rcpt-parameters] CRLF
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch Forward-path = Path
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* check transaction state as far as possible */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!cmd_rcpt_check_state(cmd))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* ( "<Postmaster@" Domain ">" / "<Postmaster>" / Forward-path ) */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (params == NULL || strncasecmp(params, "TO:", 3) != 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 501, "5.5.4", "Invalid parameters");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (smtp_address_parse_path_full(pool_datastack_create(), params + 3,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &path, &error, &params) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 501, "5.5.4", "Invalid TO: %s", error);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (*params == ' ')
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch params++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else if (*params != '\0') {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd, 501, "5.5.4",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Invalid TO: Invalid character in path");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (path->domain == NULL && !conn->set.rcpt_domain_optional &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch strcasecmp(path->localpart, "postmaster") != 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 501, "5.5.4", "Invalid TO: Missing domain");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch rcpt_data = p_new(cmd->pool, struct smtp_server_cmd_rcpt, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* [SP Rcpt-parameters] */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (smtp_params_rcpt_parse(cmd->pool, params, caps,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->param_extensions, &rcpt_data->params,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &pperror, &error) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch switch (pperror) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_PARAM_PARSE_ERROR_BAD_SYNTAX:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 501, "5.5.4", "%s", error);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_PARAM_PARSE_ERROR_NOT_SUPPORTED:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 555, "5.5.4", "%s", error);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch default:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_unreached();
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch rcpt_data->path = smtp_address_clone(cmd->pool, path);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->data = rcpt_data;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->hook_next = cmd_rcpt_recheck;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->hook_replied = cmd_rcpt_replied;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->hook_completed = cmd_rcpt_completed;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->state.pending_rcpt_cmds++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_ref(command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(callbacks != NULL && callbacks->conn_cmd_rcpt != NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if ((ret=callbacks->conn_cmd_rcpt(conn->context,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd, rcpt_data)) <= 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(ret == 0 || smtp_server_command_is_replied(command));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* command is waiting for external event or it failed */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_unref(&command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_command_is_replied(command)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* set generic RCPT success reply if none is provided */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 250, "2.1.5", "OK");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_unref(&command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}