~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to .pc/CVE-2011-4318.patch/src/login-common/login-proxy.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-12-08 14:34:36 UTC
  • Revision ID: package-import@ubuntu.com-20111208143436-9scnmh9l46vo9opk
Tags: 1:2.0.15-1ubuntu5
* SECURITY UPDATE: Incorrect cert Common Name verification when proxying
  - debian/patches/CVE-2011-4318.patch: correctly validate Common Name
    when a hostname is specified in src/login-common/{login-proxy.c,
    ssl-proxy.*,ssl-proxy-openssl.c}.
  - CVE-2011-4318

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2004-2011 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "login-common.h"
 
4
#include "ioloop.h"
 
5
#include "istream.h"
 
6
#include "ostream.h"
 
7
#include "llist.h"
 
8
#include "md5.h"
 
9
#include "str-sanitize.h"
 
10
#include "time-util.h"
 
11
#include "master-service.h"
 
12
#include "ipc-server.h"
 
13
#include "dns-lookup.h"
 
14
#include "client-common.h"
 
15
#include "ssl-proxy.h"
 
16
#include "login-proxy-state.h"
 
17
#include "login-proxy.h"
 
18
 
 
19
#define MAX_PROXY_INPUT_SIZE 4096
 
20
#define OUTBUF_THRESHOLD 1024
 
21
#define LOGIN_PROXY_DIE_IDLE_SECS 2
 
22
#define LOGIN_PROXY_DNS_WARN_MSECS 500
 
23
#define LOGIN_PROXY_IPC_PATH "ipc-proxy"
 
24
#define LOGIN_PROXY_IPC_NAME "proxy"
 
25
#define KILLED_BY_ADMIN_REASON "Killed by admin"
 
26
 
 
27
struct login_proxy {
 
28
        struct login_proxy *prev, *next;
 
29
 
 
30
        struct client *client;
 
31
        int client_fd, server_fd;
 
32
        struct io *client_io, *server_io;
 
33
        struct istream *server_input;
 
34
        struct ostream *client_output, *server_output;
 
35
        struct ssl_proxy *ssl_server_proxy;
 
36
        time_t last_io;
 
37
 
 
38
        struct timeval created;
 
39
        struct timeout *to, *to_notify;
 
40
        struct login_proxy_record *state_rec;
 
41
 
 
42
        struct ip_addr ip;
 
43
        char *host;
 
44
        unsigned int port;
 
45
        unsigned int connect_timeout_msecs;
 
46
        unsigned int notify_refresh_secs;
 
47
        enum login_proxy_ssl_flags ssl_flags;
 
48
 
 
49
        proxy_callback_t *callback;
 
50
 
 
51
        unsigned int destroying:1;
 
52
        unsigned int disconnecting:1;
 
53
};
 
54
 
 
55
static struct login_proxy_state *proxy_state;
 
56
static struct login_proxy *login_proxies = NULL;
 
57
static struct login_proxy *login_proxies_pending = NULL;
 
58
static struct ipc_server *login_proxy_ipc_server;
 
59
 
 
60
static void login_proxy_ipc_cmd(struct ipc_cmd *cmd, const char *line);
 
61
 
 
62
static void
 
63
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason);
 
64
 
 
65
static void login_proxy_free_errno(struct login_proxy **proxy,
 
66
                                   int err, const char *who)
 
67
{
 
68
        const char *reason;
 
69
 
 
70
        reason = err == 0 || err == EPIPE ?
 
71
                t_strdup_printf("Disconnected by %s", who) :
 
72
                t_strdup_printf("Disconnected by %s: %s", who, strerror(errno));
 
73
        login_proxy_free_reason(proxy, reason);
 
74
}
 
75
 
 
76
static void server_input(struct login_proxy *proxy)
 
