1
/* Copyright (c) 2011-2012 Dovecot authors, see the included COPYING file */
1
/* Copyright (c) 2011-2013 Dovecot authors, see the included COPYING file */
7
7
#include "istream-dot.h"
8
8
#include "istream-seekable.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"
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;
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;
64
unsigned int handshake_failed:1;
65
64
unsigned int running:1;
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);
71
71
struct pop3c_client *
72
72
pop3c_client_init(const struct pop3c_client_settings *set)
74
74
struct pop3c_client *client;
75
75
struct ssl_iostream_settings ssl_set;
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;
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;
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",
107
if (ssl_iostream_context_init_client(&ssl_set, &client->ssl_ctx,
109
i_error("pop3c(%s:%u): Couldn't initialize SSL context: %s",
110
set->host, set->port, error);
166
169
static void pop3c_client_ioloop_changed(struct pop3c_client *client)
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)
198
201
struct ioloop *ioloop, *prev_ioloop = current_ioloop;
199
bool timeout_added = FALSE;
202
bool timeout_added = FALSE, failed = FALSE;
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)
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;
225
client->running = TRUE;
227
client->running = FALSE;
231
client->running = TRUE;
233
client->running = FALSE;
229
236
if (timeout_added && client->to != NULL)
230
237
timeout_remove(&client->to);
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);
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;
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");
315
322
client->set.host, line);
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;
325
332
client->set.host, line);
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;
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;
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);
364
} else if (strcmp(line, ".") == 0) {
353
365
pop3c_client_login_finished(client);
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) {
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" :
404
static int pop3c_client_ssl_handshaked(void *context)
416
static int pop3c_client_ssl_handshaked(const char **error_r, void *context)
406
418
struct pop3c_client *client = context;
408
if (!client->set.ssl_verify) {
409
/* skip certificate checks */
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",
416
i_error("pop3c(%s): Received invalid SSL certificate",
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",
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);
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);
430
client->handshake_failed = TRUE;
431
i_stream_close(client->input);
435
441
static int pop3c_client_ssl_init(struct pop3c_client *client)
437
443
struct ssl_iostream_settings ssl_set;
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;
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",
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);
474
479
ssl_iostream_set_handshake_callback(client->ssl_iostream,
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);
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);
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);
534
540
client->io = io_add(client->fd, IO_WRITE,
535
541
pop3c_client_connected, client);
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)
547
struct pop3c_client *client = context;
554
client->dns_lookup = NULL;
549
556
if (result->ret != 0) {
550
557
i_error("pop3c(%s): dns_lookup() failed: %s",
657
664
if (pop3c_client_flush_asyncs(client, reply_r) < 0)
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)
662
669
if (strncasecmp(line, "+OK", 3) == 0) {
687
694
if (pop3c_client_flush_asyncs(client, &error) < 0)
690
o_stream_send_str(client->output, cmd);
697
o_stream_nsend_str(client->output, cmd);
691
698
client->async_commands++;
720
727
static void pop3c_client_dot_input(struct pop3c_client *client)
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));
731
(void)i_stream_get_data(client->dot_input, &size);
733
738
i_assert(ret == -1);
734
739
if (client->dot_input->stream_errno != 0) {