1
/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
1
/* Copyright (c) 2004-2013 Dovecot authors, see the included COPYING file */
3
3
#include "login-common.h"
8
9
#include "str-sanitize.h"
9
10
#include "time-util.h"
10
11
#include "master-service.h"
11
12
#include "ipc-server.h"
12
#include "dns-lookup.h"
13
13
#include "mail-user-hash.h"
14
14
#include "client-common.h"
15
15
#include "ssl-proxy.h"
19
19
#define MAX_PROXY_INPUT_SIZE 4096
20
20
#define OUTBUF_THRESHOLD 1024
21
21
#define LOGIN_PROXY_DIE_IDLE_SECS 2
22
#define LOGIN_PROXY_DNS_WARN_MSECS 500
23
22
#define LOGIN_PROXY_IPC_PATH "ipc-proxy"
24
23
#define LOGIN_PROXY_IPC_NAME "proxy"
25
24
#define KILLED_BY_ADMIN_REASON "Killed by admin"
61
61
static void login_proxy_ipc_cmd(struct ipc_cmd *cmd, const char *line);
64
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason);
64
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason)
66
67
static void login_proxy_free_errno(struct login_proxy **proxy,
67
68
int err, const char *who)
91
92
ret = net_receive(proxy->server_fd, buf, sizeof(buf));
93
94
login_proxy_free_errno(&proxy, errno, "server");
94
else if (o_stream_send(proxy->client_output, buf, ret) != ret) {
97
o_stream_cork(proxy->client_output);
98
ret2 = o_stream_send(proxy->client_output, buf, ret);
99
o_stream_uncork(proxy->client_output);
95
101
login_proxy_free_errno(&proxy,
96
102
proxy->client_output->stream_errno,
115
121
ret = net_receive(proxy->client_fd, buf, sizeof(buf));
117
123
login_proxy_free_errno(&proxy, errno, "client");
118
else if (o_stream_send(proxy->server_output, buf, ret) != ret) {
126
o_stream_cork(proxy->client_output);
127
ret2 = o_stream_send(proxy->server_output, buf, ret);
128
o_stream_uncork(proxy->server_output);
119
130
login_proxy_free_errno(&proxy,
120
131
proxy->server_output->stream_errno,
177
188
proxy->server_output =
178
189
o_stream_create_fd(proxy->server_fd, (size_t)-1, FALSE);
190
o_stream_set_no_error_handling(proxy->server_output, TRUE);
180
192
proxy->server_io =
181
193
io_add(proxy->server_fd, IO_READ, proxy_prelogin_input, proxy);
194
206
proxy->state_rec = NULL;
210
proxy_log_connect_error(struct login_proxy *proxy)
212
string_t *str = t_str_new(128);
213
struct ip_addr local_ip;
214
unsigned int local_port;
216
str_printfa(str, "proxy(%s): ", proxy->client->virtual_user);
217
if (!proxy->connected) {
218
str_printfa(str, "connect(%s, %u) failed: %m",
219
proxy->host, proxy->port);
221
str_printfa(str, "Login for %s:%u timed out in state=%u",
222
proxy->host, proxy->port,
223
proxy->client->proxy_state);
225
str_printfa(str, " (after %u secs",
226
(unsigned int)(ioloop_time - proxy->created.tv_sec));
228
if (proxy->server_fd != -1 &&
229
net_getsockname(proxy->server_fd, &local_ip, &local_port) == 0) {
230
str_printfa(str, ", local=%s:%u",
231
net_ip2addr(&local_ip), local_port);
234
str_append_c(str, ')');
235
i_error("%s", str_c(str));
197
238
static void proxy_wait_connect(struct login_proxy *proxy)
201
err = net_geterror(proxy->server_fd);
203
i_error("proxy(%s): connect(%s, %u) failed: %s (after %u secs)",
204
proxy->client->virtual_user,
205
proxy->host, proxy->port, strerror(err),
206
(unsigned int)(ioloop_time - proxy->created.tv_sec));
240
errno = net_geterror(proxy->server_fd);
242
proxy_log_connect_error(proxy);
207
243
proxy_fail_connect(proxy);
208
244
login_proxy_free(&proxy);
247
proxy->connected = TRUE;
211
248
proxy->state_rec->last_success = ioloop_timeval;
212
249
proxy->state_rec->num_waiting_connections--;
213
250
proxy->state_rec = NULL;
215
if (proxy->to != NULL)
216
timeout_remove(&proxy->to);
218
252
if ((proxy->ssl_flags & PROXY_SSL_FLAG_YES) != 0 &&
219
253
(proxy->ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
220
254
if (login_proxy_starttls(proxy) < 0) {
230
264
static void proxy_connect_timeout(struct login_proxy *proxy)
232
i_error("proxy(%s): connect(%s, %u) timed out",
233
proxy->client->virtual_user, proxy->host, proxy->port);
234
proxy_fail_connect(proxy);
267
proxy_log_connect_error(proxy);
268
if (!proxy->connected)
269
proxy_fail_connect(proxy);
235
270
login_proxy_free(&proxy);
253
288
proxy->server_fd = net_connect_ip(&proxy->ip, proxy->port, NULL);
254
289
if (proxy->server_fd == -1) {
255
i_error("proxy(%s): connect(%s, %u) failed: %m",
256
proxy->client->virtual_user, proxy->host, proxy->port);
290
proxy_log_connect_error(proxy);
257
291
login_proxy_free(&proxy);
272
static void login_proxy_dns_done(const struct dns_lookup_result *result,
273
struct login_proxy *proxy)
275
if (result->ret != 0) {
276
i_error("proxy(%s): DNS lookup of %s failed: %s",
277
proxy->client->virtual_user, proxy->host,
279
login_proxy_free(&proxy);
281
if (result->msecs > LOGIN_PROXY_DNS_WARN_MSECS) {
282
i_warning("proxy(%s): DNS lookup for %s took %u.%03u s",
283
proxy->client->virtual_user, proxy->host,
284
result->msecs/1000, result->msecs % 1000);
287
proxy->ip = result->ips[0];
288
(void)login_proxy_connect(proxy);
292
306
int login_proxy_new(struct client *client,
293
307
const struct login_proxy_settings *set,
294
308
proxy_callback_t *callback)
296
310
struct login_proxy *proxy;
297
struct dns_lookup_settings dns_lookup_set;
299
312
i_assert(client->login_proxy == NULL);
316
335
proxy->ssl_flags = set->ssl_flags;
317
336
client_ref(client);
319
memset(&dns_lookup_set, 0, sizeof(dns_lookup_set));
320
dns_lookup_set.dns_client_socket_path = set->dns_client_socket_path;
321
dns_lookup_set.timeout_msecs = set->connect_timeout_msecs;
323
338
if (set->ip.family == 0 &&
324
339
net_addr2ip(set->host, &proxy->ip) < 0) {
325
if (dns_lookup(set->host, &dns_lookup_set,
326
login_proxy_dns_done, proxy) < 0)
340
i_error("proxy(%s): BUG: host %s is not an IP "
341
"(auth should have changed it)",
342
client->virtual_user, set->host);
329
344
if (login_proxy_connect(proxy) < 0)
476
494
/* send all pending client input to proxy and get rid of the stream */
477
495
data = i_stream_get_data(client->input, &size);
479
(void)o_stream_send(proxy->server_output, data, size);
497
o_stream_nsend(proxy->server_output, data, size);
481
499
/* from now on, just do dummy proxying */
482
500
io_remove(&proxy->server_io);
550
568
fd = ssl_proxy_client_alloc(proxy->server_fd, &proxy->client->ip,
551
569
proxy->client->pool, proxy->client->set,
570
proxy->client->ssl_set,
552
571
login_proxy_ssl_handshaked, proxy,
553
572
&proxy->ssl_server_proxy);