77
{
 
78
        unsigned char buf[OUTBUF_THRESHOLD];
 
79
        ssize_t ret;
 
80
 
 
81
        proxy->last_io = ioloop_time;
 
82
        if (o_stream_get_buffer_used_size(proxy->client_output) >
 
83
            OUTBUF_THRESHOLD) {
 
84
                /* client's output buffer is already quite full.
 
85
                   don't send more until we're below threshold. */
 
86
                io_remove(&proxy->server_io);
 
87
                return;
 
88
        }
 
89
 
 
90
        ret = net_receive(proxy->server_fd, buf, sizeof(buf));
 
91
        if (ret < 0)
 
92
                login_proxy_free_errno(&proxy, errno, "server");
 
93
        else if (o_stream_send(proxy->client_output, buf, ret) != ret) {
 
94
                login_proxy_free_errno(&proxy,
 
95
                                       proxy->client_output->stream_errno,
 
96
                                       "client");
 
97
        }
 
98
}
 
99
 
 
100
static void proxy_client_input(struct login_proxy *proxy)
 
101
{
 
102
        unsigned char buf[OUTBUF_THRESHOLD];
 
103
        ssize_t ret;
 
104
 
 
105
        proxy->last_io = ioloop_time;
 
106
        if (o_stream_get_buffer_used_size(proxy->server_output) >
 
107
            OUTBUF_THRESHOLD) {
 
108
                /* proxy's output buffer is already quite full.
 
109
                   don't send more until we're below threshold. */
 
110
                io_remove(&proxy->client_io);
 
111
                return;
 
112
        }
 
113
 
 
114
        ret = net_receive(proxy->client_fd, buf, sizeof(buf));
 
115
        if (ret < 0)
 
116
                login_proxy_free_errno(&proxy, errno, "client");
 
117
        else if (o_stream_send(proxy->server_output, buf, ret) != ret) {
 
118
                login_proxy_free_errno(&proxy,
 
119
                                       proxy->server_output->stream_errno,
 
120
                                       "server");
 
121
        }
 
122
}
 
123
 
 
124
static int server_output(struct login_proxy *proxy)
 
125
{
 
126
        proxy->last_io = ioloop_time;
 
127
        if (o_stream_flush(proxy->server_output) < 0) {
 
128
                login_proxy_free_errno(&proxy,
 
129
                                       proxy->server_output->stream_errno,
 
130
                                       "server");
 
131
                return 1;
 
132
        }
 
133
 
 
134
        if (proxy->client_io == NULL &&
 
135
            o_stream_get_buffer_used_size(proxy->server_output) <
 
136
            OUTBUF_THRESHOLD) {
 
137
                /* there's again space in proxy's output buffer, so we can
 
138
                   read more from client. */
 
139
                proxy->client_io = io_add(proxy->client_fd, IO_READ,
 
140
                                          proxy_client_input, proxy);
 
141
        }
 
142
        return 1;
 
143
}
 
144
 
 
145
static int proxy_client_output(struct login_proxy *proxy)
 
146
{
 
147
        proxy->last_io = ioloop_time;
 
148
        if (o_stream_flush(proxy->client_output) < 0) {
 
149
                login_proxy_free_errno(&proxy,
 
150
                                       proxy->client_output->stream_errno,
 
151
                                       "client");
 
152
                return 1;
 
153
        }
 
154
 
 
155
        if (proxy->server_io == NULL &&
 
156
            o_stream_get_buffer_used_size(proxy->client_output) <
 
157
            OUTBUF_THRESHOLD) {
 
158
                /* there's again space in client's output buffer, so we can
 
159
                   read more from proxy. */
 
160
                proxy->server_io =
 
161
                        io_add(proxy->server_fd, IO_READ, server_input, proxy);
 
162
        }
 
163
        return 1;
 
164
}
 
165
 
 
166
static void proxy_prelogin_input(struct login_proxy *proxy)
 
167
{
 
168
        proxy->callback(proxy->client);
 
169
}
 
170
 
 
171
static void proxy_plain_connected(struct login_proxy *proxy)
 
