~ubuntu-branches/ubuntu/trusty/dovecot/trusty-updates

« back to all changes in this revision

Viewing changes to src/lib-storage/index/pop3c/pop3c-client.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (1.15.3) (96.1.1 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20140108093549-814nkqdcxfbvgktg
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) 2011-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2011-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "ioloop.h"
5
 
#include "network.h"
 
5
#include "net.h"
6
6
#include "istream.h"
7
7
#include "istream-dot.h"
8
8
#include "istream-seekable.h"
9
9
#include "ostream.h"
10
10
#include "iostream-rawlog.h"
11
11
#include "iostream-ssl.h"
12
 
#include "close-keep-errno.h"
13
12
#include "safe-mkstemp.h"
14
13
#include "base64.h"
15
14
#include "str.h"
50
49
        struct ostream *output, *raw_output;
51
50
        struct ssl_iostream *ssl_iostream;
52
51
        struct timeout *to;
 
52
        struct dns_lookup *dns_lookup;
53
53
 
54
54
        enum pop3c_client_state state;
55
55
        enum pop3c_capability capabilities;
61
61
        const char *input_line;
62
62
        struct istream *dot_input;
63
63
 
64
 
        unsigned int handshake_failed:1;
65
64
        unsigned int running:1;
66
65
};
67
66
 
68
67
static void
69
 
pop3c_dns_callback(const struct dns_lookup_result *result, void *context);
 
68
pop3c_dns_callback(const struct dns_lookup_result *result,
 
69
                   struct pop3c_client *client);
70
70
 
