1 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lmtp-common.h"
4 #include "istream.h"
5 #include "istream-sized.h"
6 #include "ostream.h"
7 #include "iostream-ssl.h"
8 #include "str.h"
9 #include "strescape.h"
10 #include "time-util.h"
11 #include "smtp-common.h"
12 #include "smtp-params.h"
13 #include "smtp-address.h"
14 #include "smtp-client.h"
15 #include "smtp-client-connection.h"
16 #include "smtp-client-transaction.h"
17 #include "auth-master.h"
18 #include "master-service-ssl-settings.h"
19 #include "mail-storage-service.h"
20 #include "lda-settings.h"
21 #include "lmtp-recipient.h"
22 #include "lmtp-proxy.h"
23 
24 #define LMTP_MAX_REPLY_SIZE 4096
25 #define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*125)
26 
27 enum lmtp_proxy_ssl_flags {
28 	/* Use SSL/TLS enabled */
29 	PROXY_SSL_FLAG_YES	= 0x01,
30 	/* Don't do SSL handshake immediately after connected */
31 	PROXY_SSL_FLAG_STARTTLS	= 0x02,
32 	/* Don't require that the received certificate is valid */
33 	PROXY_SSL_FLAG_ANY_CERT	= 0x04
34 };
35 
36 struct lmtp_proxy_rcpt_settings {
37 	enum smtp_protocol protocol;
38 	const char *host;
39 	struct ip_addr hostip, source_ip;
40 	in_port_t port;
41 	enum lmtp_proxy_ssl_flags ssl_flags;
42 	unsigned int timeout_msecs;
43 	struct smtp_params_rcpt params;
44 
45 	bool proxy_not_trusted:1;
46 };
47 
48 struct lmtp_proxy_recipient {
49 	struct lmtp_recipient *rcpt;
50 	struct lmtp_proxy_connection *conn;
51 
52 	struct smtp_address *address;
53 
54 	const unsigned char *forward_fields;
55 	size_t forward_fields_size;
56 
57 	bool rcpt_to_failed:1;
58 	bool data_reply_received:1;
59 };
60 
61 struct lmtp_proxy_connection {
62 	struct lmtp_proxy *proxy;
63 	struct lmtp_proxy_rcpt_settings set;
64 	char *host;
65 
66 	struct smtp_client_connection *lmtp_conn;
67 	struct smtp_client_transaction *lmtp_trans;
68 	struct istream *data_input;
69 	struct timeout *to;
70 
71 	bool finished:1;
72 	bool failed:1;
73 };
74 
75 struct lmtp_proxy {
76 	struct client *client;
77 
78 	struct smtp_server_transaction *trans;
79 
80 	struct smtp_client *lmtp_client;
81 
82 	ARRAY(struct lmtp_proxy_connection *) connections;
83 	ARRAY(struct lmtp_proxy_recipient *) rcpt_to;
84 	unsigned int next_data_reply_idx;
85 
86 	struct timeout *to_finish;
87 	struct istream *data_input;
88 
89 	unsigned int max_timeout_msecs;
90 
91 	bool finished:1;
92 };
93 
94 static void
95 lmtp_proxy_data_cb(const struct smtp_reply *reply,
96 		   struct lmtp_proxy_recipient *lprcpt);
97 
98 /*
99  * LMTP proxy
100  */
101 
102 static struct lmtp_proxy *
lmtp_proxy_init(struct client * client,struct smtp_server_transaction * trans)103 lmtp_proxy_init(struct client *client,
104 		struct smtp_server_transaction *trans)
105 {
106 	const char *extra_capabilities[] = {
107 		LMTP_RCPT_FORWARD_CAPABILITY,
108 		NULL };
109 	struct smtp_client_settings lmtp_set;
110 	struct lmtp_proxy *proxy;
111 
112 	proxy = i_new(struct lmtp_proxy, 1);
113 	proxy->client = client;
114 	proxy->trans = trans;
115 	i_array_init(&proxy->rcpt_to, 32);
116 	i_array_init(&proxy->connections, 32);
117 
118 	i_zero(&lmtp_set);
119 	lmtp_set.my_hostname = client->my_domain;
120 	lmtp_set.extra_capabilities = extra_capabilities;
121 	lmtp_set.dns_client_socket_path = dns_client_socket_path;
122 	lmtp_set.max_reply_size = LMTP_MAX_REPLY_SIZE;
123 	lmtp_set.rawlog_dir = client->lmtp_set->lmtp_proxy_rawlog_dir;
124 
125 	smtp_server_connection_get_proxy_data(client->conn,
126 					      &lmtp_set.proxy_data);
127 	lmtp_set.proxy_data.source_ip = client->remote_ip;
128 	lmtp_set.proxy_data.source_port = client->remote_port;
129 	if (lmtp_set.proxy_data.ttl_plus_1 == 0)
130 		lmtp_set.proxy_data.ttl_plus_1 = LMTP_PROXY_DEFAULT_TTL + 1;
131 	else
132 		lmtp_set.proxy_data.ttl_plus_1--;
133 	lmtp_set.event_parent = client->event;
134 
135 	proxy->lmtp_client = smtp_client_init(&lmtp_set);
136 
137 	return proxy;
138 }
139 
140 static void
lmtp_proxy_connection_deinit(struct lmtp_proxy_connection * conn)141 lmtp_proxy_connection_deinit(struct lmtp_proxy_connection *conn)
142 {
143 	if (conn->lmtp_trans != NULL)
144 		smtp_client_transaction_destroy(&conn->lmtp_trans);
145 	if (conn->lmtp_conn != NULL)
146 		smtp_client_connection_close(&conn->lmtp_conn);
147 	timeout_remove(&conn->to);
148 	i_stream_unref(&conn->data_input);
149 	i_free(conn->host);
150 	i_free(conn);
151 }
152 
lmtp_proxy_deinit(struct lmtp_proxy ** _proxy)153 void lmtp_proxy_deinit(struct lmtp_proxy **_proxy)
154 {
155 	struct lmtp_proxy *proxy = *_proxy;
156 	struct lmtp_proxy_connection *conn;
157 
158 	*_proxy = NULL;
159 
160 	array_foreach_elem(&proxy->connections, conn)
161 		lmtp_proxy_connection_deinit(conn);
162 
163 	smtp_client_deinit(&proxy->lmtp_client);
164 	i_stream_unref(&proxy->data_input);
165 	timeout_remove(&proxy->to_finish);
166 	array_free(&proxy->rcpt_to);
167 	array_free(&proxy->connections);
168 	i_free(proxy);
169 }
170 
171 static void
lmtp_proxy_mail_cb(const struct smtp_reply * proxy_reply ATTR_UNUSED,struct lmtp_proxy_connection * conn ATTR_UNUSED)172 lmtp_proxy_mail_cb(const struct smtp_reply *proxy_reply ATTR_UNUSED,
173 		   struct lmtp_proxy_connection *conn ATTR_UNUSED)
174 {
175 	/* nothing */
176 }
177 
178 static void
lmtp_proxy_connection_finish(struct lmtp_proxy_connection * conn)179 lmtp_proxy_connection_finish(struct lmtp_proxy_connection *conn)
180 {
181 	conn->finished = TRUE;
182 	conn->lmtp_trans = NULL;
183 }
184 
185 static void
lmtp_proxy_connection_init_ssl(struct lmtp_proxy_connection * conn,struct ssl_iostream_settings * ssl_set_r,enum smtp_client_connection_ssl_mode * ssl_mode_r)186 lmtp_proxy_connection_init_ssl(struct lmtp_proxy_connection *conn,
187 			       struct ssl_iostream_settings *ssl_set_r,
188 			       enum smtp_client_connection_ssl_mode *ssl_mode_r)
189 {
190 	const struct master_service_ssl_settings *master_ssl_set;
191 
192 	*ssl_mode_r = SMTP_CLIENT_SSL_MODE_NONE;
193 
194 	if ((conn->set.ssl_flags & PROXY_SSL_FLAG_YES) == 0) {
195 		i_zero(ssl_set_r);
196 		return;
197 	}
198 
199 	master_ssl_set = master_service_ssl_settings_get(master_service);
200 	master_service_ssl_client_settings_to_iostream_set(
201 		master_ssl_set, pool_datastack_create(), ssl_set_r);
202 	if ((conn->set.ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0)
203 		ssl_set_r->allow_invalid_cert = TRUE;
204 
205 	if ((conn->set.ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0)
206 		*ssl_mode_r = SMTP_CLIENT_SSL_MODE_IMMEDIATE;
207 	else
208 		*ssl_mode_r = SMTP_CLIENT_SSL_MODE_STARTTLS;
209 }
210 
211 static bool
lmtp_proxy_connection_has_rcpt_forward(struct lmtp_proxy_connection * conn)212 lmtp_proxy_connection_has_rcpt_forward(struct lmtp_proxy_connection *conn)
213 {
214 	const struct smtp_capability_extra *cap_extra =
215 		smtp_client_connection_get_extra_capability(
216 			conn->lmtp_conn, LMTP_RCPT_FORWARD_CAPABILITY);
217 
218 	return (cap_extra != NULL);
219 }
220 
221 static struct lmtp_proxy_connection *
lmtp_proxy_get_connection(struct lmtp_proxy * proxy,const struct lmtp_proxy_rcpt_settings * set)222 lmtp_proxy_get_connection(struct lmtp_proxy *proxy,
223 			  const struct lmtp_proxy_rcpt_settings *set)
224 {
225 	static const char *rcpt_param_extensions[] =
226 		{ LMTP_RCPT_FORWARD_PARAMETER, NULL };
227 	static const struct smtp_client_capability_extra cap_rcpt_forward = {
228 		.name = LMTP_RCPT_FORWARD_CAPABILITY,
229 		.rcpt_param_extensions = rcpt_param_extensions,
230 	};
231 	struct smtp_client_settings lmtp_set;
232 	struct smtp_server_transaction *trans = proxy->trans;
233 	struct lmtp_proxy_connection *conn;
234 	enum smtp_client_connection_ssl_mode ssl_mode;
235 	struct ssl_iostream_settings ssl_set;
236 
237 	i_assert(set->timeout_msecs > 0);
238 
239 	array_foreach_elem(&proxy->connections, conn) {
240 		if (conn->set.protocol == set->protocol &&
241 		    conn->set.port == set->port &&
242 		    strcmp(conn->set.host, set->host) == 0 &&
243 		    net_ip_compare(&conn->set.hostip, &set->hostip) &&
244 		    net_ip_compare(&conn->set.source_ip, &set->source_ip) &&
245 		    conn->set.ssl_flags == set->ssl_flags)
246 			return conn;
247 	}
248 
249 	conn = i_new(struct lmtp_proxy_connection, 1);
250 	conn->proxy = proxy;
251 	conn->set.protocol = set->protocol;
252 	conn->set.hostip = set->hostip;
253 	conn->host = i_strdup(set->host);
254 	conn->set.host = conn->host;
255 	conn->set.source_ip = set->source_ip;
256 	conn->set.port = set->port;
257 	conn->set.ssl_flags = set->ssl_flags;
258 	conn->set.timeout_msecs = set->timeout_msecs;
259 	array_push_back(&proxy->connections, &conn);
260 
261 	lmtp_proxy_connection_init_ssl(conn, &ssl_set, &ssl_mode);
262 
263 	i_zero(&lmtp_set);
264 	lmtp_set.my_ip = conn->set.source_ip;
265 	lmtp_set.ssl = &ssl_set;
266 	lmtp_set.peer_trusted = !conn->set.proxy_not_trusted;
267 	lmtp_set.forced_capabilities = SMTP_CAPABILITY__ORCPT;
268 	lmtp_set.mail_send_broken_path = TRUE;
269 
270 	if (conn->set.hostip.family != 0) {
271 		conn->lmtp_conn = smtp_client_connection_create_ip(
272 			proxy->lmtp_client, set->protocol,
273 			&conn->set.hostip, conn->set.port,
274 			conn->set.host, ssl_mode, &lmtp_set);
275 	} else {
276 		conn->lmtp_conn = smtp_client_connection_create(
277 			proxy->lmtp_client, set->protocol,
278 			conn->set.host, conn->set.port,
279 			ssl_mode, &lmtp_set);
280 	}
281 	smtp_client_connection_accept_extra_capability(conn->lmtp_conn,
282 						       &cap_rcpt_forward);
283 	smtp_client_connection_connect(conn->lmtp_conn, NULL, NULL);
284 
285 	conn->lmtp_trans = smtp_client_transaction_create(
286 		conn->lmtp_conn, trans->mail_from, &trans->params, 0,
287 		lmtp_proxy_connection_finish, conn);
288 
289 	smtp_client_transaction_start(conn->lmtp_trans,
290 				      lmtp_proxy_mail_cb, conn);
291 
292 	if (proxy->max_timeout_msecs < set->timeout_msecs)
293 		proxy->max_timeout_msecs = set->timeout_msecs;
294 	return conn;
295 }
296 
297 static bool
lmtp_proxy_handle_reply(struct lmtp_proxy_recipient * lprcpt,const struct smtp_reply * reply,struct smtp_reply * reply_r)298 lmtp_proxy_handle_reply(struct lmtp_proxy_recipient *lprcpt,
299 			const struct smtp_reply *reply,
300 			struct smtp_reply *reply_r)
301 {
302 	struct smtp_server_recipient *rcpt = lprcpt->rcpt->rcpt;
303 
304 	*reply_r = *reply;
305 
306 	if (!smtp_reply_is_remote(reply) ||
307 		reply->status == SMTP_CLIENT_COMMAND_ERROR_CONNECTION_CLOSED) {
308 		const char *detail = "";
309 
310 		switch (reply->status) {
311 		case SMTP_CLIENT_COMMAND_ERROR_ABORTED:
312 			break;
313 		case SMTP_CLIENT_COMMAND_ERROR_HOST_LOOKUP_FAILED:
314 			detail = " (DNS lookup)";
315 			break;
316 		case SMTP_CLIENT_COMMAND_ERROR_CONNECT_FAILED:
317 		case SMTP_CLIENT_COMMAND_ERROR_AUTH_FAILED:
318 			detail = " (connect)";
319 			break;
320 		case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_LOST:
321 		case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_CLOSED:
322 			detail = " (connection lost)";
323 			break;
324 		case SMTP_CLIENT_COMMAND_ERROR_BAD_REPLY:
325 			detail = " (bad reply)";
326 			break;
327 		case SMTP_CLIENT_COMMAND_ERROR_TIMED_OUT:
328 			detail = " (timed out)";
329 			break;
330 		default:
331 			break;
332 		}
333 
334 		smtp_server_command_fail(rcpt->cmd->cmd, 451, "4.4.0",
335 					 "Remote server not answering%s",
336 					 detail);
337 		return FALSE;
338 	}
339 
340 	if (!smtp_reply_has_enhanced_code(reply)) {
341 		reply_r->enhanced_code =
342 			SMTP_REPLY_ENH_CODE(reply->status / 100, 0, 0);
343 	}
344 	return TRUE;
345 }
346 
347 /*
348  * RCPT command
349  */
350 
351 static bool
lmtp_proxy_rcpt_parse_fields(struct lmtp_recipient * lrcpt,struct lmtp_proxy_rcpt_settings * set,const char * const * args,const char ** address)352 lmtp_proxy_rcpt_parse_fields(struct lmtp_recipient *lrcpt,
353 			     struct lmtp_proxy_rcpt_settings *set,
354 			     const char *const *args, const char **address)
355 {
356 	struct smtp_server_recipient *rcpt = lrcpt->rcpt;
357 	const char *p, *key, *value;
358 	bool proxying = FALSE, port_set = FALSE;
359 
360 	for (; *args != NULL; args++) {
361 		p = strchr(*args, '=');
362 		if (p == NULL) {
363 			key = *args;
364 			value = "";
365 		} else {
366 			key = t_strdup_until(*args, p);
367 			value = p + 1;
368 		}
369 
370 		if (strcmp(key, "proxy") == 0)
371 			proxying = TRUE;
372 		else if (strcmp(key, "host") == 0)
373 			set->host = value;
374 		else if (strcmp(key, "hostip") == 0) {
375 			if (net_addr2ip(value, &set->hostip) < 0) {
376 				e_error(rcpt->event,
377 					"proxy: Invalid hostip %s", value);
378 				return FALSE;
379 			}
380 		} else if (strcmp(key, "source_ip") == 0) {
381 			if (net_addr2ip(value, &set->source_ip) < 0) {
382 				e_error(rcpt->event,
383 					"proxy: Invalid source_ip %s", value);
384 				return FALSE;
385 			}
386 		} else if (strcmp(key, "port") == 0) {
387 			if (net_str2port(value, &set->port) < 0) {
388 				e_error(rcpt->event,
389 					"proxy: Invalid port number %s", value);
390 				return FALSE;
391 			}
392 			port_set = TRUE;
393 		} else if (strcmp(key, "proxy_timeout") == 0) {
394 			if (str_to_uint(value, &set->timeout_msecs) < 0) {
395 				e_error(rcpt->event,"proxy: "
396 					"Invalid proxy_timeout value %s", value);
397 				return FALSE;
398 			}
399 			set->timeout_msecs *= 1000;
400 		} else if (strcmp(key, "proxy_not_trusted") == 0) {
401 			set->proxy_not_trusted = TRUE;
402 		} else if (strcmp(key, "protocol") == 0) {
403 			if (strcmp(value, "lmtp") == 0) {
404 				set->protocol = SMTP_PROTOCOL_LMTP;
405 				if (!port_set)
406 					set->port = 24;
407 			} else if (strcmp(value, "smtp") == 0) {
408 				set->protocol = SMTP_PROTOCOL_SMTP;
409 				if (!port_set)
410 					set->port = 25;
411 			} else {
412 				e_error(rcpt->event,
413 					"proxy: Unknown protocol %s", value);
414 				return FALSE;
415 			}
416 		} else if (strcmp(key, "ssl") == 0) {
417 			set->ssl_flags |= PROXY_SSL_FLAG_YES;
418 			if (strcmp(value, "any-cert") == 0)
419 				set->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
420 		} else if (strcmp(key, "starttls") == 0) {
421 			set->ssl_flags |= PROXY_SSL_FLAG_YES |
422 				PROXY_SSL_FLAG_STARTTLS;
423 			if (strcmp(value, "any-cert") == 0)
424 				set->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
425 		} else if (strcmp(key, "user") == 0 ||
426 			   strcmp(key, "destuser") == 0) {
427 			/* Changing the username */
428 			*address = value;
429 		} else {
430 			/* Just ignore it */
431 		}
432 	}
433 	if (proxying && set->host == NULL) {
434 		e_error(rcpt->event, "proxy: host not given");
435 		return FALSE;
436 	}
437 	return proxying;
438 }
439 
440 static bool
lmtp_proxy_is_ourself(const struct client * client,const struct lmtp_proxy_rcpt_settings * set)441 lmtp_proxy_is_ourself(const struct client *client,
442 		      const struct lmtp_proxy_rcpt_settings *set)
443 {
444 	struct ip_addr ip;
445 
446 	if (set->port != client->local_port)
447 		return FALSE;
448 
449 	if (set->hostip.family != 0)
450 		ip = set->hostip;
451 	else {
452 		if (net_addr2ip(set->host, &ip) < 0)
453 			return FALSE;
454 	}
455 	if (!net_ip_compare(&ip, &client->local_ip))
456 		return FALSE;
457 	return TRUE;
458 }
459 
460 static void
lmtp_proxy_rcpt_approved(struct smtp_server_recipient * rcpt ATTR_UNUSED,struct lmtp_proxy_recipient * lprcpt)461 lmtp_proxy_rcpt_approved(struct smtp_server_recipient *rcpt ATTR_UNUSED,
462 			 struct lmtp_proxy_recipient *lprcpt)
463 {
464 	struct client *client = lprcpt->rcpt->client;
465 
466 	/* Add to proxy recipients */
467 	array_push_back(&client->proxy->rcpt_to, &lprcpt);
468 }
469 
470 static void
lmtp_proxy_rcpt_cb(const struct smtp_reply * proxy_reply,struct lmtp_proxy_recipient * lprcpt)471 lmtp_proxy_rcpt_cb(const struct smtp_reply *proxy_reply,
472 		   struct lmtp_proxy_recipient *lprcpt)
473 {
474 	struct smtp_server_recipient *rcpt = lprcpt->rcpt->rcpt;
475 	struct smtp_reply reply;
476 
477 	if (!lmtp_proxy_handle_reply(lprcpt, proxy_reply, &reply))
478 		return;
479 
480 	if (smtp_reply_is_success(proxy_reply)) {
481 		/* If backend accepts it, we accept it too */
482 
483 		/* The default 2.0.0 code won't do */
484 		if (!smtp_reply_has_enhanced_code(proxy_reply))
485 			reply.enhanced_code = SMTP_REPLY_ENH_CODE(2, 1, 0);
486 	}
487 
488 	/* Forward reply */
489 	smtp_server_recipient_reply_forward(rcpt, &reply);
490 }
491 
492 static void
lmtp_proxy_rcpt_login_cb(const struct smtp_reply * proxy_reply,void * context)493 lmtp_proxy_rcpt_login_cb(const struct smtp_reply *proxy_reply, void *context)
494 {
495 	struct lmtp_proxy_recipient *lprcpt = context;
496 	struct lmtp_recipient *lrcpt = lprcpt->rcpt;
497 	struct lmtp_proxy_connection *conn = lprcpt->conn;
498 	struct smtp_server_recipient *rcpt = lrcpt->rcpt;
499 	struct smtp_reply reply;
500 	struct smtp_client_transaction_rcpt *relay_rcpt;
501 	struct smtp_params_rcpt *rcpt_params = &rcpt->params;
502 	bool add_orcpt_param = FALSE, add_xrcptforward_param = FALSE;
503 	pool_t param_pool;
504 
505 	if (!lmtp_proxy_handle_reply(lprcpt, proxy_reply, &reply))
506 		return;
507 	if (!smtp_reply_is_success(proxy_reply)) {
508 		smtp_server_recipient_reply_forward(rcpt, &reply);
509 		return;
510 	}
511 
512 	/* Add an ORCPT parameter when passdb changed the username (and
513 	   therefore the RCPT address changed) and there is no ORCPT parameter
514 	   yet. */
515 	if (!smtp_params_rcpt_has_orcpt(rcpt_params) &&
516 	    !smtp_address_equals(lprcpt->address, rcpt->path))
517 		add_orcpt_param = TRUE;
518 
519 	/* Add forward fields parameter when passdb returned forward_* fields */
520 	if (lprcpt->forward_fields != NULL &&
521 	    lmtp_proxy_connection_has_rcpt_forward(conn))
522 		add_xrcptforward_param = TRUE;
523 
524 	/* Copy params when changes are pending */
525 	param_pool = NULL;
526 	if (add_orcpt_param || add_xrcptforward_param) {
527 		param_pool = pool_datastack_create();
528 		rcpt_params = p_new(param_pool, struct smtp_params_rcpt, 1);
529 		smtp_params_rcpt_copy(param_pool, rcpt_params, &rcpt->params);
530 	}
531 
532 	/* Add ORCPT */
533 	if (add_orcpt_param) {
534 		smtp_params_rcpt_set_orcpt(rcpt_params, param_pool,
535 					   rcpt->path);
536 	}
537 	/* Add forward fields parameter */
538 	if (add_xrcptforward_param) {
539 		smtp_params_rcpt_encode_extra(
540 			rcpt_params, param_pool, LMTP_RCPT_FORWARD_PARAMETER,
541 			lprcpt->forward_fields, lprcpt->forward_fields_size);
542 	}
543 
544 	smtp_server_recipient_add_hook(
545 		rcpt, SMTP_SERVER_RECIPIENT_HOOK_APPROVED,
546 		lmtp_proxy_rcpt_approved, lprcpt);
547 
548 	relay_rcpt = smtp_client_transaction_add_pool_rcpt(
549 		conn->lmtp_trans, rcpt->pool, lprcpt->address, rcpt_params,
550 		lmtp_proxy_rcpt_cb, lprcpt);
551 	smtp_client_transaction_rcpt_set_data_callback(
552 		relay_rcpt, lmtp_proxy_data_cb, lprcpt);
553 }
554 
lmtp_proxy_rcpt(struct client * client,struct smtp_server_cmd_ctx * cmd,struct lmtp_recipient * lrcpt,const char * username,const char * detail,char delim)555 int lmtp_proxy_rcpt(struct client *client,
556 		    struct smtp_server_cmd_ctx *cmd,
557 		    struct lmtp_recipient *lrcpt,
558 		    const char *username, const char *detail,
559 		    char delim)
560 {
561 	struct auth_master_connection *auth_conn;
562 	struct lmtp_proxy_rcpt_settings set;
563 	struct lmtp_proxy_connection *conn;
564 	struct smtp_server_recipient *rcpt = lrcpt->rcpt;
565 	struct lmtp_proxy_recipient *lprcpt;
566 	struct smtp_server_transaction *trans;
567 	struct smtp_address *address = rcpt->path;
568 	struct auth_user_info info;
569 	struct mail_storage_service_input input;
570 	const char *const *fields, *errstr, *orig_username = username;
571 	struct smtp_proxy_data proxy_data;
572 	struct smtp_address *user;
573 	string_t *fwfields;
574 	pool_t auth_pool;
575 	int ret;
576 
577 	trans = smtp_server_connection_get_transaction(cmd->conn);
578 	i_assert(trans != NULL); /* MAIL command is synchronous */
579 
580 	i_zero(&input);
581 	input.module = input.service = "lmtp";
582 	mail_storage_service_init_settings(storage_service, &input);
583 
584 	i_zero(&info);
585 	info.service = master_service_get_name(master_service);
586 	info.local_ip = client->local_ip;
587 	info.real_local_ip = client->real_local_ip;
588 	info.remote_ip = client->remote_ip;
589 	info.real_remote_ip = client->real_remote_ip;
590 	info.local_port = client->local_port;
591 	info.real_local_port = client->real_local_port;
592 	info.remote_port = client->remote_port;
593 	info.real_remote_port = client->real_remote_port;
594 	info.forward_fields = lrcpt->forward_fields;
595 
596 	// FIXME: make this async
597 	auth_pool = pool_alloconly_create("auth lookup", 1024);
598 	auth_conn = mail_storage_service_get_auth_conn(storage_service);
599 	ret = auth_master_pass_lookup(auth_conn, username, &info,
600 				      auth_pool, &fields);
601 	if (ret <= 0) {
602 		errstr = (ret < 0 && fields[0] != NULL ?
603 			  t_strdup(fields[0]) :
604 			  "Temporary user lookup failure");
605 		pool_unref(&auth_pool);
606 		if (ret < 0) {
607 			smtp_server_recipient_reply(rcpt, 451, "4.3.0", "%s",
608 						    errstr);
609 			return -1;
610 		} else {
611 			/* User not found from passdb: revert to local delivery.
612 			 */
613 			return 0;
614 		}
615 	}
616 
617 	i_zero(&set);
618 	set.port = client->local_port;
619 	set.protocol = SMTP_PROTOCOL_LMTP;
620 	set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
621 
622 	if (!lmtp_proxy_rcpt_parse_fields(lrcpt, &set, fields, &username)) {
623 		/* Not proxying this user */
624 		pool_unref(&auth_pool);
625 		return 0;
626 	}
627 	if (strcmp(username, orig_username) != 0) {
628 		/* The existing "user" event field is overridden with the new
629 		   user name, while old username is available as "orig_user" */
630 		event_add_str(rcpt->event, "user", username);
631 		event_add_str(rcpt->event, "original_user", orig_username);
632 
633 		if (smtp_address_parse_username(pool_datastack_create(),
634 						username, &user, &errstr) < 0) {
635 			e_error(rcpt->event, "%s: "
636 				"Username `%s' returned by passdb lookup is not a valid SMTP address",
637 				orig_username, username);
638 			smtp_server_recipient_reply(
639 				rcpt, 550, "5.3.5",
640 				"Internal user lookup failure");
641 			pool_unref(&auth_pool);
642 			return -1;
643 		}
644 		/* Username changed. change the address as well */
645 		if (*detail == '\0') {
646 			address = user;
647 		} else {
648 			address = smtp_address_add_detail_temp(
649 				user, detail, delim);
650 		}
651 	} else if (lmtp_proxy_is_ourself(client, &set)) {
652 		e_error(rcpt->event, "Proxying to <%s> loops to itself",
653 			username);
654 		smtp_server_recipient_reply(rcpt, 554, "5.4.6",
655 					    "Proxying loops to itself");
656 		pool_unref(&auth_pool);
657 		return -1;
658 	}
659 
660 	smtp_server_connection_get_proxy_data(cmd->conn, &proxy_data);
661 	if (proxy_data.ttl_plus_1 == 1) {
662 		e_error(rcpt->event,
663 			"Proxying to <%s> appears to be looping (TTL=0)",
664 			username);
665 		smtp_server_recipient_reply(rcpt, 554, "5.4.6",
666 					    "Proxying appears to be looping "
667 					    "(TTL=0)");
668 		pool_unref(&auth_pool);
669 		return -1;
670 	}
671 
672 	if (client->proxy == NULL)
673 		client->proxy = lmtp_proxy_init(client, trans);
674 
675 	conn = lmtp_proxy_get_connection(client->proxy, &set);
676 
677 	lprcpt = p_new(rcpt->pool, struct lmtp_proxy_recipient, 1);
678 	lprcpt->rcpt = lrcpt;
679 	lprcpt->address = smtp_address_clone(rcpt->pool, address);
680 	lprcpt->conn = conn;
681 
682 	lrcpt->type = LMTP_RECIPIENT_TYPE_PROXY;
683 	lrcpt->backend_context = lprcpt;
684 
685 	/* Copy forward fields returned from passdb */
686 	fwfields = NULL;
687 	for (const char *const *ptr = fields; *ptr != NULL; ptr++) {
688 		if (strncasecmp(*ptr, "forward_", 8) != 0)
689 			continue;
690 
691 		if (fwfields == NULL)
692 			fwfields = t_str_new(128);
693 		else
694 			str_append_c(fwfields, '\t');
695 
696 		str_append_tabescaped(fwfields, (*ptr) + 8);
697 	}
698 	if (fwfields != NULL) {
699 		lprcpt->forward_fields = p_memdup(
700 			rcpt->pool, str_data(fwfields), str_len(fwfields));
701 		lprcpt->forward_fields_size = str_len(fwfields);
702 	}
703 
704 	pool_unref(&auth_pool);
705 
706 	smtp_client_connection_connect(conn->lmtp_conn,
707 				       lmtp_proxy_rcpt_login_cb, lprcpt);
708 	return 1;
709 }
710 
711 /*
712  * DATA command
713  */
714 
715 static void
lmtp_proxy_data_cb(const struct smtp_reply * proxy_reply,struct lmtp_proxy_recipient * lprcpt)716 lmtp_proxy_data_cb(const struct smtp_reply *proxy_reply,
717 		   struct lmtp_proxy_recipient *lprcpt)
718 {
719 	struct lmtp_proxy_connection *conn = lprcpt->conn;
720 	struct smtp_server_recipient *rcpt = lprcpt->rcpt->rcpt;
721 	struct lmtp_proxy *proxy = conn->proxy;
722 	struct smtp_server_transaction *trans = proxy->trans;
723 	struct smtp_address *address = lprcpt->address;
724 	const struct smtp_client_transaction_times *times =
725 		smtp_client_transaction_get_times(conn->lmtp_trans);
726 	unsigned int rcpt_index = rcpt->index;
727 	struct smtp_reply reply;
728 	string_t *msg;
729 
730 	/* Compose log message */
731 	msg = t_str_new(128);
732 	str_printfa(msg, "%s: ", trans->id);
733 	if (smtp_reply_is_success(proxy_reply))
734 		str_append(msg, "Sent message to");
735 	else
736 		str_append(msg, "Failed to send message to");
737 	str_printfa(msg, " <%s> at %s:%u: %s (%u/%u at %u ms)",
738 		    smtp_address_encode(address),
739 		    conn->set.host, conn->set.port,
740 		    smtp_reply_log(proxy_reply),
741 		    rcpt_index + 1, array_count(&trans->rcpt_to),
742 		    timeval_diff_msecs(&ioloop_timeval, &times->started));
743 
744 	/* Handle reply */
745 	if (smtp_reply_is_success(proxy_reply)) {
746 		/* If backend accepts it, we accept it too */
747 		e_info(rcpt->event, "%s", str_c(msg));
748 
749 		/* Substitute our own success message */
750 		smtp_reply_printf(&reply, 250, "%s Saved", trans->id);
751 		/* Do let the enhanced code through */
752 		if (!smtp_reply_has_enhanced_code(proxy_reply))
753 			reply.enhanced_code = SMTP_REPLY_ENH_CODE(2, 0, 0);
754 		else
755 			reply.enhanced_code = proxy_reply->enhanced_code;
756 
757 	} else {
758 		if (smtp_reply_is_remote(proxy_reply)) {
759 			/* The problem isn't with the proxy, it's with the
760 			   remote side. so the remote side will log an error,
761 			   while for us this is just an info event */
762 			e_info(rcpt->event, "%s", str_c(msg));
763 		} else {
764 			e_error(rcpt->event, "%s", str_c(msg));
765 		}
766 
767 		if (!lmtp_proxy_handle_reply(lprcpt, proxy_reply, &reply))
768 			return;
769 	}
770 
771 	/* Forward reply */
772 	smtp_server_recipient_reply_forward(rcpt, &reply);
773 }
774 
775 static void
lmtp_proxy_data_dummy_cb(const struct smtp_reply * proxy_reply ATTR_UNUSED,struct lmtp_proxy_connection * conn ATTR_UNUSED)776 lmtp_proxy_data_dummy_cb(const struct smtp_reply *proxy_reply ATTR_UNUSED,
777 			 struct lmtp_proxy_connection *conn ATTR_UNUSED)
778 {
779 	/* nothing */
780 }
781 
lmtp_proxy_data(struct client * client,struct smtp_server_cmd_ctx * cmd ATTR_UNUSED,struct smtp_server_transaction * trans ATTR_UNUSED,struct istream * data_input)782 void lmtp_proxy_data(struct client *client,
783 		     struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
784 		     struct smtp_server_transaction *trans ATTR_UNUSED,
785 		     struct istream *data_input)
786 {
787 	struct lmtp_proxy *proxy = client->proxy;
788 	struct lmtp_proxy_connection *conn;
789 	uoff_t size;
790 
791 	i_assert(data_input->seekable);
792 	i_assert(proxy->data_input == NULL);
793 
794 	client_update_data_state(client, "proxying");
795 
796 	proxy->data_input = data_input;
797 	i_stream_ref(proxy->data_input);
798 	if (i_stream_get_size(proxy->data_input, TRUE, &size) < 0) {
799 		e_error(client->event,
800 			"i_stream_get_size(data_input) failed: %s",
801 			i_stream_get_error(proxy->data_input));
802 		size = UOFF_T_MAX;
803 	}
804 
805 	/* Create the data_input streams first */
806 	array_foreach_elem(&proxy->connections, conn) {
807 		if (conn->finished) {
808 			/* This connection had already failed */
809 			continue;
810 		}
811 
812 		if (size == UOFF_T_MAX) {
813 			conn->data_input =
814 				i_stream_create_limit(data_input, UOFF_T_MAX);
815 		} else {
816 			conn->data_input =
817 				i_stream_create_sized(data_input, size);
818 		}
819 	}
820 	/* Now that all the streams are created, start reading them
821 	   (reading them earlier could have caused the data_input parent's
822 	   offset to change) */
823 	array_foreach_elem(&proxy->connections, conn) {
824 		if (conn->finished) {
825 			/* This connection had already failed */
826 			continue;
827 		}
828 
829 		smtp_client_transaction_set_timeout(conn->lmtp_trans,
830 						    proxy->max_timeout_msecs);
831 		smtp_client_transaction_send(conn->lmtp_trans, conn->data_input,
832 					     lmtp_proxy_data_dummy_cb, conn);
833 	}
834 }
835