172
{
 
173
        proxy->server_input =
 
174
                i_stream_create_fd(proxy->server_fd, MAX_PROXY_INPUT_SIZE,
 
175
                                   FALSE);
 
176
        proxy->server_output =
 
177
                o_stream_create_fd(proxy->server_fd, (size_t)-1, FALSE);
 
178
 
 
179
        proxy->server_io =
 
180
                io_add(proxy->server_fd, IO_READ, proxy_prelogin_input, proxy);
 
181
}
 
182
 
 
183
static void proxy_fail_connect(struct login_proxy *proxy)
 
184
{
 
185
        if (timeval_cmp(&proxy->created, &proxy->state_rec->last_success) < 0) {
 
186
                /* there was a successful connection done since we started
 
187
                   connecting. perhaps this is just a temporary one-off
 
188
                   failure. */
 
189
        } else {
 
190
                proxy->state_rec->last_failure = ioloop_timeval;
 
191
        }
 
192
        proxy->state_rec->num_waiting_connections--;
 
193
        proxy->state_rec = NULL;
 
194
}
 
195
 
 
196
static void proxy_wait_connect(struct login_proxy *proxy)
 
197
{
 
198
        int err;
 
199
 
 
200
        err = net_geterror(proxy->server_fd);
 
201
        if (err != 0) {
 
202
                i_error("proxy: connect(%s, %u) failed: %s",
 
203
                        proxy->host, proxy->port, strerror(err));
 
204
                proxy_fail_connect(proxy);
 
205
                login_proxy_free(&proxy);
 
206
                return;
 
207
        }
 
208
        proxy->state_rec->last_success = ioloop_timeval;
 
209
        proxy->state_rec->num_waiting_connections--;
 
210
        proxy->state_rec = NULL;
 
211
 
 
212
        if (proxy->to != NULL)
 
213
                timeout_remove(&proxy->to);
 
214
 
 
215
        if ((proxy->ssl_flags & PROXY_SSL_FLAG_YES) != 0 &&
 
216
            (proxy->ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
 
217
                if (login_proxy_starttls(proxy) < 0) {
 
218
                        login_proxy_free(&proxy);
 
219
                        return;
 
220
                }
 
221
        } else {
 
222
                io_remove(&proxy->server_io);
 
223
                proxy_plain_connected(proxy);
 
224
        }
 
225
}
 
226
 
 
227
static void proxy_connect_timeout(struct login_proxy *proxy)
 
228
{
 
229
        i_error("proxy: connect(%s, %u) timed out", proxy->host, proxy->port);
 
230
        proxy_fail_connect(proxy);
 
231
        login_proxy_free(&proxy);
 
232
}
 
233
 
 
234
static int login_proxy_connect(struct login_proxy *proxy)
 
235
{
 
236
        struct login_proxy_record *rec;
 
237
 
 
238
        rec = login_proxy_state_get(proxy_state, &proxy->ip, proxy->port);
 
239
        if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 &&
 
240
            rec->num_waiting_connections != 0) {
 
241
                /* the server is down. fail immediately */
 
242
                i_error("proxy(%s): Host %s:%u is down",
 
243
                        proxy->client->virtual_user, proxy->host, proxy->port);
 
244
                login_proxy_free(&proxy);
 
245
                return -1;
 
246
        }
 
247
 
 
248
        proxy->server_fd = net_connect_ip(&proxy->ip, proxy->port, NULL);
 
249
        if (proxy->server_fd == -1) {
 
250
                i_error("proxy(%s): connect(%s, %u) failed: %m",
 
251
                        proxy->client->virtual_user, proxy->host, proxy->port);
 
252
                login_proxy_free(&proxy);
 
253
                return -1;
 
254
        }
 
255
        proxy->server_io = io_add(proxy->server_fd, IO_WRITE,
 
256
                                  proxy_wait_connect, proxy);
 
257
        if (proxy->connect_timeout_msecs != 0) {
 
258
                proxy->to = timeout_add(proxy->connect_timeout_msecs,
 
259
                                        proxy_connect_timeout, proxy);
 
260
        }
 
261
 
 
262
        proxy->state_rec = rec;
 
263
        proxy->state_rec->num_waiting_connections++;
 
264
        return 0;
 
265
}
 
