bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "lib.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "llist.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "array.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-reply.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-server-private.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/*
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch * Command registry
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_register(struct smtp_server *server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *name, smtp_server_cmd_start_func_t *func,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch enum smtp_server_command_flags flags)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command_reg cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_zero(&cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd.name = name;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd.func = func;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd.flags = flags;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_append(&server->commands_reg, &cmd, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch server->commands_unsorted = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_unregister(struct smtp_server *server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *name)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_command_reg *cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int i, count;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = array_get(&server->commands_reg, &count);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch for (i = 0; i < count; i++) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (strcasecmp(cmd[i].name, name) == 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_delete(&server->commands_reg, i, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_panic("smtp-server: Trying to unregister unknown command '%s'", name);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic int
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_command_cmp(const struct smtp_server_command_reg *c1,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_command_reg *c2)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return strcasecmp(c1->name, c2->name);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic int
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_command_bsearch(const char *name,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_command_reg *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return strcasecmp(name, cmd->name);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic struct smtp_server_command_reg *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_command_find(struct smtp_server *server, const char *name)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (server->commands_unsorted) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_sort(&server->commands_reg, smtp_server_command_cmp);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch server->commands_unsorted = FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return array_bsearch(&server->commands_reg,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name, smtp_server_command_bsearch);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_commands_init(struct smtp_server *server)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch p_array_init(&server->commands_reg, server->pool, 16);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch switch (server->set.protocol) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_PROTOCOL_SMTP:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "EHLO", smtp_server_cmd_ehlo,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PRETLS |
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "HELO", smtp_server_cmd_helo,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_PROTOCOL_LMTP:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "LHLO", smtp_server_cmd_ehlo,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PRETLS |
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "AUTH", smtp_server_cmd_auth,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "STARTTLS", smtp_server_cmd_starttls,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PRETLS | SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "MAIL", smtp_server_cmd_mail, 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "RCPT", smtp_server_cmd_rcpt, 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "DATA", smtp_server_cmd_data, 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "BDAT", smtp_server_cmd_bdat, 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "RSET", smtp_server_cmd_rset,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "VRFY", smtp_server_cmd_vrfy, 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "NOOP", smtp_server_cmd_noop,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PRETLS | SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "QUIT", smtp_server_cmd_quit,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PRETLS | SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_register(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "XCLIENT", smtp_server_cmd_xclient,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_CMD_FLAG_PREAUTH);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/*
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch * Logging
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_debug(struct smtp_server_cmd_ctx *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *format, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_settings *set = &conn->set;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_list args;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->debug) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_start(args, format);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_debug("%s-server: conn %s: command %s: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_protocol_name(set->protocol),
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_label(conn),
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_label(cmd->cmd),
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch t_strdup_vprintf(format, args));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_end(args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/*
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_command *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_command_alloc(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool_t pool;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool = pool_alloconly_create("smtp_server_command", 256);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = p_new(pool, struct smtp_server_command, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.pool = pool;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.cmd = cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->refcount = 1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.conn = conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.server = conn->server;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->replies_expected = 1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch DLLIST2_APPEND(&conn->command_queue_head,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->command_queue_tail, cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->command_queue_count++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_command *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_command_new(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *name, const char *params)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server *server = conn->server;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_command_reg *cmd_reg;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = smtp_server_command_alloc(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.name = p_strdup(cmd->context.pool, name);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if ((cmd_reg=smtp_server_command_find(server, name)) == NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* RFC 5321, Section 4.2.4: Reply Code 502
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch Questions have been raised as to when reply code 502 (Command
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch not implemented) SHOULD be returned in preference to other
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch codes. 502 SHOULD be used when the command is actually
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch recognized by the SMTP server, but not implemented. If the
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command is not recognized, code 500 SHOULD be returned.
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_fail(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 500, "5.5.1", "Unknown command");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (!conn->ssl_secured && conn->set.tls_required &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch (cmd_reg->flags & SMTP_SERVER_CMD_FLAG_PRETLS) == 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* RFC 3207, Section 4:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch A SMTP server that is not publicly referenced may choose to
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch require that the client perform a TLS negotiation before
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch accepting any commands. In this case, the server SHOULD
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return the reply code:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 530 Must issue a STARTTLS command first
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch to every command other than NOOP, EHLO, STARTTLS, or QUIT. If
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch the client and server are using the ENHANCEDSTATUSCODES ESMTP
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch extension [RFC2034], the status code to be returned SHOULD be
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 5.7.0.
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_fail(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 530, "5.7.0", "TLS required.");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (!conn->authenticated && !conn->set.auth_optional &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch (cmd_reg->flags & SMTP_SERVER_CMD_FLAG_PREAUTH) == 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* RFC 4954, Section 6: Status Codes
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 530 5.7.0 Authentication required
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch This response SHOULD be returned by any command other than
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch AUTH, EHLO, HELO, NOOP, RSET, or QUIT when server policy
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch requires authentication in order to perform the requested
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch action and authentication is not currently in force.
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_fail(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 530, "5.7.0", "Authentication required.");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *tmp_cmd = cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(cmd_reg->func != NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_ref(tmp_cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch tmp_cmd->reg = cmd_reg;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd_reg->func(&tmp_cmd->context, params);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (tmp_cmd->state == SMTP_SERVER_COMMAND_STATE_NEW)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch tmp_cmd->state = SMTP_SERVER_COMMAND_STATE_PROCESSING;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_command_unref(&tmp_cmd))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_ref(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->refcount++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_command_unref(struct smtp_server_command **_cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd = *_cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->context.conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch *_cmd = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(cmd->refcount > 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (--cmd->refcount > 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_debug(&cmd->context, "Destroy");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->state < SMTP_SERVER_COMMAND_STATE_FINISHED) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->state = SMTP_SERVER_COMMAND_STATE_ABORTED;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch DLLIST2_REMOVE(&conn->command_queue_head,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->command_queue_tail, cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->command_queue_count--;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* execute hooks */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->context.hook_destroy != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.hook_destroy(&cmd->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->hook_destroy != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->hook_destroy(&cmd->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply_free(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool_unref(&cmd->context.pool);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_abort(struct smtp_server_command **_cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd = *_cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->context.conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* preemptively remove command from queue (references may still exist)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->state < SMTP_SERVER_COMMAND_STATE_FINISHED) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->state = SMTP_SERVER_COMMAND_STATE_ABORTED;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch DLLIST2_REMOVE(&conn->command_queue_head,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->command_queue_tail, cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->command_queue_count--;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply_free(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_unref(_cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_set_reply_count(struct smtp_server_command *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int count)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(count > 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(!array_is_created(&cmd->replies));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->replies_expected = count;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_ready_to_reply(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->state = SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_debug(&cmd->context, "Ready to reply");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_trigger_output(cmd->context.conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_next_to_reply(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->hook_next == NULL && cmd->context.hook_next == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_debug(&cmd->context, "Next to reply");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* execute private hook_next */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->hook_next != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_cmd_func_t *hook_next = cmd->hook_next;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->hook_next = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch hook_next(&cmd->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* execute public hook_next */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->context.hook_next != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_cmd_func_t *hook_next = cmd->context.hook_next;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.hook_next = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch hook_next(&cmd->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_command_replied(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->hook_replied == NULL && cmd->context.hook_replied == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->replies_submitted == cmd->replies_expected) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_debug(&cmd->context, "Replied");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* execute private hook_replied */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->hook_replied != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_cmd_func_t *hook_replied =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->hook_replied;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->hook_replied = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch hook_replied(&cmd->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* execute public hook_replied */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->context.hook_replied != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_cmd_func_t *hook_replied =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.hook_replied;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.hook_replied = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch hook_replied(&cmd->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_completed(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->hook_completed == NULL && cmd->context.hook_completed == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->replies_submitted == cmd->replies_expected) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_debug(&cmd->context, "Completed");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* execute private hook_completed */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->hook_completed != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_cmd_func_t *hook_completed =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->hook_completed;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->hook_completed = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch hook_completed(&cmd->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* execute public hook_completed */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->context.hook_completed != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_cmd_func_t *hook_completed =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.hook_completed;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.hook_completed = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch hook_completed(&cmd->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_submit_reply(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->context.conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int i, submitted;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch bool is_bad = FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(conn != NULL && array_is_created(&cmd->replies));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch submitted = 0;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch for (i = 0; i < cmd->replies_expected; i++) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_reply *reply =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_idx(&cmd->replies, i);
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch if (!reply->submitted)
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch continue;
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch submitted++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch i_assert(reply->content != NULL);
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch switch (reply->content->status) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case 500:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case 501:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case 503:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch is_bad = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(submitted == cmd->replies_submitted);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->hook_next = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->context.hook_next = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_replied(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* limit number of consecutive bad commands */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (is_bad)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->bad_counter++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else if (cmd->replies_submitted == cmd->replies_expected)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->bad_counter = 0;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* submit reply */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_ref(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch switch (cmd->state) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_NEW:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_PROCESSING:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_command_is_complete(cmd)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_debug(&cmd->context,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Not ready to reply");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->state = SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_ready_to_reply(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_ABORTED:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch default:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_unreached();
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_connection_unref(&conn))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn != NULL && conn->bad_counter > conn->set.max_bad_commands) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_terminate(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "4.7.0", "Too many invalid commands.");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_command_is_replied(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int i;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!array_is_created(&cmd->replies))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch for (i = 0; i < cmd->replies_expected; i++) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_reply *reply =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_idx(&cmd->replies, i);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!reply->submitted)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_reply *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_command_get_reply(struct smtp_server_command *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int idx)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_reply *reply;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!array_is_created(&cmd->replies))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reply = array_idx_modifiable(&cmd->replies, idx);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!reply->submitted)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return reply;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_command_reply_status_equals(struct smtp_server_command *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int status)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_reply *reply;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(cmd->replies_expected == 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reply = smtp_server_command_get_reply(cmd, 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch return (reply->content != NULL && reply->content->status == status);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_command_replied_success(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch bool success = FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int i;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!array_is_created(&cmd->replies))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch for (i = 0; i < cmd->replies_expected; i++) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_reply *reply =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_idx(&cmd->replies, i);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!reply->submitted)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch i_assert(reply->content != NULL);
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch if (reply->content->status / 100 == 2)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch success = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return success;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_finished(struct smtp_server_command *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->context.conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_reply *reply;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(cmd->state < SMTP_SERVER_COMMAND_STATE_FINISHED);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->state = SMTP_SERVER_COMMAND_STATE_FINISHED;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch DLLIST2_REMOVE(&conn->command_queue_head,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->command_queue_tail, cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->command_queue_count--;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->stats.reply_count++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(array_is_created(&cmd->replies));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reply = array_idx_modifiable(&cmd->replies, 0);
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch i_assert(reply->content != NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch if (reply->content->status == 221 || reply->content->status == 421) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(cmd->replies_expected == 1);
1d4c4128808d04cf4b8396ce04ce524da9194782Stephan Bosch if (reply->content->status == 421) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn, t_strdup_printf(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Server closed the connection: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply_get_one_line(reply)));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Client has quit the connection");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_unref(&cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (cmd->input_locked) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->input_captured)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_resume(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_unref(&cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_trigger_output(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_fail(struct smtp_server_command *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int status, const char *enh_code,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *fmt, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int i;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_list args;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(status / 100 > 2);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_start(args, fmt);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->replies_expected == 1) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply_indexv(&cmd->context, 0,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch status, enh_code, fmt, args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else for (i = 0; i < cmd->replies_expected; i++) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch bool sent = FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (array_is_created(&cmd->replies)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_reply *reply =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch array_idx(&cmd->replies, i);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch sent = reply->sent;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* send the same reply for all */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!sent) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_list args_copy;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch VA_COPY(args_copy, args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply_indexv(&cmd->context, i,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch status, enh_code, fmt, args_copy);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_end(args_copy);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_end(args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_input_lock(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->input_locked = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
e69ac57b1a97e56011e988564985728be31bfb2aStephan Boschvoid smtp_server_command_input_unlock(struct smtp_server_cmd_ctx *cmd)
e69ac57b1a97e56011e988564985728be31bfb2aStephan Bosch{
e69ac57b1a97e56011e988564985728be31bfb2aStephan Bosch struct smtp_server_command *command = cmd->cmd;
e69ac57b1a97e56011e988564985728be31bfb2aStephan Bosch struct smtp_server_connection *conn = cmd->conn;
e69ac57b1a97e56011e988564985728be31bfb2aStephan Bosch
e69ac57b1a97e56011e988564985728be31bfb2aStephan Bosch command->input_locked = FALSE;
e69ac57b1a97e56011e988564985728be31bfb2aStephan Bosch smtp_server_connection_input_resume(conn);
e69ac57b1a97e56011e988564985728be31bfb2aStephan Bosch}
e69ac57b1a97e56011e988564985728be31bfb2aStephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_command_input_capture(struct smtp_server_cmd_ctx *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_cmd_input_callback_t *callback)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_capture(conn, *callback, cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->input_locked = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->input_captured = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}