71
71
struct pop3c_client *
72
72
pop3c_client_init(const struct pop3c_client_settings *set)
73
73
{
74
74
        struct pop3c_client *client;
75
75
        struct ssl_iostream_settings ssl_set;
76
 
        const char *source;
 
76
        const char *error;
77
77
        pool_t pool;
78
78
 
79
79
        pool = pool_alloconly_create("pop3c client", 1024);
84
84
        client->set.debug = set->debug;
85
85
        client->set.host = p_strdup(pool, set->host);
86
86
        client->set.port = set->port;
87
 
        client->set.master_user = p_strdup(pool, set->master_user);
 
87
        client->set.master_user = p_strdup_empty(pool, set->master_user);
88
88
        client->set.username = p_strdup(pool, set->username);
89
89
        client->set.password = p_strdup(pool, set->password);
90
90
        client->set.dns_client_socket_path =
95
95
        if (set->ssl_mode != POP3C_CLIENT_SSL_MODE_NONE) {
96
96
                client->set.ssl_mode = set->ssl_mode;
97
97
                client->set.ssl_ca_dir = p_strdup(pool, set->ssl_ca_dir);
 
98
                client->set.ssl_ca_file = p_strdup(pool, set->ssl_ca_file);
98
99
                client->set.ssl_verify = set->ssl_verify;
99
100
 
100
101
                memset(&ssl_set, 0, sizeof(ssl_set));
101
102
                ssl_set.ca_dir = set->ssl_ca_dir;
 
103
                ssl_set.ca_file = set->ssl_ca_file;
102
104
                ssl_set.verify_remote_cert = set->ssl_verify;
103
105
                ssl_set.crypto_device = set->ssl_crypto_device;
104
106
 
105
 
                source = t_strdup_printf("%s:%u", set->host, set->port);
106
 
                if (ssl_iostream_context_init_client(source, &ssl_set,
107
 
                                                     &client->ssl_ctx) < 0) {
108
 
                        i_error("pop3c(%s): Couldn't initialize SSL context",
109
 
                                source);
 
107
                if (ssl_iostream_context_init_client(&ssl_set, &client->ssl_ctx,
 
108
                                                     &error) < 0) {
 
109
                        i_error("pop3c(%s:%u): Couldn't initialize SSL context: %s",
 
110
                                set->host, set->port, error);
110
111
                }
111
112
        }
112
113
        return client;
134
135
        if (client->running)
135
136
                io_loop_stop(current_ioloop);
136
137
 
 
138
        if (client->dns_lookup != NULL)
 
139
                dns_lookup_abort(&client->dns_lookup);
137
140
        if (client->to != NULL)
138
141
                timeout_remove(&client->to);
139
142
        if (client->io != NULL)
166
169
static void pop3c_client_ioloop_changed(struct pop3c_client *client)
167
170
{
168
171
        if (client->to != NULL)
169
 
                io_loop_move_timeout(&client->to);
 
172
                client->to = io_loop_move_timeout(&client->to);
170
173
        if (client->io != NULL)
171
174
                client->io = io_loop_move_io(&client->io);
172
175
        if (client->output != NULL)
196
199
void pop3c_client_run(struct pop3c_client *client)
197
200
{
198
201
        struct ioloop *ioloop, *prev_ioloop = current_ioloop;
199
 
        bool timeout_added = FALSE;
 
202
        bool timeout_added = FALSE, failed = FALSE;
200
203
 
201
204
        i_assert(client->fd != -1 ||
202
205
                 client->state == POP3C_CLIENT_STATE_CONNECTING);
214
217
                dns_set.dns_client_socket_path =
215
218
                        client->set.dns_client_socket_path;
216
219
                dns_set.timeout_msecs = POP3C_DNS_LOOKUP_TIMEOUT_MSECS;
217
 
                (void)dns_lookup(client->set.host, &dns_set,
218
 
                                 pop3c_dns_callback, client);
 
220
                if (dns_lookup(client->set.host, &dns_set,
 
221
                               pop3c_dns_callback, client,
 
222
                               &client->dns_lookup) < 0)
 
223
                        failed = TRUE;
219
224
        } else if (client->to == NULL) {
220
225
                client->to = timeout_add(POP3C_COMMAND_TIMEOUT_MSECS,
221
226
                                         pop3c_client_timeout, client);
222
227
                timeout_added = TRUE;
223
228
        }
224
229
 
225
 
        client->running = TRUE;
226
 
        io_loop_run(ioloop);
227
 
        client->running = FALSE;
 
230
        if (!failed) {
 
231
                client->running = TRUE;
 
232
                io_loop_run(ioloop);
 
233
                client->running = FALSE;
 
234
        }
228
235
 
229
236
        if (timeout_added && client->to != NULL)
230
237
                timeout_remove(&client->to);
231
238
 
232
 
        current_ioloop = prev_ioloop;
 
239
        io_loop_set_current(prev_ioloop);
233
240
        pop3c_client_ioloop_changed(client);
234
 
        current_ioloop = ioloop;
 
241
        io_loop_set_current(ioloop);
235
242
        io_loop_destroy(&ioloop);
236
243
}
237
244
 
251
258
        }
252
259
 
253
260
        if (set->master_user == NULL) {
254
 
                o_stream_send_str(client->output,
 
261
                o_stream_nsend_str(client->output,
255
262
                        t_strdup_printf("USER %s\r\n", set->username));
256
263
                client->state = POP3C_CLIENT_STATE_USER;
257
264
        } else {
258
265
                client->state = POP3C_CLIENT_STATE_AUTH;
259
 
                o_stream_send_str(client->output, "AUTH PLAIN\r\n");
 
266
                o_stream_nsend_str(client->output, "AUTH PLAIN\r\n");
260
267
        }
261
268
}
262
269
 
315
322
                                client->set.host, line);
316
323
                        return -1;
317
324
                }
318
 
                o_stream_send_str(client->output,
 
325
                o_stream_nsend_str(client->output,
319
326
                        t_strdup_printf("PASS %s\r\n", client->set.password));
320
327
                client->state = POP3C_CLIENT_STATE_PASS;
321
328
                break;
325
332
                                client->set.host, line);
326
333
                        return -1;
327
334
                }