266
 
 
267
static void login_proxy_dns_done(const struct dns_lookup_result *result,
 
268
                                 struct login_proxy *proxy)
 
269
{
 
270
        if (result->ret != 0) {
 
271
                i_error("proxy(%s): DNS lookup of %s failed: %s",
 
272
                        proxy->client->virtual_user, proxy->host,
 
273
                        result->error);
 
274
                login_proxy_free(&proxy);
 
275
        } else {
 
276
                if (result->msecs > LOGIN_PROXY_DNS_WARN_MSECS) {
 
277
                        i_warning("proxy(%s): DNS lookup for %s took %u.%03u s",
 
278
                                  proxy->client->virtual_user, proxy->host,
 
279
                                  result->msecs/1000, result->msecs % 1000);
 
280
                }
 
281
 
 
282
                proxy->ip = result->ips[0];
 
283
                (void)login_proxy_connect(proxy);
 
284
        }
 
285
}
 
286
 
 
287
int login_proxy_new(struct client *client,
 
288
                    const struct login_proxy_settings *set,
 
289
                    proxy_callback_t *callback)
 
290
{
 
291
        struct login_proxy *proxy;
 
292
        struct dns_lookup_settings dns_lookup_set;
 
293
 
 
294
        i_assert(client->login_proxy == NULL);
 
295
 
 
296
        if (set->host == NULL || *set->host == '\0') {
 
297
                i_error("proxy(%s): host not given", client->virtual_user);
 
298
                return -1;
 
299
        }
 
300
 
 
301
        proxy = i_new(struct login_proxy, 1);
 
302
        proxy->client = client;
 
303
        proxy->client_fd = -1;
 
304
        proxy->server_fd = -1;
 
305
        proxy->created = ioloop_timeval;
 
306
        proxy->host = i_strdup(set->host);
 
307
        proxy->port = set->port;
 
308
        proxy->connect_timeout_msecs = set->connect_timeout_msecs;
 
309
        proxy->notify_refresh_secs = set->notify_refresh_secs;
 
310
        proxy->ssl_flags = set->ssl_flags;
 
311
        client_ref(client);
 
312
 
 
313
        memset(&dns_lookup_set, 0, sizeof(dns_lookup_set));
 
314
        dns_lookup_set.dns_client_socket_path = set->dns_client_socket_path;
 
315
        dns_lookup_set.timeout_msecs = set->connect_timeout_msecs;
 
316
 
 
317
        if (net_addr2ip(set->host, &proxy->ip) < 0) {
 
318
                if (dns_lookup(set->host, &dns_lookup_set,
 
319
                               login_proxy_dns_done, proxy) < 0)
 
320
                        return -1;
 
321
        } else {
 
322
                if (login_proxy_connect(proxy) < 0)
 
323
                        return -1;
 
324
        }
 
325
 
 
326
        DLLIST_PREPEND(&login_proxies_pending, proxy);
 
327
 
 
328
        proxy->callback = callback;
 
329
        client->login_proxy = proxy;
 
330
        return 0;
 
331
}
 
332
 
 
333
static void
 
334
login_proxy_free_reason(struct login_proxy **_proxy, const char *reason)
 
