diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-smtp/smtp-server-cmd-helo.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/src/lib-smtp/smtp-server-cmd-helo.c b/src/lib-smtp/smtp-server-cmd-helo.c new file mode 100644 index 0000000..2f03ceb --- /dev/null +++ b/src/lib-smtp/smtp-server-cmd-helo.c @@ -0,0 +1,196 @@ +/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "array.h" +#include "smtp-syntax.h" + +#include "smtp-server-private.h" + +/* EHLO, HELO commands */ + +static void +cmd_helo_completed(struct smtp_server_cmd_ctx *cmd, + struct smtp_server_cmd_helo *data) +{ + struct smtp_server_connection *conn = cmd->conn; + struct smtp_server_command *command = cmd->cmd; + + i_assert(smtp_server_command_is_replied(command)); + if (!smtp_server_command_replied_success(command)) { + /* Failure */ + return; + } + + if (conn->pending_helo == &data->helo) + conn->pending_helo = NULL; + + /* Success */ + smtp_server_connection_reset_state(conn); + + i_free(conn->helo_domain); + conn->helo_domain = i_strdup(data->helo.domain); + conn->helo.domain = conn->helo_domain; + conn->helo.domain_valid = data->helo.domain_valid; + conn->helo.old_smtp = data->helo.old_smtp; +} + +static void +cmd_helo_next(struct smtp_server_cmd_ctx *cmd, + struct smtp_server_cmd_helo *data) +{ + struct smtp_server_connection *conn = cmd->conn; + + if (null_strcmp(conn->helo.domain, data->helo.domain) != 0 || + conn->helo.old_smtp != data->helo.old_smtp) + data->changed = TRUE; /* Definitive assessment */ +} + +static void +smtp_server_cmd_helo_run(struct smtp_server_cmd_ctx *cmd, const char *params, + bool old_smtp) +{ + struct smtp_server_connection *conn = cmd->conn; + const struct smtp_server_callbacks *callbacks = conn->callbacks; + struct smtp_server_cmd_helo *helo_data; + struct smtp_server_command *command = cmd->cmd; + bool first = (conn->pending_helo == NULL && conn->helo.domain == NULL); + const char *domain = NULL; + int ret; + + /* Parse domain argument */ + + if (*params == '\0') { + smtp_server_reply(cmd, 501, "", "Missing hostname"); + return; + } + ret = smtp_helo_domain_parse(params, !old_smtp, &domain); + + smtp_server_command_pipeline_block(cmd); + if (conn->state.state == SMTP_SERVER_STATE_GREETING) { + smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_HELO, + NULL); + } + + helo_data = p_new(cmd->pool, struct smtp_server_cmd_helo, 1); + helo_data->helo.domain = p_strdup(cmd->pool, domain); + helo_data->helo.domain_valid = ( ret >= 0 ); + helo_data->helo.old_smtp = old_smtp; + helo_data->first = first; + command->data = helo_data; + + if (null_strcmp(conn->helo.domain, domain) != 0 || + conn->helo.old_smtp != old_smtp) + helo_data->changed = TRUE; /* Preliminary assessment */ + + if (conn->pending_helo == NULL) + conn->pending_helo = &helo_data->helo; + + smtp_server_command_add_hook( + command, SMTP_SERVER_COMMAND_HOOK_NEXT, + cmd_helo_next, helo_data); + smtp_server_command_add_hook( + command, SMTP_SERVER_COMMAND_HOOK_COMPLETED, + cmd_helo_completed, helo_data); + + smtp_server_command_ref(command); + if (callbacks != NULL && callbacks->conn_cmd_helo != NULL) { + /* Specific implementation of EHLO command */ + ret = callbacks->conn_cmd_helo(conn->context, cmd, helo_data); + if (ret <= 0) { + i_assert(ret == 0 || + smtp_server_command_is_replied(command)); + /* Command is waiting for external event or it failed */ + smtp_server_command_unref(&command); + return; + } + } + + if (!smtp_server_command_is_replied(command)) { + /* Submit default EHLO reply if none is provided */ + smtp_server_cmd_ehlo_reply_default(cmd); + } + smtp_server_command_unref(&command); +} + +void smtp_server_cmd_ehlo(struct smtp_server_cmd_ctx *cmd, const char *params) +{ + /* ehlo = "EHLO" SP ( Domain / address-literal ) CRLF */ + + smtp_server_cmd_helo_run(cmd, params, FALSE); +} + +void smtp_server_cmd_helo(struct smtp_server_cmd_ctx *cmd, const char *params) +{ + /* helo = "HELO" SP Domain CRLF */ + + smtp_server_cmd_helo_run(cmd, params, TRUE); +} + +struct smtp_server_reply * +smtp_server_cmd_ehlo_reply_create(struct smtp_server_cmd_ctx *cmd) +{ + static struct { + const char *name; + void (*add)(struct smtp_server_reply *reply); + } standard_caps[] = { + /* Sorted alphabetically */ + { "8BITMIME", smtp_server_reply_ehlo_add_8bitmime }, + { "BINARYMIME", smtp_server_reply_ehlo_add_binarymime }, + { "CHUNKING", smtp_server_reply_ehlo_add_chunking }, + { "DSN", smtp_server_reply_ehlo_add_dsn }, + { "ENHANCEDSTATUSCODES", + smtp_server_reply_ehlo_add_enhancedstatuscodes }, + { "PIPELINING", smtp_server_reply_ehlo_add_pipelining }, + { "SIZE", smtp_server_reply_ehlo_add_size }, + { "STARTTLS", smtp_server_reply_ehlo_add_starttls }, + { "VRFY", smtp_server_reply_ehlo_add_vrfy }, + { "XCLIENT", smtp_server_reply_ehlo_add_xclient } + }; + const unsigned int standard_caps_count = N_ELEMENTS(standard_caps); + struct smtp_server_connection *conn = cmd->conn; + struct smtp_server_command *command = cmd->cmd; + struct smtp_server_cmd_helo *helo_data = command->data; + const struct smtp_capability_extra *extra_caps = NULL; + unsigned int extra_caps_count, i, j; + struct smtp_server_reply *reply; + + reply = smtp_server_reply_create_ehlo(cmd->cmd); + + if (helo_data->helo.old_smtp) { + i_assert(cmd->cmd->reg->func == smtp_server_cmd_helo); + return reply; + } + i_assert(cmd->cmd->reg->func == smtp_server_cmd_ehlo); + + extra_caps_count = 0; + if (array_is_created(&conn->extra_capabilities)) { + extra_caps = array_get(&conn->extra_capabilities, + &extra_caps_count); + } + + i = j = 0; + while (i < standard_caps_count || j < extra_caps_count) { + if (i < standard_caps_count && + (j >= extra_caps_count || + strcasecmp(standard_caps[i].name, + extra_caps[j].name) < 0)) { + standard_caps[i].add(reply); + i++; + } else { + smtp_server_reply_ehlo_add_params( + reply, extra_caps[j].name, + extra_caps[j].params); + j++; + } + } + return reply; +} + +void smtp_server_cmd_ehlo_reply_default(struct smtp_server_cmd_ctx *cmd) +{ + struct smtp_server_reply *reply; + + reply = smtp_server_cmd_ehlo_reply_create(cmd); + smtp_server_reply_submit(reply); +} |