~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/login-common/login-proxy.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2004-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "login-common.h"
4
4
#include "ioloop.h"
5
5
#include "istream.h"
6
6
#include "ostream.h"
7
7
#include "llist.h"
 
8
#include "str.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"
49
48
 
50
49
        proxy_callback_t *callback;
51
50
 
 
51
        unsigned int connected:1;
52
52
        unsigned int destroying:1;
53
53
        unsigned int disconnecting:1;
54
54
};
61
61
static void login_proxy_ipc_cmd(struct ipc_cmd *cmd, const char *line);
62
62
 
63
63
static void
64
 
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason);
 
64
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason)
 
65
        ATTR_NULL(2);
65
66
 
66
67
static void login_proxy_free_errno(struct login_proxy **proxy,
67
68
                                   int err, const char *who)
77
78
static void server_input(struct login_proxy *proxy)
78
79
{
79
80
        unsigned char buf[OUTBUF_THRESHOLD];
80
 
        ssize_t ret;
 
81
        ssize_t ret, ret2;
81
82
 
82
83
        proxy->last_io = ioloop_time;
83
84
        if (o_stream_get_buffer_used_size(proxy->client_output) >
89
90
        }
90
91
 
91
92
        ret = net_receive(proxy->server_fd, buf, sizeof(buf));
92
 
        if (ret < 0)
 
93
        if (ret < 0) {
93
94
                login_proxy_free_errno(&proxy, errno, "server");
94
 
        else if (o_stream_send(proxy->client_output, buf, ret) != ret) {
 
95
                return;
 
96
        }
 
97
        o_stream_cork(proxy->client_output);
 
98
        ret2 = o_stream_send(proxy->client_output, buf, ret);
 
99
        o_stream_uncork(proxy->client_output);
 
100
        if (ret2 != ret) {
95
101
                login_proxy_free_errno(&proxy,
96
102
                                       proxy->client_output->stream_errno,
97
103
                                       "client");
101
107
static void proxy_client_input(struct login_proxy *proxy)
102
108
{
103
109
        unsigned char buf[OUTBUF_THRESHOLD];
104
 
        ssize_t ret;
 
110
        ssize_t ret, ret2;
105
111
 
106
112
        proxy->last_io = ioloop_time;
107
113
        if (o_stream_get_buffer_used_size(proxy->server_output) >
113
119
        }
114
120
 
115
121
        ret = net_receive(proxy->client_fd, buf, sizeof(buf));
116
 
        if (ret < 0)
 
122
        if (ret < 0) {
117
123
                login_proxy_free_errno(&proxy, errno, "client");
118
 
        else if (o_stream_send(proxy->server_output, buf, ret) != ret) {
 
124
                return;
 
125
        }
 
126
        o_stream_cork(proxy->client_output);
 
127
        ret2 = o_stream_send(proxy->server_output, buf, ret);
 
128
        o_stream_uncork(proxy->server_output);
 
129
        if (ret2 != ret) {
119
130
                login_proxy_free_errno(&proxy,
120
131
                                       proxy->server_output->stream_errno,
121
132
                                       "server");
176
187
                                   FALSE);
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);
179
191
 
180
192
        proxy->server_io =
181
193
                io_add(proxy->server_fd, IO_READ, proxy_prelogin_input, proxy);
194
206
        proxy->state_rec = NULL;
195
207
}
196
208
 
 
209
static void
 
210
proxy_log_connect_error(struct login_proxy *proxy)
 
211
{
 
212
        string_t *str = t_str_new(128);
 
213
        struct ip_addr local_ip;
 
214
        unsigned int local_port;
 
215
 
 
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);
 
220
        } else {
 
221
                str_printfa(str, "Login for %s:%u timed out in state=%u",
 
222
                            proxy->host, proxy->port,
 
223
                            proxy->client->proxy_state);
 
224
        }
 
225
        str_printfa(str, " (after %u secs",
 
226
                    (unsigned int)(ioloop_time - proxy->created.tv_sec));
 
227
 
 
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);
 
232
        }
 
233
 
 
234
        str_append_c(str, ')');
 
235
        i_error("%s", str_c(str));
 
236
}
 