335
{
 
336
        struct login_proxy *proxy = *_proxy;
 
337
        struct client *client = proxy->client;
 
338
        const char *ipstr;
 
339
 
 
340
        *_proxy = NULL;
 
341
 
 
342
        if (proxy->destroying)
 
343
                return;
 
344
        proxy->destroying = TRUE;
 
345
 
 
346
        if (proxy->to != NULL)
 
347
                timeout_remove(&proxy->to);
 
348
        if (proxy->to_notify != NULL)
 
349
                timeout_remove(&proxy->to_notify);
 
350
 
 
351
        if (proxy->state_rec != NULL)
 
352
                proxy->state_rec->num_waiting_connections--;
 
353
        if (proxy->to != NULL)
 
354
                timeout_remove(&proxy->to);
 
355
 
 
356
        if (proxy->server_io != NULL)
 
357
                io_remove(&proxy->server_io);
 
358
        if (proxy->server_input != NULL)
 
359
                i_stream_destroy(&proxy->server_input);
 
360
        if (proxy->server_output != NULL)
 
361
                o_stream_destroy(&proxy->server_output);
 
362
 
 
363
        if (proxy->client_fd != -1) {
 
364
                /* detached proxy */
 
365
                DLLIST_REMOVE(&login_proxies, proxy);
 
366
 
 
367
                ipstr = net_ip2addr(&proxy->client->ip);
 
368
                i_info("proxy(%s): disconnecting %s%s",
 
369
                       proxy->client->virtual_user,
 
370
                       ipstr != NULL ? ipstr : "",
 
371
                       reason == NULL ? "" : t_strdup_printf(" (%s)", reason));
 
372
 
 
373
                if (proxy->client_io != NULL)
 
374
                        io_remove(&proxy->client_io);
 
375
                if (proxy->client_output != NULL)
 
376
                        o_stream_destroy(&proxy->client_output);
 
377
                net_disconnect(proxy->client_fd);
 
378
        } else {
 
379
                i_assert(proxy->client_io == NULL);
 
380
                i_assert(proxy->client_output == NULL);
 
381
 
 
382
                DLLIST_REMOVE(&login_proxies_pending, proxy);
 
383
 
 
384
                if (proxy->callback != NULL)
 
385
                        proxy->callback(proxy->client);
 
386
        }
 
387
 
 
388
        if (proxy->server_fd != -1)
 
389
                net_disconnect(proxy->server_fd);
 
390
 
 
391
        if (proxy->ssl_server_proxy != NULL)
 
392
                ssl_proxy_free(&proxy->ssl_server_proxy);
 
393
        i_free(proxy->host);
 
394
        i_free(proxy);
 
395
 
 
396
        client->login_proxy = NULL;
 
397
        client_unref(&client);
 
398
}
 
399
 
 
400
void login_proxy_free(struct login_proxy **_proxy)
 
401
{
 
402
        login_proxy_free_reason(_proxy, NULL);
 
403
}
 
404
 
 
405
bool login_proxy_is_ourself(const struct client *client, const char *host,
 
406
                            unsigned int port, const char *destuser)
 
407
{
 
408
        struct ip_addr ip;
 
409
 
 
410
        if (port != client->local_port)
 
411
                return FALSE;
 
412
 
 
413
        if (net_addr2ip(host, &ip) < 0)
 
414
                return FALSE;
 
415
        if (!net_ip_compare(&ip, &client->local_ip))
 
416
                return FALSE;
 
417
 
 
418
        return strcmp(client->virtual_user, destuser) == 0;
 
419
}
 
420
 
 
421
struct istream *login_proxy_get_istream(struct login_proxy *proxy)
 
422
{
 
423
        return proxy->disconnecting ? NULL : proxy->server_input;
 
424
}
 
425
 
 
426
struct ostream *login_proxy_get_ostream(struct login_proxy *proxy)
 
427
{
 
428
        return proxy->server_output;
 
429
}
 
430
 
 
431
const char *login_proxy_get_host(const struct login_proxy *proxy)
 
432
{
 
433
        return proxy->host;
 
434
}
 
435
 
 
436
unsigned int login_proxy_get_port(const struct login_proxy *proxy)
 
437
{
 
438
        return proxy->port;
 
439
}
 
440
 
 
441
enum login_proxy_ssl_flags
 
442
login_proxy_get_ssl_flags(const struct login_proxy *proxy)
 
443
{
 
444
        return proxy->ssl_flags;
 
445
}
 
446
 
 
447
static void login_proxy_notify(struct login_proxy *proxy)
 
448
{
 
449
        login_proxy_state_notify(proxy_state, proxy->client->proxy_user);
 
450
}
 
