bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "login-common.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "ioloop.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "istream.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "ostream.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "base64.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "safe-memset.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "str.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "str-sanitize.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "strescape.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "dsasl-client.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "client.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "submission-login-settings.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "submission-proxy.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include <ctype.h>
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const char *submission_proxy_state_names[SUBMISSION_PROXY_STATE_COUNT] = {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "banner", "ehlo", "starttls", "tls-ehlo", "xclient", "authenticate"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch};
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void proxy_free_password(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->proxy_password == NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_free_and_null(client->proxy_password);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschproxy_send_xclient(struct submission_client *client, struct ostream *output)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *const *arg;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch string_t *str, *fwd;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if ((client->proxy_capability & SMTP_CAPABILITY_XCLIENT) == 0 ||
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->common.proxy_not_trusted)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* remote supports XCLIENT, send it */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch fwd = t_str_new(128);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch for(arg = client->common.auth_passdb_args; *arg != NULL; arg++) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (strncasecmp(*arg, "forward_", 8) == 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (str_len(fwd) > 0)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append_c(fwd, '\t');
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append_tabescaped(fwd, (*arg)+8);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str = t_str_new(128);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, "XCLIENT ");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (str_array_icase_find(client->proxy_xclient, "ADDR")) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, "ADDR=");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, net_ip2addr(&client->common.ip));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (str_array_icase_find(client->proxy_xclient, "PORT"))
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_printfa(str, "PORT=%u", client->common.remote_port);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (str_array_icase_find(client->proxy_xclient, "SESSION")) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, "SESSION=");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, client_get_session_id(&client->common));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (str_array_icase_find(client->proxy_xclient, "TTL"))
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_printfa(str, "TTL=%u", client->common.proxy_ttl - 1);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (str_array_icase_find(client->proxy_xclient, "FORWARD") &&
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_len(fwd) > 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, " FORWARD=");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch base64_encode(str_data(fwd), str_len(fwd), str);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, "\r\n");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch o_stream_nsend(output, str_data(str), str_len(str));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->proxy_state = SUBMISSION_PROXY_XCLIENT;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic int
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschproxy_send_login(struct submission_client *client, struct ostream *output)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct dsasl_client_settings sasl_set;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const unsigned char *sasl_output;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch size_t len;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *mech_name, *error;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch string_t *str;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if ((client->proxy_capability & SMTP_CAPABILITY_AUTH) == 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* Prevent sending credentials to a server that has login disabled;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i.e., due to the lack of TLS */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(&client->common, "proxy: "
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "Server has disabled authentication (TLS required?)");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_assert(client->common.proxy_ttl > 1);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch proxy_send_xclient(client, output);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str = t_str_new(128);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->common.proxy_mech == NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->common.proxy_mech = &dsasl_client_mech_plain;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_assert(client->common.proxy_sasl_client == NULL);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_zero(&sasl_set);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch sasl_set.authid = client->common.proxy_master_user != NULL ?
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->common.proxy_master_user : client->common.proxy_user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch sasl_set.authzid = client->common.proxy_user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch sasl_set.password = client->common.proxy_password;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->common.proxy_sasl_client =
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch dsasl_client_new(client->common.proxy_mech, &sasl_set);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mech_name = dsasl_client_mech_get_name(client->common.proxy_mech);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_printfa(str, "AUTH %s ", mech_name);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (dsasl_client_output(client->common.proxy_sasl_client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch &sasl_output, &len, &error) < 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(&client->common, t_strdup_printf(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: SASL mechanism %s init failed: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mech_name, error));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (len == 0)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append_c(str, '=');
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch else
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch base64_encode(sasl_output, len, str);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, "\r\n");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch o_stream_nsend(output, str_data(str), str_len(str));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch proxy_free_password(&client->common);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->proxy_state != SUBMISSION_PROXY_XCLIENT)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->proxy_state = SUBMISSION_PROXY_AUTHENTICATE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic int
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschsubmission_proxy_continue_sasl_auth(struct client *client, struct ostream *output,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *line)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch string_t *str;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const unsigned char *data;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch size_t data_len;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *error;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch int ret;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str = t_str_new(128);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (base64_decode(line, strlen(line), NULL, str) < 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: Server sent invalid base64 data in AUTH response");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ret = dsasl_client_input(client->proxy_sasl_client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_data(str), str_len(str), &error);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (ret == 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ret = dsasl_client_output(client->proxy_sasl_client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch &data, &data_len, &error);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (ret < 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(client, t_strdup_printf(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: Server sent invalid authentication data: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch error));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_assert(ret == 0);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_truncate(str, 0);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch base64_encode(data, data_len, str);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_append(str, "\r\n");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch o_stream_nsend(output, str_data(str), str_len(str));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const char *
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstrip_enhanced_code(const char *text, const char **enh_code_r)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *p = text;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch unsigned int digits;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch *enh_code_r = NULL;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (*p != '2' && *p != '4' && *p != '5')
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return text;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch p++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (*p != '.')
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return text;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch p++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch digits = 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch while (i_isdigit(*p) && digits < 3) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch p++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch digits++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (*p != '.')
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return text;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch p++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch digits = 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch while (i_isdigit(*p) && digits < 3) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch p++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch digits++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (*p != ' ')
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return text;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch *enh_code_r = t_strdup_until(text, p);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch p++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return p;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschsubmission_proxy_success_reply_sent(struct smtp_server_cmd_ctx *cmd)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
0afd9a9acab584e770ffcd6a0e1e02e2d18d360aJosef 'Jeff' Sipek struct submission_client *subm_client = cmd->context;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_finish_destroy_client(&subm_client->common);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschint submission_proxy_parse_line(struct client *client, const char *line)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct submission_client *subm_client =
c4588e66e80482994cf0fbc45251cb8e9db6404dJosef 'Jeff' Sipek container_of(client, struct submission_client, common);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_cmd_ctx *cmd = subm_client->pending_auth;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_command *command = cmd->cmd;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct ostream *output;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch enum login_proxy_ssl_flags ssl_flags;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch bool last_line = FALSE, invalid_line = FALSE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *text = NULL, *enh_code = NULL;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch unsigned int status = 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_assert(!client->destroyed);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_assert(cmd != NULL);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if ((line[3] != ' ' && line[3] != '-') ||
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_parse_uint(line, &status, &text) < 0 ||
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch status < 200 || status >= 560) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch invalid_line = TRUE;
4a1af46c8ed806fbc51bedfaf79c019b0afa3aa6Stephan Bosch } else {
4a1af46c8ed806fbc51bedfaf79c019b0afa3aa6Stephan Bosch text++;
a46221f25bbaf310f73f77bec24f2d3f0c80d4feStephan Bosch
a46221f25bbaf310f73f77bec24f2d3f0c80d4feStephan Bosch if ((subm_client->proxy_capability &
a46221f25bbaf310f73f77bec24f2d3f0c80d4feStephan Bosch SMTP_CAPABILITY_ENHANCEDSTATUSCODES) != 0)
a46221f25bbaf310f73f77bec24f2d3f0c80d4feStephan Bosch text = strip_enhanced_code(text, &enh_code);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (subm_client->proxy_reply_status != 0 &&
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_reply_status != status) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(client, t_strdup_printf(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: Remote returned inconsistent SMTP reply: %s "
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "(status != %u)", str_sanitize(line, 160),
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_reply_status));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (line[3] == ' ') {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch last_line = TRUE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_reply_status = 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch } else {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_reply_status = status;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch output = login_proxy_get_ostream(client->login_proxy);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch switch (subm_client->proxy_state) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch case SUBMISSION_PROXY_BANNER:
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* this is a banner */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (invalid_line || status != 220) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(client, t_strdup_printf(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: Remote returned invalid banner: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_sanitize(line, 160)));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (!last_line)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_state = SUBMISSION_PROXY_EHLO;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch o_stream_nsend_str(output, t_strdup_printf("EHLO %s\r\n",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->set->hostname));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch case SUBMISSION_PROXY_EHLO:
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch case SUBMISSION_PROXY_TLS_EHLO:
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (invalid_line || (status / 100) != 2) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(client, t_strdup_printf(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: Remote returned invalid EHLO line: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_sanitize(line, 160)));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (strncasecmp(text, "XCLIENT ", 8) == 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_capability |=
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_XCLIENT;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_free_and_null(subm_client->proxy_xclient);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_xclient = p_strarray_dup(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch default_pool, t_strsplit_spaces(text + 8, " "));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch } else if (strncasecmp(text, "STARTTLS", 9) == 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_capability |=
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_STARTTLS;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch } else if (strncasecmp(text, "AUTH", 4) == 0 &&
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch text[4] == ' ' && text[5] != '\0') {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_capability |=
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_AUTH;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch } else if (strcasecmp(text, "ENHANCEDSTATUSCODES") == 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_capability |=
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_ENHANCEDSTATUSCODES;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (!last_line)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (subm_client->proxy_state == SUBMISSION_PROXY_TLS_EHLO) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (proxy_send_login(subm_client, output) < 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (proxy_send_login(subm_client, output) < 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch } else {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if ((subm_client->proxy_capability &
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_STARTTLS) == 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: Remote doesn't support STARTTLS");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch o_stream_nsend_str(output, "STARTTLS\r\n");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_state = SUBMISSION_PROXY_STARTTLS;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch case SUBMISSION_PROXY_STARTTLS:
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (invalid_line || status != 220) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(client, t_strdup_printf(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: Remote STARTTLS failed: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_sanitize(line, 160)));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (!last_line)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (login_proxy_starttls(client->login_proxy) < 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* i/ostreams changed. */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch output = login_proxy_get_ostream(client->login_proxy);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_capability = 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_free_and_null(subm_client->proxy_xclient);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_state = SUBMISSION_PROXY_TLS_EHLO;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch o_stream_nsend_str(output, t_strdup_printf("EHLO %s\r\n",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->set->hostname));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch case SUBMISSION_PROXY_XCLIENT:
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (invalid_line || (status / 100) != 2) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_log_err(client, t_strdup_printf(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "proxy: Remote XCLIENT failed: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str_sanitize(line, 160)));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (!last_line)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_state = SUBMISSION_PROXY_AUTHENTICATE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch case SUBMISSION_PROXY_AUTHENTICATE:
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (invalid_line)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch break;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (status == 334 && client->proxy_sasl_client != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* continue SASL authentication */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (submission_proxy_continue_sasl_auth(client, output,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch text) < 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (subm_client->proxy_reply == NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_reply =
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_reply_create(command, status, enh_code);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_reply_add_text(subm_client->proxy_reply, text);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (!last_line)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if ((status / 100) != 2)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch break;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_input_lock(cmd->conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch cmd->context = subm_client;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch cmd->hook_destroy = submission_proxy_success_reply_sent;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->pending_auth = NULL;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* Login successful. Send this reply to client. */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_reply_submit(subm_client->proxy_reply);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return 1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch case SUBMISSION_PROXY_STATE_COUNT:
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_unreached();
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* Login failed. Pass through the error message to client.
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch If the backend server isn't Dovecot, the error message may
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch be different from Dovecot's "user doesn't exist" error. This
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch would allow an attacker to find out what users exist in the
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch system.
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch The optimal way to handle this would be to replace the
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch backend's "password failed" error message with Dovecot's
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch AUTH_FAILED_MSG, but this would require a new setting and
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch the sysadmin to actually bother setting it properly.
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch So for now we'll just forward the error message. This
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch shouldn't be a real problem since of course everyone will
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch be using only Dovecot as their backend :) */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if ((status / 100) == 2) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch submission_proxy_error(client, AUTH_FAILED_MSG);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch } else {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_assert(subm_client->proxy_reply != NULL);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_reply_submit(subm_client->proxy_reply);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->pending_auth = NULL;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->set->auth_verbose) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_log_failure(client, text);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->proxy_auth_failed = TRUE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_failed(client, FALSE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return -1;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschvoid submission_proxy_reset(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct submission_client *subm_client =
c4588e66e80482994cf0fbc45251cb8e9db6404dJosef 'Jeff' Sipek container_of(client, struct submission_client, common);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_state = SUBMISSION_PROXY_BANNER;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_capability = 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_free_and_null(subm_client->proxy_xclient);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_reply_status = 0;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->proxy_reply = NULL;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschvoid submission_proxy_error(struct client *client, const char *text)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct submission_client *subm_client =
c4588e66e80482994cf0fbc45251cb8e9db6404dJosef 'Jeff' Sipek container_of(client, struct submission_client, common);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_cmd_ctx *cmd = subm_client->pending_auth;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (cmd != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch subm_client->pending_auth = NULL;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_reply(cmd, 535, "5.7.8", "%s", text);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschconst char *submission_proxy_get_state(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct submission_client *subm_client =
c4588e66e80482994cf0fbc45251cb8e9db6404dJosef 'Jeff' Sipek container_of(client, struct submission_client, common);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_assert(subm_client->proxy_state < SUBMISSION_PROXY_STATE_COUNT);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return submission_proxy_state_names[subm_client->proxy_state];
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}