"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/submission-login/submission-proxy.c" between
dovecot-2.3.16.tar.gz and dovecot-2.3.17.tar.gz

About: Dovecot is an IMAP and POP3 server, written with security primarily in mind.

submission-proxy.c  (dovecot-2.3.16):submission-proxy.c  (dovecot-2.3.17)
skipping to change at line 21 skipping to change at line 21
#include "strescape.h" #include "strescape.h"
#include "dsasl-client.h" #include "dsasl-client.h"
#include "client.h" #include "client.h"
#include "smtp-syntax.h" #include "smtp-syntax.h"
#include "submission-login-settings.h" #include "submission-login-settings.h"
#include "submission-proxy.h" #include "submission-proxy.h"
#include <ctype.h> #include <ctype.h>
static const char *submission_proxy_state_names[SUBMISSION_PROXY_STATE_COUNT] = { static const char *submission_proxy_state_names[SUBMISSION_PROXY_STATE_COUNT] = {
"banner", "ehlo", "starttls", "tls-ehlo", "xclient", "authenticate" "banner", "ehlo", "starttls", "tls-ehlo", "xclient", "xclient-ehlo", "aut henticate"
}; };
static void
submission_proxy_success_reply_sent(
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct submission_client *subm_client)
{
client_proxy_finish_destroy_client(&subm_client->common);
}
static int
proxy_send_starttls(struct submission_client *client, struct ostream *output)
{
enum login_proxy_ssl_flags ssl_flags;
ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy);
if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0)
return 0;
if ((client->proxy_capability & SMTP_CAPABILITY_STARTTLS) == 0) {
login_proxy_failed(
client->common.login_proxy,
login_proxy_get_event(client->common.login_proxy),
LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG,
"STARTTLS not supported");
return -1;
}
o_stream_nsend_str(output, "STARTTLS\r\n");
client->proxy_state = SUBMISSION_PROXY_STARTTLS;
return 1;
}
static buffer_t * static buffer_t *
proxy_compose_xclient_forward(struct submission_client *client) proxy_compose_xclient_forward(struct submission_client *client)
{ {
const char *const *arg; const char *const *arg;
string_t *str; string_t *str;
if (*client->common.auth_passdb_args == NULL) if (*client->common.auth_passdb_args == NULL)
return NULL; return NULL;
str = t_str_new(128); str = t_str_new(128);
for (arg = client->common.auth_passdb_args; *arg != NULL; arg++) { for (arg = client->common.auth_passdb_args; *arg != NULL; arg++) {
if (strncasecmp(*arg, "forward_", 8) == 0) { if (strncasecmp(*arg, "forward_", 8) == 0) {
if (str_len(str) > 0) if (str_len(str) > 0)
str_append_c(str, '\t'); str_append_c(str, '\t');
str_append_tabescaped(str, (*arg)+8); str_append_tabescaped(str, (*arg)+8);
} }
} }
if (str_len(str) == 0)
return NULL;
return t_base64_encode(0, 0, str_data(str), str_len(str)); return t_base64_encode(0, 0, str_data(str), str_len(str));
} }
static void static void
proxy_send_xclient_more_data(struct submission_client *client,
struct ostream *output, string_t *buf,
const char *field, const unsigned char *value,
size_t value_size)
{
const size_t cmd_len = strlen("XCLIENT");
size_t prev_len = str_len(buf);
str_append_c(buf, ' ');
str_append(buf, field);
str_append_c(buf, '=');
smtp_xtext_encode(buf, value, value_size);
if (str_len(buf) > 512) {
if (prev_len <= cmd_len)
prev_len = str_len(buf);
o_stream_nsend(output, str_data(buf), prev_len);
o_stream_nsend(output, "\r\n", 2);
client->proxy_xclient_replies_expected++;
str_delete(buf, cmd_len, prev_len - cmd_len);
}
}
static void
proxy_send_xclient_more(struct submission_client *client,
struct ostream *output, string_t *buf,
const char *field, const char *value)
{
proxy_send_xclient_more_data(client, output, buf, field,
(const unsigned char *)value,
strlen(value));
}
static int
proxy_send_xclient(struct submission_client *client, struct ostream *output) proxy_send_xclient(struct submission_client *client, struct ostream *output)
{ {
string_t *str; string_t *str;
if ((client->proxy_capability & SMTP_CAPABILITY_XCLIENT) == 0 || if ((client->proxy_capability & SMTP_CAPABILITY_XCLIENT) == 0 ||
client->common.proxy_not_trusted) client->common.proxy_not_trusted)
return; return 0;
struct smtp_proxy_data proxy_data;
smtp_server_connection_get_proxy_data(client->conn, &proxy_data);
i_assert(client->common.proxy_ttl > 1);
/* remote supports XCLIENT, send it */ /* remote supports XCLIENT, send it */
client->proxy_xclient_replies_expected = 0;
str = t_str_new(128); str = t_str_new(128);
str_append(str, "XCLIENT"); str_append(str, "XCLIENT");
if (str_array_icase_find(client->proxy_xclient, "HELO")) {
if (proxy_data.helo != NULL) {
proxy_send_xclient_more(client, output, str, "HELO",
proxy_data.helo);
} else {
proxy_send_xclient_more(client, output, str, "HELO",
"[UNAVAILABLE]");
}
}
if (str_array_icase_find(client->proxy_xclient, "PROTO")) {
const char *proto = "[UNAVAILABLE]";
switch (proxy_data.proto) {
case SMTP_PROXY_PROTOCOL_UNKNOWN:
break;
case SMTP_PROXY_PROTOCOL_SMTP:
proto = "SMTP";
break;
case SMTP_PROXY_PROTOCOL_ESMTP:
proto = "ESMTP";
break;
case SMTP_PROXY_PROTOCOL_LMTP:
proto = "LMTP";
break;
}
proxy_send_xclient_more(client, output, str, "PROTO", proto);
}
if (client->common.proxy_noauth &&
str_array_icase_find(client->proxy_xclient, "LOGIN")) {
if (proxy_data.login != NULL) {
proxy_send_xclient_more(client, output, str, "LOGIN",
proxy_data.login);
} else if (client->common.virtual_user != NULL) {
proxy_send_xclient_more(client, output, str, "LOGIN",
client->common.virtual_user);
} else {
proxy_send_xclient_more(client, output, str, "LOGIN",
"[UNAVAILABLE]");
}
}
if (str_array_icase_find(client->proxy_xclient, "TTL")) {
proxy_send_xclient_more(
client, output, str, "TTL",
t_strdup_printf("%u",client->common.proxy_ttl - 1));
}
if (str_array_icase_find(client->proxy_xclient, "PORT")) {
proxy_send_xclient_more(
client, output, str, "PORT",
t_strdup_printf("%u", client->common.remote_port));
}
if (str_array_icase_find(client->proxy_xclient, "ADDR")) { if (str_array_icase_find(client->proxy_xclient, "ADDR")) {
str_append(str, " ADDR="); proxy_send_xclient_more(client, output, str, "ADDR",
str_append(str, net_ip2addr(&client->common.ip)); net_ip2addr(&client->common.ip));
} }
if (str_array_icase_find(client->proxy_xclient, "PORT"))
str_printfa(str, " PORT=%u", client->common.remote_port);
if (str_array_icase_find(client->proxy_xclient, "SESSION")) { if (str_array_icase_find(client->proxy_xclient, "SESSION")) {
str_append(str, " SESSION="); proxy_send_xclient_more(client, output, str, "SESSION",
smtp_xtext_encode_cstr( client_get_session_id(&client->common));
str, client_get_session_id(&client->common));
} }
if (str_array_icase_find(client->proxy_xclient, "TTL"))
str_printfa(str, " TTL=%u", client->common.proxy_ttl - 1);
if (str_array_icase_find(client->proxy_xclient, "FORWARD")) { if (str_array_icase_find(client->proxy_xclient, "FORWARD")) {
buffer_t *fwd = proxy_compose_xclient_forward(client); buffer_t *fwd = proxy_compose_xclient_forward(client);
if (fwd != NULL) { if (fwd != NULL) {
str_append(str, " FORWARD="); proxy_send_xclient_more_data(
smtp_xtext_encode(str, fwd->data, fwd->used); client, output, str, "FORWARD",
fwd->data, fwd->used);
} }
} }
str_append(str, "\r\n"); str_append(str, "\r\n");
o_stream_nsend(output, str_data(str), str_len(str)); o_stream_nsend(output, str_data(str), str_len(str));
client->proxy_state = SUBMISSION_PROXY_XCLIENT; client->proxy_state = SUBMISSION_PROXY_XCLIENT;
client->proxy_xclient_replies_expected++;
return 1;
} }
static int static int
proxy_send_login(struct submission_client *client, struct ostream *output) proxy_send_login(struct submission_client *client, struct ostream *output)
{ {
struct dsasl_client_settings sasl_set; struct dsasl_client_settings sasl_set;
const unsigned char *sasl_output; const unsigned char *sasl_output;
size_t len; size_t len;
const char *mech_name, *error; const char *mech_name, *error;
string_t *str; string_t *str;
skipping to change at line 102 skipping to change at line 222
if ((client->proxy_capability & SMTP_CAPABILITY_AUTH) == 0) { if ((client->proxy_capability & SMTP_CAPABILITY_AUTH) == 0) {
/* Prevent sending credentials to a server that has login /* Prevent sending credentials to a server that has login
disabled; i.e., due to the lack of TLS */ disabled; i.e., due to the lack of TLS */
login_proxy_failed(client->common.login_proxy, login_proxy_failed(client->common.login_proxy,
login_proxy_get_event(client->common.login_proxy), login_proxy_get_event(client->common.login_proxy),
LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG, LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG,
"Authentication support not advertised (TLS required?)"); "Authentication support not advertised (TLS required?)");
return -1; return -1;
} }
i_assert(client->common.proxy_ttl > 1);
proxy_send_xclient(client, output);
str = t_str_new(128); str = t_str_new(128);
if (client->common.proxy_mech == NULL) if (client->common.proxy_mech == NULL)
client->common.proxy_mech = &dsasl_client_mech_plain; client->common.proxy_mech = &dsasl_client_mech_plain;
i_assert(client->common.proxy_sasl_client == NULL); i_assert(client->common.proxy_sasl_client == NULL);
i_zero(&sasl_set); i_zero(&sasl_set);
sasl_set.authid = client->common.proxy_master_user != NULL ? sasl_set.authid = client->common.proxy_master_user != NULL ?
client->common.proxy_master_user : client->common.proxy_user; client->common.proxy_master_user : client->common.proxy_user;
sasl_set.authzid = client->common.proxy_user; sasl_set.authzid = client->common.proxy_user;
skipping to change at line 138 skipping to change at line 255
LOGIN_PROXY_FAILURE_TYPE_INTERNAL, reason); LOGIN_PROXY_FAILURE_TYPE_INTERNAL, reason);
return -1; return -1;
} }
if (len == 0) if (len == 0)
str_append_c(str, '='); str_append_c(str, '=');
else else
base64_encode(sasl_output, len, str); base64_encode(sasl_output, len, str);
str_append(str, "\r\n"); str_append(str, "\r\n");
o_stream_nsend(output, str_data(str), str_len(str)); o_stream_nsend(output, str_data(str), str_len(str));
if (client->proxy_state != SUBMISSION_PROXY_XCLIENT) client->proxy_state = SUBMISSION_PROXY_AUTHENTICATE;
client->proxy_state = SUBMISSION_PROXY_AUTHENTICATE;
return 0; return 0;
} }
static int static int
proxy_handle_ehlo_reply(struct submission_client *client,
struct ostream *output)
{
struct smtp_server_cmd_ctx *cmd = client->pending_auth;
int ret;
switch (client->proxy_state) {
case SUBMISSION_PROXY_EHLO:
ret = proxy_send_starttls(client, output);
if (ret < 0)
return -1;
if (ret != 0)
return 0;
/* Fall through */
case SUBMISSION_PROXY_TLS_EHLO:
ret = proxy_send_xclient(client, output);
if (ret < 0)
return -1;
if (ret != 0) {
client->proxy_capability = 0;
i_free_and_null(client->proxy_xclient);
o_stream_nsend_str(output, t_strdup_printf(
"EHLO %s\r\n",
client->set->hostname));
return 0;
}
break;
case SUBMISSION_PROXY_XCLIENT_EHLO:
break;
default:
i_unreached();
}
if (client->common.proxy_noauth) {
smtp_server_connection_input_lock(cmd->conn);
smtp_server_command_add_hook(
cmd->cmd, SMTP_SERVER_COMMAND_HOOK_DESTROY,
submission_proxy_success_reply_sent, client);
client->pending_auth = NULL;
smtp_server_reply(cmd, 235, "2.7.0", "Logged in.");
return 1;
}
return proxy_send_login(client, output);
}
static int
submission_proxy_continue_sasl_auth(struct client *client, struct ostream *outpu t, submission_proxy_continue_sasl_auth(struct client *client, struct ostream *outpu t,
const char *line) const char *line)
{ {
string_t *str; string_t *str;
const unsigned char *data; const unsigned char *data;
size_t data_len; size_t data_len;
const char *error; const char *error;
int ret; int ret;
str = t_str_new(128); str = t_str_new(128);
skipping to change at line 221 skipping to change at line 386
p++; p++;
digits++; digits++;
} }
if (*p != ' ') if (*p != ' ')
return text; return text;
*enh_code_r = t_strdup_until(text, p); *enh_code_r = t_strdup_until(text, p);
p++; p++;
return p; return p;
} }
static void
submission_proxy_success_reply_sent(
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct submission_client *subm_client)
{
client_proxy_finish_destroy_client(&subm_client->common);
}
int submission_proxy_parse_line(struct client *client, const char *line) int submission_proxy_parse_line(struct client *client, const char *line)
{ {
struct submission_client *subm_client = struct submission_client *subm_client =
container_of(client, struct submission_client, common); container_of(client, struct submission_client, common);
struct smtp_server_cmd_ctx *cmd = subm_client->pending_auth; struct smtp_server_cmd_ctx *cmd = subm_client->pending_auth;
struct smtp_server_command *command = cmd->cmd; struct smtp_server_command *command = cmd->cmd;
struct ostream *output; struct ostream *output;
enum login_proxy_ssl_flags ssl_flags;
bool last_line = FALSE, invalid_line = FALSE; bool last_line = FALSE, invalid_line = FALSE;
const char *text = NULL, *enh_code = NULL; const char *text = NULL, *enh_code = NULL;
unsigned int status = 0; unsigned int status = 0;
i_assert(!client->destroyed); i_assert(!client->destroyed);
i_assert(cmd != NULL); i_assert(cmd != NULL);
if ((line[3] != ' ' && line[3] != '-') || if ((line[3] != ' ' && line[3] != '-') ||
str_parse_uint(line, &status, &text) < 0 || str_parse_uint(line, &status, &text) < 0 ||
status < 200 || status >= 560) { status < 200 || status >= 560) {
skipping to change at line 294 skipping to change at line 450
} }
if (!last_line) if (!last_line)
return 0; return 0;
subm_client->proxy_state = SUBMISSION_PROXY_EHLO; subm_client->proxy_state = SUBMISSION_PROXY_EHLO;
o_stream_nsend_str(output, t_strdup_printf("EHLO %s\r\n", o_stream_nsend_str(output, t_strdup_printf("EHLO %s\r\n",
subm_client->set->hostname)); subm_client->set->hostname));
return 0; return 0;
case SUBMISSION_PROXY_EHLO: case SUBMISSION_PROXY_EHLO:
case SUBMISSION_PROXY_TLS_EHLO: case SUBMISSION_PROXY_TLS_EHLO:
case SUBMISSION_PROXY_XCLIENT_EHLO:
if (invalid_line || (status / 100) != 2) { if (invalid_line || (status / 100) != 2) {
const char *reason = t_strdup_printf( const char *reason = t_strdup_printf(
"Invalid EHLO line: %s", "Invalid EHLO line: %s",
str_sanitize(line, 160)); str_sanitize(line, 160));
login_proxy_failed(client->login_proxy, login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy), login_proxy_get_event(client->login_proxy),
LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason); LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
return -1; return -1;
} }
skipping to change at line 324 skipping to change at line 481
text[4] == ' ' && text[5] != '\0') { text[4] == ' ' && text[5] != '\0') {
subm_client->proxy_capability |= subm_client->proxy_capability |=
SMTP_CAPABILITY_AUTH; SMTP_CAPABILITY_AUTH;
} else if (strcasecmp(text, "ENHANCEDSTATUSCODES") == 0) { } else if (strcasecmp(text, "ENHANCEDSTATUSCODES") == 0) {
subm_client->proxy_capability |= subm_client->proxy_capability |=
SMTP_CAPABILITY_ENHANCEDSTATUSCODES; SMTP_CAPABILITY_ENHANCEDSTATUSCODES;
} }
if (!last_line) if (!last_line)
return 0; return 0;
if (subm_client->proxy_state == SUBMISSION_PROXY_TLS_EHLO) { return proxy_handle_ehlo_reply(subm_client, output);
if (proxy_send_login(subm_client, output) < 0)
return -1;
return 0;
}
ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
if (proxy_send_login(subm_client, output) < 0)
return -1;
} else {
if ((subm_client->proxy_capability &
SMTP_CAPABILITY_STARTTLS) == 0) {
login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy
),
LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG,
"STARTTLS not supported");
return -1;
}
o_stream_nsend_str(output, "STARTTLS\r\n");
subm_client->proxy_state = SUBMISSION_PROXY_STARTTLS;
}
return 0;
case SUBMISSION_PROXY_STARTTLS: case SUBMISSION_PROXY_STARTTLS:
if (invalid_line || status != 220) { if (invalid_line || status != 220) {
const char *reason = t_strdup_printf( const char *reason = t_strdup_printf(
"STARTTLS failed: %s", "STARTTLS failed: %s",
str_sanitize(line, 160)); str_sanitize(line, 160));
login_proxy_failed(client->login_proxy, login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy), login_proxy_get_event(client->login_proxy),
LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason); LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason);
return -1; return -1;
} }
skipping to change at line 381 skipping to change at line 516
if (invalid_line || (status / 100) != 2) { if (invalid_line || (status / 100) != 2) {
const char *reason = t_strdup_printf( const char *reason = t_strdup_printf(
"XCLIENT failed: %s", str_sanitize(line, 160)); "XCLIENT failed: %s", str_sanitize(line, 160));
login_proxy_failed(client->login_proxy, login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy), login_proxy_get_event(client->login_proxy),
LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason); LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason);
return -1; return -1;
} }
if (!last_line) if (!last_line)
return 0; return 0;
subm_client->proxy_state = SUBMISSION_PROXY_AUTHENTICATE; i_assert(subm_client->proxy_xclient_replies_expected > 0);
if (--subm_client->proxy_xclient_replies_expected > 0)
return 0;
subm_client->proxy_state = SUBMISSION_PROXY_XCLIENT_EHLO;
return 0; return 0;
case SUBMISSION_PROXY_AUTHENTICATE: case SUBMISSION_PROXY_AUTHENTICATE:
if (invalid_line) if (invalid_line)
break; break;
if (status == 334 && client->proxy_sasl_client != NULL) { if (status == 334 && client->proxy_sasl_client != NULL) {
/* continue SASL authentication */ /* continue SASL authentication */
if (submission_proxy_continue_sasl_auth(client, output, if (submission_proxy_continue_sasl_auth(client, output,
text) < 0) text) < 0)
return -1; return -1;
return 0; return 0;
 End of changes. 21 change blocks. 
52 lines changed or deleted 189 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)