451
 
 
452
void login_proxy_detach(struct login_proxy *proxy)
 
453
{
 
454
        struct client *client = proxy->client;
 
455
        const unsigned char *data;
 
456
        size_t size;
 
457
 
 
458
        i_assert(proxy->client_fd == -1);
 
459
        i_assert(proxy->server_output != NULL);
 
460
 
 
461
        proxy->client_fd = i_stream_get_fd(client->input);
 
462
        proxy->client_output = client->output;
 
463
 
 
464
        o_stream_set_max_buffer_size(client->output, (size_t)-1);
 
465
        o_stream_set_flush_callback(client->output, proxy_client_output, proxy);
 
466
        client->output = NULL;
 
467
 
 
468
        /* send all pending client input to proxy and get rid of the stream */
 
469
        data = i_stream_get_data(client->input, &size);
 
470
        if (size != 0)
 
471
                (void)o_stream_send(proxy->server_output, data, size);
 
472
 
 
473
        /* from now on, just do dummy proxying */
 
474
        io_remove(&proxy->server_io);
 
475
        proxy->server_io =
 
476
                io_add(proxy->server_fd, IO_READ, server_input, proxy);
 
477
        proxy->client_io =
 
478
                io_add(proxy->client_fd, IO_READ, proxy_client_input, proxy);
 
479
        o_stream_set_flush_callback(proxy->server_output, server_output, proxy);
 
480
        i_stream_destroy(&proxy->server_input);
 
481
 
 
482
        if (proxy->notify_refresh_secs != 0) {
 
483
                proxy->to_notify =
 
484
                        timeout_add(proxy->notify_refresh_secs * 1000,
 
485
                                    login_proxy_notify, proxy);
 
486
        }
 
487
 
 
488
        proxy->callback = NULL;
 
489
 
 
490
        if (login_proxy_ipc_server == NULL) {
 
491
                login_proxy_ipc_server =
 
492
                        ipc_server_init(LOGIN_PROXY_IPC_PATH,
 
493
                                        LOGIN_PROXY_IPC_NAME,
 
494
                                        login_proxy_ipc_cmd);
 
495
        }
 
496
 
 
497
        DLLIST_REMOVE(&login_proxies_pending, proxy);
 
498
        DLLIST_PREPEND(&login_proxies, proxy);
 
499
 
 
500
        client->fd = -1;
 
501
        client->login_proxy = NULL;
 
502
}
 
503
 
 
504
static int login_proxy_ssl_handshaked(void *context)
 
