From fdfb6fbd980e7b0b714b170fde066b440da1ba5d Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Sat, 20 Nov 2021 23:35:16 +0100 Subject: [PATCH] lib-smtp: smtp-dovecot - Generate and parse referral data as URI authority. This makes sure special characters are escaped properly. Before, usernames with special characters and IPv6 caused problems. --- src/lib-smtp/smtp-dovecot.c | 61 ++++++++++++++++------ src/lib-smtp/smtp-dovecot.h | 3 +- src/lmtp/lmtp-proxy.c | 1 + src/submission-login/client-authenticate.c | 1 + 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/lib-smtp/smtp-dovecot.c b/src/lib-smtp/smtp-dovecot.c index 510091a412..88e68a6099 100644 --- a/src/lib-smtp/smtp-dovecot.c +++ b/src/lib-smtp/smtp-dovecot.c @@ -2,7 +2,7 @@ #include "lib.h" #include "str.h" -#include "auth-proxy.h" +#include "uri-util.h" #include "smtp-common.h" #include "smtp-reply.h" #include "smtp-server.h" @@ -20,32 +20,55 @@ bool smtp_reply_is_proxy_redirect(const struct smtp_reply *reply) SMTP_PROXY_REDIRECT_ENH_CODE); } -int smtp_proxy_redirect_parse(const char *target, const char **destuser_r, +int smtp_proxy_redirect_parse(const char *resp, const char **destuser_r, const char **host_r, struct ip_addr *ip_r, in_port_t *port_r, const char **error_r) { const char *pend; + *destuser_r = NULL; + *host_r = NULL; + i_zero(ip_r); + *port_r = 0; *error_r = NULL; /* Skip
part of the reply if present (RCPT reply) */ - pend = strchr(target, ' '); - if (*target == '<') { - if (pend == NULL) { + pend = strchr(resp, ' '); + if (*resp == '<') { + if (pend == NULL || *(pend - 1) != '>') { *error_r = "Invalid path in redirect response"; return -1; } - target = pend + 1; - pend = strchr(target, ' '); + resp = pend + 1; } - if (pend != NULL) - target = t_strdup_until(target, pend); - if (!auth_proxy_parse_redirect(target, destuser_r, host_r, - ip_r, port_r)) { - *error_r = "Invalid redirect data"; + struct uri_parser parser; + const char *destuser; + struct uri_authority uri_auth; + + i_zero(&parser); + parser.pool = pool_datastack_create(); + parser.begin = parser.cur = (const unsigned char *)resp; + parser.end = parser.begin + strlen(resp); + parser.parse_prefix = TRUE; + + if (uri_parse_host_authority(&parser, &uri_auth) < 0 || + !uri_data_decode(&parser, uri_auth.enc_userinfo, NULL, &destuser)) { + *error_r = parser.error; return -1; + } + if (*parser.cur != '\0' && *parser.cur != ' ') { + *error_r = t_strdup_printf( + "Invalid character %s in redirect target", + uri_char_sanitize(*parser.cur)); + return -1; + } + + *destuser_r = destuser; + *host_r = uri_auth.host.name; + *ip_r = uri_auth.host.ip; + *port_r = uri_auth.port; return 0; } @@ -55,12 +78,16 @@ smtp_create_redirect_reply(const struct smtp_proxy_redirect *predir, { string_t *referral = t_str_new(128); + struct uri_host host = { + .name = predir->host, + .ip = predir->host_ip, + }; if (predir->username != NULL) - str_printfa(referral, "%s@", predir->username); - if (predir->port == default_port) - str_append(referral, predir->host); - else - str_printfa(referral, "%s:%u", predir->host, predir->port); + uri_append_userinfo(referral, predir->username); + uri_append_host(referral, &host); + if (predir->port != default_port) + uri_append_port(referral, predir->port); + return str_c(referral); } diff --git a/src/lib-smtp/smtp-dovecot.h b/src/lib-smtp/smtp-dovecot.h index 75352d325e..0757a892e0 100644 --- a/src/lib-smtp/smtp-dovecot.h +++ b/src/lib-smtp/smtp-dovecot.h @@ -14,13 +14,14 @@ struct smtp_server_recipient; struct smtp_proxy_redirect { const char *username; const char *host; + struct ip_addr host_ip; in_port_t port; }; bool smtp_reply_code_is_proxy_redirect(unsigned int code, const char *enh_code); bool smtp_reply_is_proxy_redirect(const struct smtp_reply *reply); -int smtp_proxy_redirect_parse(const char *target, const char **destuser_r, +int smtp_proxy_redirect_parse(const char *resp, const char **destuser_r, const char **host_r, struct ip_addr *ip_r, in_port_t *port_r, const char **error_r); diff --git a/src/lmtp/lmtp-proxy.c b/src/lmtp/lmtp-proxy.c index f5ffdaf4df..205acd21b8 100644 --- a/src/lmtp/lmtp-proxy.c +++ b/src/lmtp/lmtp-proxy.c @@ -846,6 +846,7 @@ lmtp_proxy_rcpt_handle_not_proxied(struct lmtp_proxy_recipient *lprcpt, const struct smtp_proxy_redirect predir = { .username = destuser, .host = set->set.host, + .host_ip = set->set.host_ip, .port = set->set.port, }; smtp_server_recipient_reply_redirect(rcpt, 0, &predir); diff --git a/src/submission-login/client-authenticate.c b/src/submission-login/client-authenticate.c index d9c03ff3b1..afd086c9c7 100644 --- a/src/submission-login/client-authenticate.c +++ b/src/submission-login/client-authenticate.c @@ -114,6 +114,7 @@ void submission_client_auth_result(struct client *client, const struct smtp_proxy_redirect predir = { .username = reply->proxy.username, .host = reply->proxy.host, + .host_ip = reply->proxy.host_ip, .port = reply->proxy.port, }; smtp_server_reply_redirect(cmd, login_binary->default_port, -- 2.47.3