328
 
                o_stream_send_str(client->output,
 
335
                o_stream_nsend_str(client->output,
329
336
                        pop3c_client_get_sasl_plain_request(client));
330
337
                client->state = POP3C_CLIENT_STATE_PASS;
331
338
                break;
344
351
                if (!success)
345
352
                        return -1;
346
353
 
347
 
                o_stream_send_str(client->output, "CAPA\r\n");
 
354
                o_stream_nsend_str(client->output, "CAPA\r\n");
348
355
                client->state = POP3C_CLIENT_STATE_CAPA;
349
356
                break;
350
357
        case POP3C_CLIENT_STATE_CAPA:
351
 
                if (strncasecmp(line, "-ERR", 4) == 0 ||
352
 
                    strcmp(line, ".") == 0) {
 
358
                if (strncasecmp(line, "-ERR", 4) == 0) {
 
359
                        /* CAPA command not supported. some commands still
 
360
                           support UIDL though. */
 
361
                        client->capabilities |= POP3C_CAPABILITY_UIDL;
 
362
                        pop3c_client_login_finished(client);
 
363
                        break;
 
364
                } else if (strcmp(line, ".") == 0) {
353
365
                        pop3c_client_login_finished(client);
354
366
                        break;
355
367
                }
388
400
                if (client->ssl_iostream == NULL) {
389
401
                        i_error("pop3c(%s): Server disconnected unexpectedly",
390
402
                                client->set.host);
391
 
                } else if (!client->handshake_failed) {
 
403
                } else {
392
404
                        errstr = ssl_iostream_get_last_error(client->ssl_iostream);
393
405
                        if (errstr == NULL) {
394
406
                                errstr = client->input->stream_errno == 0 ? "EOF" :
401
413
        }
402
414
}
403
415
 
404
 
static int pop3c_client_ssl_handshaked(void *context)
 
416
static int pop3c_client_ssl_handshaked(const char **error_r, void *context)
405
417
{
406
418
        struct pop3c_client *client = context;
 
419
        const char *error;
407
420
 
408
 
        if (!client->set.ssl_verify) {
409
 
                /* skip certificate checks */
410
 
                return 0;
411
 
        } else if (!ssl_iostream_has_valid_client_cert(client->ssl_iostream)) {
412
 
                if (!ssl_iostream_has_broken_client_cert(client->ssl_iostream)) {
413
 
                        i_error("pop3c(%s): SSL certificate not received",
414
 
                                client->set.host);
415
 
                } else {
416
 
                        i_error("pop3c(%s): Received invalid SSL certificate",
417
 
                                client->set.host);
418
 
                }
419
 
        } else if (ssl_iostream_cert_match_name(client->ssl_iostream,
420
 
                                                client->set.host) < 0) {
421
 
                i_error("pop3c(%s): SSL certificate doesn't match host name",
422
 
                        client->set.host);
423
 
        } else {
 
421
        if (ssl_iostream_check_cert_validity(client->ssl_iostream,
 
422
                                             client->set.host, &error) == 0) {
424
423
                if (client->set.debug) {
425
424
                        i_debug("pop3c(%s): SSL handshake successful",
426
425
                                client->set.host);
427
426
                }
428
427
                return 0;
 
428
        } else if (!client->set.ssl_verify) {
 
429
                if (client->set.debug) {
 
430
                        i_debug("pop3c(%s): SSL handshake successful, "
 
431
                                "ignoring invalid certificate: %s",
 
432
                                client->set.host, error);
 
433
                }
 
434
                return 0;
 
435
        } else {
 
436
                *error_r = error;
 
437
                return -1;
429
438
        }
430
 
        client->handshake_failed = TRUE;
431
 
        i_stream_close(client->input);
432
 
        return -1;
433
439
}
434
440
 
435
441
static int pop3c_client_ssl_init(struct pop3c_client *client)
436
442
{
437
443
        struct ssl_iostream_settings ssl_set;
438
444
        struct stat st;
439
 
        const char *source;
 
445
        const char *error;
440
446
 
441
447
        if (client->ssl_ctx == NULL) {
442
448
                i_error("pop3c(%s): No SSL context", client->set.host);
463
469
                client->output = client->raw_output;
464
470
        }
465
471
 
466
 
        source = t_strdup_printf("pop3c(%s): ", client->set.host);
467
 
        if (io_stream_create_ssl(client->ssl_ctx, source, &ssl_set,
468
 
                                 &client->input, &client->output,
469
 
                                 &client->ssl_iostream) < 0) {
470
 
                i_error("pop3c(%s): Couldn't initialize SSL client",
471
 
                        client->set.host);
 
472
        if (io_stream_create_ssl_client(client->ssl_ctx, client->set.host,
 
473
                                        &ssl_set, &client->input, &client->output,
 
474
                                        &client->ssl_iostream, &error) < 0) {
 
475
                i_error("pop3c(%s): Couldn't initialize SSL client: %s",
 
476
                        client->set.host, error);
472
477
                return -1;
473
478
        }
474
479
        ssl_iostream_set_handshake_callback(client->ssl_iostream,
482
487
 
483
488
        if (*client->set.rawlog_dir != '\0' &&
484
489
            stat(client->set.rawlog_dir, &st) == 0) {
485
 
                (void)iostream_rawlog_create(client->set.rawlog_dir,
486
 
                                             &client->input, &client->output);
 
490
                iostream_rawlog_create(client->set.rawlog_dir,
 
491
                                       &client->input, &client->output);
487
492
        }
488
493
        return 0;
489
494
}
524
529
                i_stream_create_fd(client->fd, POP3C_MAX_INBUF_SIZE, FALSE);
525
530
        client->output = client->raw_output =
526
531
                o_stream_create_fd(client->fd, (size_t)-1, FALSE);
 
532
        o_stream_set_no_error_handling(client->output, TRUE);
527
533
 
528
534
        if (*client->set.rawlog_dir != '\0' &&
529
535
            client->set.ssl_mode != POP3C_CLIENT_SSL_MODE_IMMEDIATE &&
530
536
            stat(client->set.rawlog_dir, &st) == 0) {
531
 
                (void)iostream_rawlog_create(client->set.rawlog_dir,
532
 
                                             &client->input, &client->output);
 
537
                iostream_rawlog_create(client->set.rawlog_dir,
 
538
                                       &client->input, &client->output);
533
539
        }
534
540
        client->io = io_add(client->fd, IO_WRITE,
535
541
                            pop3c_client_connected, client);
542
548
}
543
549
 
544
550
static void
545
 
pop3c_dns_callback(const struct dns_lookup_result *result, void *context)
 
551
pop3c_dns_callback(const struct dns_lookup_result *result,
 
552
                   struct pop3c_client *client)
546
553
{
547
 
        struct pop3c_client *client = context;
 
554
        client->dns_lookup = NULL;
548
555
 
549
556
        if (result->ret != 0) {
550
557
                i_error("pop3c(%s): dns_lookup() failed: %s",
656
663
 
657
664
        if (pop3c_client_flush_asyncs(client, reply_r) < 0)
658
665
                return -1;
659
 
        o_stream_send_str(client->output, cmd);
 
666
        o_stream_nsend_str(client->output, cmd);
660
667
        if (pop3c_client_read_line(client, &line, reply_r) < 0)
661
668
                return -1;
662
669
        if (strncasecmp(line, "+OK", 3) == 0) {
687
694
                if (pop3c_client_flush_asyncs(client, &error) < 0)
688
695
                        return;
689
696
        }
690
 
        o_stream_send_str(client->output, cmd);
 
697
        o_stream_nsend_str(client->output, cmd);
691
698
        client->async_commands++;
692
699
}
693
700
 
709
716
        if (unlink(str_c(path)) < 0) {
710
717
                /* shouldn't happen.. */
711
718
                i_error("unlink(%s) failed: %m", str_c(path));
712
 
                close_keep_errno(fd);
 
719
                i_close_fd(&fd);
713
720
                return -1;
714
721
        }
715
722
 
720
727
static void pop3c_client_dot_input(struct pop3c_client *client)
721
728
{
722
729
        ssize_t ret;
723
 
        size_t size;
724
730
 
725
731
        if (client->to != NULL)
726
732
                timeout_reset(client->to);
727
733
        while ((ret = i_stream_read(client->dot_input)) > 0 || ret == -2) {
728
 
                (void)i_stream_get_data(client->dot_input, &size);
729
 
                i_stream_skip(client->dot_input, size);
 
734
                i_stream_skip(client->dot_input,
 
735
                              i_stream_get_data_size(client->dot_input));
730
736
        }
731
 
        (void)i_stream_get_data(client->dot_input, &size);
732
737
        if (ret != 0) {
733
738
                i_assert(ret == -1);
734
739
                if (client->dot_input->stream_errno != 0) {