237
 
197
238
static void proxy_wait_connect(struct login_proxy *proxy)
198
239
{
199
 
        int err;
200
 
 
201
 
        err = net_geterror(proxy->server_fd);
202
 
        if (err != 0) {
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);
 
241
        if (errno != 0) {
 
242
                proxy_log_connect_error(proxy);
207
243
                proxy_fail_connect(proxy);
208
244
                login_proxy_free(&proxy);
209
245
                return;
210
246
        }
 
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;
214
251
 
215
 
        if (proxy->to != NULL)
216
 
                timeout_remove(&proxy->to);
217
 
 
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) {
229
263
 
230
264
static void proxy_connect_timeout(struct login_proxy *proxy)
231
265
{
232
 
        i_error("proxy(%s): connect(%s, %u) timed out",
233
 
                proxy->client->virtual_user, proxy->host, proxy->port);
234
 
        proxy_fail_connect(proxy);
 
266
        errno = ETIMEDOUT;
 
267
        proxy_log_connect_error(proxy);
 
268
        if (!proxy->connected)
 
269
                proxy_fail_connect(proxy);
235
270
        login_proxy_free(&proxy);
236
271
}
237
272
 
252
287
 
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);
258
292
                return -1;
259
293
        }
269
303
        return 0;
270
304
}
271
305
 
272
 
static void login_proxy_dns_done(const struct dns_lookup_result *result,
273
 
                                 struct login_proxy *proxy)
274
 
{
275
 
        if (result->ret != 0) {
276
 
                i_error("proxy(%s): DNS lookup of %s failed: %s",
277
 
                        proxy->client->virtual_user, proxy->host,
278
 
                        result->error);
279
 
                login_proxy_free(&proxy);
280
 
        } else {
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);
285
 
                }
286
 
 
287
 
                proxy->ip = result->ips[0];
288
 
                (void)login_proxy_connect(proxy);
289
 
        }
290
 
}
291
 
 
292
306
int login_proxy_new(struct client *client,
293
307
                    const struct login_proxy_settings *set,
294
308
                    proxy_callback_t *callback)
295
309
{
296
310
        struct login_proxy *proxy;
297
 
        struct dns_lookup_settings dns_lookup_set;
298
311
 
299
312
        i_assert(client->login_proxy == NULL);
300
313
 
303
316
                return -1;
304
317
        }
305
318
 
 
319
        if (client->proxy_ttl <= 1) {
 
320
                i_error("proxy(%s): TTL reached zero - "
 
321
                        "proxies appear to be looping?", client->virtual_user);
 
322
                return -1;
 
323
        }
 
324
 
306
325
        proxy = i_new(struct login_proxy, 1);
307
326
        proxy->client = client;
308
327
        proxy->client_fd = -1;
316
335
        proxy->ssl_flags = set->ssl_flags;
317
336
        client_ref(client);
318
337
 
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;
322
 
 
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)
327
 
                        return -1;
 
340
                i_error("proxy(%s): BUG: host %s is not an IP "
 
341
                        "(auth should have changed it)",
 
342
                        client->virtual_user, set->host);
328
343
        } else {
329
344
                if (login_proxy_connect(proxy) < 0)
330
345
                        return -1;
337
352
        return 0;
338
353
}
339
354
 
340
 
static void
 
355
static void ATTR_NULL(2)
341
356
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason)
342
357
{
343
358
        struct login_proxy *proxy = *_proxy;
466
481
        i_assert(proxy->client_fd == -1);
467
482
        i_assert(proxy->server_output != NULL);
468
483
 
 
484
        if (proxy->to != NULL)
 
485
                timeout_remove(&proxy->to);
 
486
 
469
487
        proxy->client_fd = i_stream_get_fd(client->input);
470
488
        proxy->client_output = client->output;
471
489
 
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);
478
496
        if (size != 0)
479
 
                (void)o_stream_send(proxy->server_output, data, size);
 
497
                o_stream_nsend(proxy->server_output, data, size);
480
498
 
481
499
        /* from now on, just do dummy proxying */
482
500
        io_remove(&proxy->server_io);
549
567
 
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);
554
573
        if (fd < 0) {