505
{
 
506
        struct login_proxy *proxy = context;
 
507
 
 
508
        if ((proxy->ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0 ||
 
509
            ssl_proxy_has_valid_client_cert(proxy->ssl_server_proxy))
 
510
                return 0;
 
511
 
 
512
        if (!ssl_proxy_has_broken_client_cert(proxy->ssl_server_proxy)) {
 
513
                client_log_err(proxy->client, t_strdup_printf(
 
514
                        "proxy: SSL certificate not received from %s:%u",
 
515
                        proxy->host, proxy->port));
 
516
        } else {
 
517
                client_log_err(proxy->client, t_strdup_printf(
 
518
                        "proxy: Received invalid SSL certificate from %s:%u",
 
519
                        proxy->host, proxy->port));
 
520
        }
 
521
        proxy->disconnecting = TRUE;
 
522
        return -1;
 
523
}
 
524
 
 
525
int login_proxy_starttls(struct login_proxy *proxy)
 
526
{
 
527
        int fd;
 
528
 
 
529
        if (proxy->server_input != NULL)
 
530
                i_stream_destroy(&proxy->server_input);
 
531
        if (proxy->server_output != NULL)
 
532
                o_stream_destroy(&proxy->server_output);
 
533
        io_remove(&proxy->server_io);
 
534
 
 
535
        fd = ssl_proxy_client_alloc(proxy->server_fd, &proxy->client->ip,
 
536
                                    proxy->client->set,
 
537
                                    login_proxy_ssl_handshaked, proxy,
 
538
                                    &proxy->ssl_server_proxy);
 
539
        if (fd < 0) {
 
540
                client_log_err(proxy->client, t_strdup_printf(
 
541
                        "proxy: SSL handshake failed to %s:%u",
 
542
                        proxy->host, proxy->port));
 
543
                return -1;
 
544
        }
 
545
        ssl_proxy_set_client(proxy->ssl_server_proxy, proxy->client);
 
546
        ssl_proxy_start(proxy->ssl_server_proxy);
 
547
 
 
548
        proxy->server_fd = fd;
 
549
        proxy_plain_connected(proxy);
 
550
        return 0;
 
551
}
 
552
 
 
553
static void proxy_kill_idle(struct login_proxy *proxy)
 
554
{
 
555
        login_proxy_free_reason(&proxy, KILLED_BY_ADMIN_REASON);
 
556
}
 
557
 
 
558
void login_proxy_kill_idle(void)
 
559
{
 
560
        struct login_proxy *proxy, *next;
 
561
        time_t now = time(NULL);
 
562
        time_t stop_timestamp = now - LOGIN_PROXY_DIE_IDLE_SECS;
 
563
        unsigned int stop_msecs;
 
564
 
 
565
        for (proxy = login_proxies; proxy != NULL; proxy = next) {
 
566
                next = proxy->next;
 
567
 
 
568
                if (proxy->last_io <= stop_timestamp)
 
569
                        proxy_kill_idle(proxy);
 
570
                else {
 
571
                        i_assert(proxy->to == NULL);
 
572
                        stop_msecs = (proxy->last_io - stop_timestamp) * 1000;
 
573
                        proxy->to = timeout_add(stop_msecs,
 
574
                                                proxy_kill_idle, proxy);
 
575
                }
 
576
        }
 
577
}
 
578
 
 
579
static void
 
580
login_proxy_cmd_kick(struct ipc_cmd *cmd, const char *const *args)
 
581
{
 
582
        struct login_proxy *proxy, *next;
 
583
        unsigned int count = 0;
 
584
 
 
585
        if (args[0] == NULL) {
 
586
                ipc_cmd_fail(&cmd, "Missing parameter");
 
587
                return;
 
588
        }
 
589
 
 
590
        for (proxy = login_proxies; proxy != NULL; proxy = next) {
 
591
                next = proxy->next;
 
592
 
 
593
                if (strcmp(proxy->client->virtual_user, args[0]) == 0) {
 
594
                        login_proxy_free_reason(&proxy, KILLED_BY_ADMIN_REASON);
 
595
                        count++;
 
596
                }
 
597
        }
 
598
        for (proxy = login_proxies_pending; proxy != NULL; proxy = next) {
 
599
                next = proxy->next;
 
600
 
 
601
                if (strcmp(proxy->client->virtual_user, args[0]) == 0) {
 
602
                        client_destroy(proxy->client, "Connection kicked");
 
603
                        count++;
 
604
                }
 
605
        }
 
606
        ipc_cmd_success_reply(&cmd, t_strdup_printf("%u", count));
 
607
}
 
608
 
 
609
static unsigned int director_username_hash(const char *username)
 
610
{
 
611
        /* NOTE: If you modify this, modify also
 
612
           user_directory_get_username_hash() in director/user-director.c */
 
613
        unsigned char md5[MD5_RESULTLEN];
 
614
        unsigned int i, hash = 0;
 
615
 
 
616
        md5_get_digest(username, strlen(username), md5);
 
617
        for (i = 0; i < sizeof(hash); i++)
 
618
                hash = (hash << CHAR_BIT) | md5[i];
 
619
        return hash;
 
620
}
 
621
 
 
622
static void
 
623
login_proxy_cmd_kick_director_hash(struct ipc_cmd *cmd, const char *const *args)
 
624
{
 
625
        struct login_proxy *proxy, *next;
 
626
        unsigned int hash, count = 0;
 
627
 
 
628
        if (args[0] == NULL || str_to_uint(args[0], &hash) < 0) {
 
629
                ipc_cmd_fail(&cmd, "Invalid parameters");
 
630
                return;
 
631
        }
 
632
 
 
633
        for (proxy = login_proxies; proxy != NULL; proxy = next) {
 
634
                next = proxy->next;
 
635
 
 
636
                if (director_username_hash(proxy->client->virtual_user) == hash) {
 
637
                        login_proxy_free_reason(&proxy, KILLED_BY_ADMIN_REASON);
 
638
                        count++;
 
639
                }
 
640
        }
 
641
        for (proxy = login_proxies_pending; proxy != NULL; proxy = next) {
 
642
                next = proxy->next;
 
643
 
 
644
                if (director_username_hash(proxy->client->virtual_user) == hash) {
 
645
                        client_destroy(proxy->client, "Connection kicked");
 
646
                        count++;
 
647
                }
 
648
        }
 
649
        ipc_cmd_success_reply(&cmd, t_strdup_printf("%u", count));
 
650
}
 
651
 
 
652
static void
 
653
login_proxy_cmd_list_reply(struct ipc_cmd *cmd,
 
654
                           struct login_proxy *proxy)
 
655
{
 
656
        T_BEGIN {
 
657
                const char *reply;
 
658
 
 
659
                reply = t_strdup_printf("%s\t%s\t%s\t%s\t%u",
 
660
                                        proxy->client->virtual_user,
 
661
                                        login_binary.protocol,
 
662
                                        net_ip2addr(&proxy->client->ip),
 
663
                                        net_ip2addr(&proxy->ip), proxy->port);
 
664
                ipc_cmd_send(cmd, reply);
 
665
        } T_END;
 
666
}
 
667
 
 
668
static void
 
669
login_proxy_cmd_list(struct ipc_cmd *cmd, const char *const *args ATTR_UNUSED)
 
670
{
 
671
        struct login_proxy *proxy;
 
672
 
 
673
        for (proxy = login_proxies; proxy != NULL; proxy = proxy->next)
 
674
                login_proxy_cmd_list_reply(cmd, proxy);
 
675
        for (proxy = login_proxies_pending; proxy != NULL; proxy = proxy->next)
 
676
                login_proxy_cmd_list_reply(cmd, proxy);
 
677
        ipc_cmd_success(&cmd);
 
678
}
 
679
 
 
680
static void login_proxy_ipc_cmd(struct ipc_cmd *cmd, const char *line)
 
681
{
 
682
        const char *const *args = t_strsplit(line, "\t");
 
683
        const char *name = args[0];
 
684
 
 
685
        args++;
 
686
        if (strcmp(name, "KICK") == 0)
 
687
                login_proxy_cmd_kick(cmd, args);
 
688
        else if (strcmp(name, "KICK-DIRECTOR-HASH") == 0)
 
689
                login_proxy_cmd_kick_director_hash(cmd, args);
 
690
        else if (strcmp(name, "LIST") == 0)
 
691
                login_proxy_cmd_list(cmd, args);
 
692
        else
 
693
                ipc_cmd_fail(&cmd, "Unknown command");
 
694
}
 
695
 
 
696
void login_proxy_init(const char *proxy_notify_pipe_path)
 
697
{
 
698
        proxy_state = login_proxy_state_init(proxy_notify_pipe_path);
 
699
}
 
700
 
 
701
void login_proxy_deinit(void)
 
702
{
 
703
        struct login_proxy *proxy;
 
704
 
 
705
        while (login_proxies != NULL) {
 
706
                proxy = login_proxies;
 
707
                login_proxy_free_reason(&proxy, KILLED_BY_ADMIN_REASON);
 
708
        }
 
709
        if (login_proxy_ipc_server != NULL)
 
710
                ipc_server_deinit(&login_proxy_ipc_server);
 
711
        login_proxy_state_deinit(&proxy_state);
 
712
}