#include "iostream-ssl.h"
#include "rfc822-parser.h"
#include "message-date.h"
-#include "auth-master.h"
#include "mail-storage-service.h"
#include "index/raw/raw-storage.h"
#include "lda-settings.h"
#include "lmtp-proxy.h"
#define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error"
-#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> "
-#define ERRSTR_TEMP_USERDB_FAIL \
- ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure"
-
-#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*125)
int cmd_lhlo(struct client *client, const char *args)
{
return 0;
}
-static bool
-client_proxy_rcpt_parse_fields(struct lmtp_proxy_rcpt_settings *set,
- const char *const *args, const char **address)
-{
- const char *p, *key, *value;
- bool proxying = FALSE, port_set = FALSE;
-
- for (; *args != NULL; args++) {
- p = strchr(*args, '=');
- if (p == NULL) {
- key = *args;
- value = "";
- } else {
- key = t_strdup_until(*args, p);
- value = p + 1;
- }
-
- if (strcmp(key, "proxy") == 0)
- proxying = TRUE;
- else if (strcmp(key, "host") == 0)
- set->host = value;
- else if (strcmp(key, "hostip") == 0) {
- if (net_addr2ip(value, &set->hostip) < 0) {
- i_error("proxy: Invalid hostip %s", value);
- return FALSE;
- }
- } else if (strcmp(key, "port") == 0) {
- if (net_str2port(value, &set->port) < 0) {
- i_error("proxy: Invalid port number %s", value);
- return FALSE;
- }
- port_set = TRUE;
- } else if (strcmp(key, "proxy_timeout") == 0) {
- if (str_to_uint(value, &set->timeout_msecs) < 0) {
- i_error("proxy: Invalid proxy_timeout value %s", value);
- return FALSE;
- }
- set->timeout_msecs *= 1000;
- } else if (strcmp(key, "protocol") == 0) {
- if (strcmp(value, "lmtp") == 0) {
- set->protocol = SMTP_PROTOCOL_LMTP;
- if (!port_set)
- set->port = 24;
- } else if (strcmp(value, "smtp") == 0) {
- set->protocol = SMTP_PROTOCOL_SMTP;
- if (!port_set)
- set->port = 25;
- } else {
- i_error("proxy: Unknown protocol %s", value);
- return FALSE;
- }
- } else if (strcmp(key, "user") == 0 ||
- strcmp(key, "destuser") == 0) {
- /* changing the username */
- *address = value;
- } else {
- /* just ignore it */
- }
- }
- if (proxying && set->host == NULL) {
- i_error("proxy: host not given");
- return FALSE;
- }
- return proxying;
-}
-
-static bool
-client_proxy_is_ourself(const struct client *client,
- const struct lmtp_proxy_rcpt_settings *set)
-{
- struct ip_addr ip;
-
- if (set->port != client->local_port)
- return FALSE;
-
- if (set->hostip.family != 0)
- ip = set->hostip;
- else {
- if (net_addr2ip(set->host, &ip) < 0)
- return FALSE;
- }
- if (!net_ip_compare(&ip, &client->local_ip))
- return FALSE;
- return TRUE;
-}
-
-static bool client_proxy_rcpt(struct client *client,
- struct smtp_address *address,
- const char *username, const char *detail, char delim,
- struct smtp_params_rcpt *params)
-{
- struct auth_master_connection *auth_conn;
- struct lmtp_proxy_rcpt_settings set;
- struct auth_user_info info;
- struct mail_storage_service_input input;
- const char *const *fields, *errstr, *orig_username = username;
- struct smtp_address *user;
- pool_t pool;
- int ret;
-
- i_zero(&input);
- input.module = input.service = "lmtp";
- mail_storage_service_init_settings(storage_service, &input);
-
- i_zero(&info);
- info.service = master_service_get_name(master_service);
- info.local_ip = client->local_ip;
- info.remote_ip = client->remote_ip;
- info.local_port = client->local_port;
- info.remote_port = client->remote_port;
-
- pool = pool_alloconly_create("auth lookup", 1024);
- auth_conn = mail_storage_service_get_auth_conn(storage_service);
- ret = auth_master_pass_lookup(auth_conn, username, &info,
- pool, &fields);
- if (ret <= 0) {
- errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) :
- t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL,
- smtp_address_encode(address));
- pool_unref(&pool);
- if (ret < 0) {
- client_send_line(client, "%s", errstr);
- return TRUE;
- } else {
- /* user not found from passdb. try userdb also. */
- return FALSE;
- }
- }
-
- i_zero(&set);
- set.port = client->local_port;
- set.protocol = SMTP_PROTOCOL_LMTP;
- set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
- set.params = *params;
-
- if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) {
- /* not proxying this user */
- pool_unref(&pool);
- return FALSE;
- }
- if (strcmp(username, orig_username) != 0) {
- if (smtp_address_parse_username(pool_datastack_create(),
- username, &user, &errstr) < 0) {
- i_error("%s: Username `%s' returned by passdb lookup is not a valid SMTP address",
- orig_username, username);
- client_send_line(client, "550 5.3.5 <%s> "
- "Internal user lookup failure",
- smtp_address_encode(address));
- pool_unref(&pool);
- return FALSE;
- }
- /* username changed. change the address as well */
- if (*detail == '\0') {
- address = user;
- } else {
- address = smtp_address_add_detail_temp(user, detail, delim);
- }
- } else if (client_proxy_is_ourself(client, &set)) {
- i_error("Proxying to <%s> loops to itself", username);
- client_send_line(client, "554 5.4.6 <%s> "
- "Proxying loops to itself",
- smtp_address_encode(address));
- pool_unref(&pool);
- return TRUE;
- }
-
- if (client->proxy_ttl <= 1) {
- i_error("Proxying to <%s> appears to be looping (TTL=0)",
- username);
- client_send_line(client, "554 5.4.6 <%s> "
- "Proxying appears to be looping (TTL=0)",
- username);
- pool_unref(&pool);
- return TRUE;
- }
- if (array_count(&client->state.rcpt_to) != 0) {
- client_send_line(client, "451 4.3.0 <%s> "
- "Can't handle mixed proxy/non-proxy destinations",
- smtp_address_encode(address));
- pool_unref(&pool);
- return TRUE;
- }
- if (client->proxy == NULL) {
- struct lmtp_proxy_settings proxy_set;
-
- i_zero(&proxy_set);
- proxy_set.my_hostname = client->my_domain;
- proxy_set.dns_client_socket_path = dns_client_socket_path;
- proxy_set.session_id = client->state.session_id;
- proxy_set.source_ip = client->remote_ip;
- proxy_set.source_port = client->remote_port;
- proxy_set.proxy_ttl = client->proxy_ttl-1;
-
- client->proxy = lmtp_proxy_init(&proxy_set, client->output);
- lmtp_proxy_mail_from(client->proxy, client->state.mail_from,
- &client->state.mail_params);
- }
- if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0)
- client_send_line(client, "451 4.4.0 Remote server not answering");
- else
- client_send_line(client, "250 2.1.5 OK");
- pool_unref(&pool);
- return TRUE;
-}
-
int cmd_rcpt(struct client *client, const char *args)
{
struct mail_recipient *rcpt;
#include "smtp-client.h"
#include "smtp-client-connection.h"
#include "smtp-client-transaction.h"
+#include "auth-master.h"
+#include "master-service.h"
+#include "mail-storage-service.h"
+#include "client.h"
+#include "main.h"
#include "lmtp-proxy.h"
#define LMTP_MAX_LINE_LEN 1024
+#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*125)
+
+#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> "
+#define ERRSTR_TEMP_USERDB_FAIL \
+ ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure"
struct lmtp_proxy_recipient {
struct lmtp_proxy_connection *conn;
/* nothing */
}
+static bool
+client_proxy_rcpt_parse_fields(struct lmtp_proxy_rcpt_settings *set,
+ const char *const *args, const char **address)
+{
+ const char *p, *key, *value;
+ bool proxying = FALSE, port_set = FALSE;
+
+ for (; *args != NULL; args++) {
+ p = strchr(*args, '=');
+ if (p == NULL) {
+ key = *args;
+ value = "";
+ } else {
+ key = t_strdup_until(*args, p);
+ value = p + 1;
+ }
+
+ if (strcmp(key, "proxy") == 0)
+ proxying = TRUE;
+ else if (strcmp(key, "host") == 0)
+ set->host = value;
+ else if (strcmp(key, "hostip") == 0) {
+ if (net_addr2ip(value, &set->hostip) < 0) {
+ i_error("proxy: Invalid hostip %s", value);
+ return FALSE;
+ }
+ } else if (strcmp(key, "port") == 0) {
+ if (net_str2port(value, &set->port) < 0) {
+ i_error("proxy: Invalid port number %s", value);
+ return FALSE;
+ }
+ port_set = TRUE;
+ } else if (strcmp(key, "proxy_timeout") == 0) {
+ if (str_to_uint(value, &set->timeout_msecs) < 0) {
+ i_error("proxy: Invalid proxy_timeout value %s", value);
+ return FALSE;
+ }
+ set->timeout_msecs *= 1000;
+ } else if (strcmp(key, "protocol") == 0) {
+ if (strcmp(value, "lmtp") == 0) {
+ set->protocol = SMTP_PROTOCOL_LMTP;
+ if (!port_set)
+ set->port = 24;
+ } else if (strcmp(value, "smtp") == 0) {
+ set->protocol = SMTP_PROTOCOL_SMTP;
+ if (!port_set)
+ set->port = 25;
+ } else {
+ i_error("proxy: Unknown protocol %s", value);
+ return FALSE;
+ }
+ } else if (strcmp(key, "user") == 0 ||
+ strcmp(key, "destuser") == 0) {
+ /* changing the username */
+ *address = value;
+ } else {
+ /* just ignore it */
+ }
+ }
+ if (proxying && set->host == NULL) {
+ i_error("proxy: host not given");
+ return FALSE;
+ }
+ return proxying;
+}
+
+static bool
+client_proxy_is_ourself(const struct client *client,
+ const struct lmtp_proxy_rcpt_settings *set)
+{
+ struct ip_addr ip;
+
+ if (set->port != client->local_port)
+ return FALSE;
+
+ if (set->hostip.family != 0)
+ ip = set->hostip;
+ else {
+ if (net_addr2ip(set->host, &ip) < 0)
+ return FALSE;
+ }
+ if (!net_ip_compare(&ip, &client->local_ip))
+ return FALSE;
+ return TRUE;
+}
+
+bool client_proxy_rcpt(struct client *client,
+ struct smtp_address *address,
+ const char *username, const char *detail, char delim,
+ struct smtp_params_rcpt *params)
+{
+ struct auth_master_connection *auth_conn;
+ struct lmtp_proxy_rcpt_settings set;
+ struct auth_user_info info;
+ struct mail_storage_service_input input;
+ const char *const *fields, *errstr, *orig_username = username;
+ struct smtp_address *user;
+ pool_t pool;
+ int ret;
+
+ i_zero(&input);
+ input.module = input.service = "lmtp";
+ mail_storage_service_init_settings(storage_service, &input);
+
+ i_zero(&info);
+ info.service = master_service_get_name(master_service);
+ info.local_ip = client->local_ip;
+ info.remote_ip = client->remote_ip;
+ info.local_port = client->local_port;
+ info.remote_port = client->remote_port;
+
+ pool = pool_alloconly_create("auth lookup", 1024);
+ auth_conn = mail_storage_service_get_auth_conn(storage_service);
+ ret = auth_master_pass_lookup(auth_conn, username, &info,
+ pool, &fields);
+ if (ret <= 0) {
+ errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) :
+ t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL,
+ smtp_address_encode(address));
+ pool_unref(&pool);
+ if (ret < 0) {
+ client_send_line(client, "%s", errstr);
+ return TRUE;
+ } else {
+ /* user not found from passdb. try userdb also. */
+ return FALSE;
+ }
+ }
+
+ i_zero(&set);
+ set.port = client->local_port;
+ set.protocol = SMTP_PROTOCOL_LMTP;
+ set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
+ set.params = *params;
+
+ if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) {
+ /* not proxying this user */
+ pool_unref(&pool);
+ return FALSE;
+ }
+ if (strcmp(username, orig_username) != 0) {
+ if (smtp_address_parse_username(pool_datastack_create(),
+ username, &user, &errstr) < 0) {
+ i_error("%s: Username `%s' returned by passdb lookup is not a valid SMTP address",
+ orig_username, username);
+ client_send_line(client, "550 5.3.5 <%s> "
+ "Internal user lookup failure",
+ smtp_address_encode(address));
+ pool_unref(&pool);
+ return FALSE;
+ }
+ /* username changed. change the address as well */
+ if (*detail == '\0') {
+ address = user;
+ } else {
+ address = smtp_address_add_detail_temp(user, detail, delim);
+ }
+ } else if (client_proxy_is_ourself(client, &set)) {
+ i_error("Proxying to <%s> loops to itself", username);
+ client_send_line(client, "554 5.4.6 <%s> "
+ "Proxying loops to itself",
+ smtp_address_encode(address));
+ pool_unref(&pool);
+ return TRUE;
+ }
+
+ if (client->proxy_ttl <= 1) {
+ i_error("Proxying to <%s> appears to be looping (TTL=0)",
+ username);
+ client_send_line(client, "554 5.4.6 <%s> "
+ "Proxying appears to be looping (TTL=0)",
+ username);
+ pool_unref(&pool);
+ return TRUE;
+ }
+ if (array_count(&client->state.rcpt_to) != 0) {
+ client_send_line(client, "451 4.3.0 <%s> "
+ "Can't handle mixed proxy/non-proxy destinations",
+ smtp_address_encode(address));
+ pool_unref(&pool);
+ return TRUE;
+ }
+ if (client->proxy == NULL) {
+ struct lmtp_proxy_settings proxy_set;
+
+ i_zero(&proxy_set);
+ proxy_set.my_hostname = client->my_domain;
+ proxy_set.dns_client_socket_path = dns_client_socket_path;
+ proxy_set.session_id = client->state.session_id;
+ proxy_set.source_ip = client->remote_ip;
+ proxy_set.source_port = client->remote_port;
+ proxy_set.proxy_ttl = client->proxy_ttl-1;
+
+ client->proxy = lmtp_proxy_init(&proxy_set, client->output);
+ lmtp_proxy_mail_from(client->proxy, client->state.mail_from,
+ &client->state.mail_params);
+ }
+ if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0)
+ client_send_line(client, "451 4.4.0 Remote server not answering");
+ else
+ client_send_line(client, "250 2.1.5 OK");
+ pool_unref(&pool);
+ return TRUE;
+}
+
void lmtp_proxy_start(struct lmtp_proxy *proxy, struct istream *data_input,
lmtp_proxy_finish_callback_t *callback, void *context)
{
#define LMTP_PROXY_DEFAULT_TTL 5
+struct smtp_address;
+struct client;
+
struct lmtp_proxy_settings {
const char *my_hostname;
const char *dns_client_socket_path;
int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy,
const struct smtp_address *address,
const struct lmtp_proxy_rcpt_settings *set);
+
+bool client_proxy_rcpt(struct client *client,
+ struct smtp_address *address,
+ const char *username, const char *detail, char delim,
+ struct smtp_params_rcpt *params);
+
/* Start proxying */
void lmtp_proxy_start(struct lmtp_proxy *proxy, struct istream *data_input,
lmtp_proxy_finish_callback_t *callback, void *context)
ATTR_NULL(3);
+
#endif