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, ×->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