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

« back to all changes in this revision

Viewing changes to src/lib-imap-client/imapc-connection.c

  • Committer: Package Import Robot
  • Author(s): Jaldhar H. Vyas
  • Date: 2013-09-09 00:57:32 UTC
  • mfrom: (1.13.11)
  • mto: (4.8.5 experimental) (1.16.1)
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: package-import@ubuntu.com-20130909005732-dn1eell8srqbhh0e
Tags: upstream-2.2.5
ImportĀ upstreamĀ versionĀ 2.2.5

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 "ostream.h"
8
8
#include "base64.h"
20
20
#include <unistd.h>
21
21
#include <ctype.h>
22
22
 
23
 
#define IMAPC_DNS_LOOKUP_TIMEOUT_MSECS (1000*30)
24
 
#define IMAPC_CONNECT_TIMEOUT_MSECS (1000*30)
25
 
#define IMAPC_COMMAND_TIMEOUT_MSECS (1000*60*5)
26
23
#define IMAPC_MAX_INLINE_LITERAL_SIZE (1024*32)
27
24
 
28
25
enum imapc_input_state {
51
48
           executed */
52
49
        struct imapc_client_mailbox *box;
53
50
 
54
 
        ARRAY_DEFINE(streams, struct imapc_command_stream);
 
51
        ARRAY(struct imapc_command_stream) streams;
55
52
 
56
53
        imapc_command_callback_t *callback;
57
54
        void *context;
84
81
        struct imap_parser *parser;
85
82
        struct timeout *to;
86
83
        struct timeout *to_output;
 
84
        struct dns_lookup *dns_lookup;
87
85
 
88
86
        struct ssl_iostream *ssl_iostream;
89
87
 
94
92
 
95
93
        struct imapc_client_mailbox *selecting_box, *selected_box;
96
94
        enum imapc_connection_state state;
 
95
        char *disconnect_reason;
97
96
 
98
97
        enum imapc_capability capabilities;
99
98
        char **capabilities_list;
110
109
        struct ip_addr *ips;
111
110
 
112
111
        struct imapc_connection_literal literal;
113
 
        ARRAY_DEFINE(literal_files, struct imapc_arg_file);
 
112
        ARRAY(struct imapc_arg_file) literal_files;
114
113
 
115
114
        unsigned int idling:1;
116
115
        unsigned int idle_stopping:1;
117
116
        unsigned int idle_plus_waiting:1;
118
 
        unsigned int handshake_failed:1;
119
117
};
120
118
 
121
119
static void imapc_connection_capability_cb(const struct imapc_command_reply *reply,
162
160
        if (--conn->refcount > 0)
163
161
                return;
164
162
 
 
163
        i_assert(conn->disconnect_reason == NULL);
 
164
 
165
165
        if (conn->capabilities_list != NULL)
166
166
                p_strsplit_free(default_pool, conn->capabilities_list);
167
167
        array_free(&conn->cmd_send_queue);
187
187
                conn->to = io_loop_move_timeout(&conn->to);
188
188
        if (conn->output != NULL)
189
189
                o_stream_switch_ioloop(conn->output);
 
190
        if (conn->dns_lookup != NULL)
 
191
                dns_lookup_switch_ioloop(conn->dns_lookup);
190
192
 
191
193
        if (conn->client->ioloop == NULL && conn->to_output != NULL) {
192
194
                /* we're only once moving the to_output to the main ioloop,
302
304
        case IMAPC_CONNECTION_STATE_DISCONNECTED:
303
305
                memset(&reply, 0, sizeof(reply));
304
306
                reply.state = IMAPC_COMMAND_STATE_DISCONNECTED;
305
 
                reply.text_without_resp = reply.text_full =
306
 
                        "Disconnected from server";
 
307
                reply.text_full = "Disconnected from server";
 
308
                if (conn->disconnect_reason != NULL) {
 
309
                        reply.text_full = t_strdup_printf("%s: %s",
 
310
                                reply.text_full, conn->disconnect_reason);
 
311
                        i_free_and_null(conn->disconnect_reason);
 
312
                }
 
313
                reply.text_without_resp = reply.text_full;
307
314
                imapc_login_callback(conn, &reply);
308
315
 
309
316
                conn->idling = FALSE;
347
354
        bool reconnecting = conn->selected_box != NULL &&
348
355
                conn->selected_box->reconnecting;
349
356
 
350
 
        if (conn->fd == -1)
 
357
        if (conn->state == IMAPC_CONNECTION_STATE_DISCONNECTED)
351
358
                return;
352
359
 
353
360
        if (conn->client->set.debug)
354
361
                i_debug("imapc(%s): Disconnected", conn->name);
355
362
 
 
363
        if (conn->dns_lookup != NULL)
 
364
                dns_lookup_abort(&conn->dns_lookup);
356
365
        imapc_connection_lfiles_free(conn);
357
366
        imapc_connection_literal_reset(&conn->literal);
358
367
        if (conn->to != NULL)
359
368
                timeout_remove(&conn->to);
360
369
        if (conn->to_output != NULL)
361
370
                timeout_remove(&conn->to_output);
362
 
        imap_parser_unref(&conn->parser);
363
 
        io_remove(&conn->io);
 
371
        if (conn->parser != NULL)
 
372
                imap_parser_unref(&conn->parser);
 
373
        if (conn->io != NULL)
 
374
                io_remove(&conn->io);
364
375
        if (conn->ssl_iostream != NULL)
365
376
                ssl_iostream_unref(&conn->ssl_iostream);
366
 
        i_stream_destroy(&conn->input);
367
 
        o_stream_destroy(&conn->output);
368
 
        net_disconnect(conn->fd);
369
 
        conn->fd = -1;
 
377
        if (conn->fd != -1) {
 
378
                i_stream_destroy(&conn->input);
 
379
                o_stream_destroy(&conn->output);
 
380
                net_disconnect(conn->fd);
 
381
                conn->fd = -1;
 
382
        }
370
383
 
371
384
        imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DISCONNECTED);
372
385
        imapc_connection_abort_commands(conn, NULL, reconnecting);
900
913
                value = imap_args_to_str(imap_args);
901
914
                if (imapc_connection_parse_capability(conn, value) < 0)
902
915
                        return -1;
 
916
        } else if (strcasecmp(name, "BYE") == 0) {
 
917
                i_free(conn->disconnect_reason);
 
918
                conn->disconnect_reason = i_strdup(imap_args_to_str(imap_args));
903
919
        }
904
920
 
905
921
        reply.name = name;
1048
1064
                imapc_connection_disconnect(conn);
1049
1065
        }
1050
1066
 
 
1067
        if (reply.state == IMAPC_COMMAND_STATE_NO &&
 
1068
            (cmd->flags & IMAPC_COMMAND_FLAG_SELECT) != 0 &&
 
1069
            conn->selected_box != NULL) {
 
1070
                /* EXAMINE/SELECT failed: mailbox is no longer selected */
 
1071
                imapc_connection_unselect(conn->selected_box);
 
1072
        }
 
1073
 
1051
1074
        imapc_connection_input_reset(conn);
1052
1075
        imapc_command_reply_free(cmd, &reply);
1053
1076
        imapc_command_send_more(conn);
1114
1137
 
1115
1138
        if (ret < 0) {
1116
1139
                /* disconnected */
1117
 
                if (conn->ssl_iostream == NULL) {
 
1140
                if (conn->disconnect_reason != NULL) {
 
1141
                        i_error("imapc(%s): Server disconnected with message: %s",
 
1142
                                conn->name, conn->disconnect_reason);
 
1143
                } else if (conn->ssl_iostream == NULL) {
1118
1144
                        i_error("imapc(%s): Server disconnected unexpectedly",
1119
1145
                                conn->name);
1120
 
                } else if (!conn->handshake_failed) {
 
1146
                } else {
1121
1147
                        errstr = ssl_iostream_get_last_error(conn->ssl_iostream);
1122
1148
                        if (errstr == NULL) {
1123
1149
                                errstr = conn->input->stream_errno == 0 ? "EOF" :
1131
1157
        imapc_connection_unref(&conn);
1132
1158
}
1133
1159
 
1134
 
static int imapc_connection_ssl_handshaked(void *context)
 
1160
static int imapc_connection_ssl_handshaked(const char **error_r, void *context)
1135
1161
{
1136
1162
        struct imapc_connection *conn = context;
 
1163
        const char *error;
1137
1164
 
1138
 
        if (!conn->client->set.ssl_verify) {
1139
 
                /* skip certificate checks */
1140
 
                return 0;
1141
 
        } else if (!ssl_iostream_has_valid_client_cert(conn->ssl_iostream)) {
1142
 
                if (!ssl_iostream_has_broken_client_cert(conn->ssl_iostream)) {
1143
 
                        i_error("imapc(%s): SSL certificate not received",
1144
 
                                conn->name);
1145
 
                } else {
1146
 
                        i_error("imapc(%s): Received invalid SSL certificate",
1147
 
                                conn->name);
1148
 
                }
1149
 
        } else if (ssl_iostream_cert_match_name(conn->ssl_iostream,
1150
 
                                                conn->client->set.host) < 0) {
1151
 
                i_error("imapc(%s): SSL certificate doesn't match host name",
1152
 
                        conn->name);
1153
 
        } else {
 
1165
        if (ssl_iostream_check_cert_validity(conn->ssl_iostream,
 
1166
                                             conn->client->set.host, &error) == 0) {
1154
1167
                if (conn->client->set.debug) {
1155
1168
                        i_debug("imapc(%s): SSL handshake successful",
1156
1169
                                conn->name);
1157
1170
                }
1158
1171
                return 0;
 
1172
        } else if (!conn->client->set.ssl_verify) {
 
1173
                if (conn->client->set.debug) {
 
1174
                        i_debug("imapc(%s): SSL handshake successful, "
 
1175
                                "ignoring invalid certificate: %s",
 
1176
                                conn->name, error);
 
1177
                }
 
1178
                return 0;
 
1179
        } else {
 
1180
                *error_r = error;
 
1181
                return -1;
1159
1182
        }
1160
 
        conn->handshake_failed = TRUE;
1161
 
        i_stream_close(conn->input);
1162
 
        return -1;
1163
1183
}
1164
1184
 
1165
1185
static int imapc_connection_ssl_init(struct imapc_connection *conn)
1166
1186
{
1167
1187
        struct ssl_iostream_settings ssl_set;
1168
1188
        struct stat st;
1169
 
        const char *source;
 
1189
        const char *error;
1170
1190
 
1171
1191
        if (conn->client->ssl_ctx == NULL) {
1172
1192
                i_error("imapc(%s): No SSL context", conn->name);
1193
1213
                conn->output = conn->raw_output;
1194
1214
        }
1195
1215
 
1196
 
        source = t_strdup_printf("imapc(%s): ", conn->name);
1197
 
        if (io_stream_create_ssl(conn->client->ssl_ctx, source, &ssl_set,
1198
 
                                 &conn->input, &conn->output,
1199
 
                                 &conn->ssl_iostream) < 0) {
1200
 
                i_error("imapc(%s): Couldn't initialize SSL client",
1201
 
                        conn->name);
 
1216
        if (io_stream_create_ssl_client(conn->client->ssl_ctx,
 
1217
                                        conn->client->set.host,
 
1218
                                        &ssl_set, &conn->input, &conn->output,
 
1219
                                        &conn->ssl_iostream, &error) < 0) {
 
1220
                i_error("imapc(%s): Couldn't initialize SSL client: %s",
 
1221
                        conn->name, error);
1202
1222
                return -1;
1203
1223
        }
1204
1224
        ssl_iostream_set_handshake_callback(conn->ssl_iostream,
1212
1232
 
1213
1233
        if (*conn->client->set.rawlog_dir != '\0' &&
1214
1234
            stat(conn->client->set.rawlog_dir, &st) == 0) {
1215
 
                (void)iostream_rawlog_create(conn->client->set.rawlog_dir,
1216
 
                                             &conn->input, &conn->output);
 
1235
                iostream_rawlog_create(conn->client->set.rawlog_dir,
 
1236
                                       &conn->input, &conn->output);
1217
1237
        }
1218
1238
 
1219
1239
        imap_parser_set_streams(conn->parser, conn->input, NULL);
1250
1270
        case IMAPC_CONNECTION_STATE_CONNECTING:
1251
1271
                i_error("imapc(%s): connect(%s, %u) timed out after %u seconds",
1252
1272
                        conn->name, net_ip2addr(ip), conn->client->set.port,
1253
 
                        IMAPC_CONNECT_TIMEOUT_MSECS/1000);
 
1273
                        conn->client->set.connect_timeout_msecs/1000);
1254
1274
                break;
1255
1275
        case IMAPC_CONNECTION_STATE_AUTHENTICATING:
1256
1276
                i_error("imapc(%s): Authentication timed out after %u seconds",
1257
 
                        conn->name, IMAPC_CONNECT_TIMEOUT_MSECS/1000);
 
1277
                        conn->name, conn->client->set.connect_timeout_msecs/1000);
1258
1278
                break;
1259
1279
        default:
1260
1280
                i_unreached();
1306
1326
        conn->fd = fd;
1307
1327
        conn->input = conn->raw_input = i_stream_create_fd(fd, (size_t)-1, FALSE);
1308
1328
        conn->output = conn->raw_output = o_stream_create_fd(fd, (size_t)-1, FALSE);
 
1329
        o_stream_set_no_error_handling(conn->output, TRUE);
1309
1330
 
1310
1331
        if (*conn->client->set.rawlog_dir != '\0' &&
1311
1332
            conn->client->set.ssl_mode != IMAPC_CLIENT_SSL_MODE_IMMEDIATE &&
1312
1333
            stat(conn->client->set.rawlog_dir, &st) == 0) {
1313
 
                (void)iostream_rawlog_create(conn->client->set.rawlog_dir,
1314
 
                                             &conn->input, &conn->output);
 
1334
                iostream_rawlog_create(conn->client->set.rawlog_dir,
 
1335
                                       &conn->input, &conn->output);
1315
1336
        }
1316
1337
 
1317
1338
        o_stream_set_flush_callback(conn->output, imapc_connection_output,
1318
1339
                                    conn);
1319
1340
        conn->io = io_add(fd, IO_WRITE, imapc_connection_connected, conn);
1320
1341
        conn->parser = imap_parser_create(conn->input, NULL, (size_t)-1);
1321
 
        conn->to = timeout_add(IMAPC_CONNECT_TIMEOUT_MSECS,
 
1342
        conn->to = timeout_add(conn->client->set.connect_timeout_msecs,
1322
1343
                               imapc_connection_timeout, conn);
1323
1344
        conn->to_output = timeout_add(conn->client->set.max_idle_time*1000,
1324
1345
                                      imapc_connection_reset_idle, conn);
1330
1351
 
1331
1352
static void
1332
1353
imapc_connection_dns_callback(const struct dns_lookup_result *result,
1333
 
                              void *context)
 
1354
                              struct imapc_connection *conn)
1334
1355
{
1335
 
        struct imapc_connection *conn = context;
 
1356
        conn->dns_lookup = NULL;
1336
1357
 
1337
1358
        if (result->ret != 0) {
1338
1359
                i_error("imapc(%s): dns_lookup(%s) failed: %s",
1359
1380
        unsigned int ips_count;
1360
1381
        int ret;
1361
1382
 
1362
 
        if (conn->fd != -1) {
 
1383
        if (conn->fd != -1 || conn->dns_lookup != NULL) {
1363
1384
                i_assert(login_callback == NULL);
1364
1385
                return;
1365
1386
        }
1375
1396
        memset(&dns_set, 0, sizeof(dns_set));
1376
1397
        dns_set.dns_client_socket_path =
1377
1398
                conn->client->set.dns_client_socket_path;
1378
 
        dns_set.timeout_msecs = IMAPC_DNS_LOOKUP_TIMEOUT_MSECS;
 
1399
        dns_set.timeout_msecs = conn->client->set.connect_timeout_msecs;
1379
1400
 
1380
1401
        imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_CONNECTING);
1381
1402
        if (conn->ips_count == 0 &&
1400
1421
 
1401
1422
        if (conn->ips_count == 0) {
1402
1423
                (void)dns_lookup(conn->client->set.host, &dns_set,
1403
 
                                 imapc_connection_dns_callback, conn);
 
1424
                                 imapc_connection_dns_callback, conn,
 
1425
                                 &conn->dns_lookup);
1404
1426
        } else {
1405
1427
                imapc_connection_connect_next_ip(conn);
1406
1428
        }
1638
1660
 
1639
1661
        data = CONST_PTR_OFFSET(cmd->data->data, cmd->send_pos);
1640
1662
        size = end_pos - cmd->send_pos;
1641
 
        o_stream_send(conn->output, data, size);
 
1663
        o_stream_nsend(conn->output, data, size);
1642
1664
        cmd->send_pos = end_pos;
1643
1665
 
1644
1666
        if (cmd->send_pos == cmd->data->used) {
1667
1689
{
1668
1690
        if ((conn->idling || conn->idle_plus_waiting) && !conn->idle_stopping) {
1669
1691
                conn->idle_stopping = TRUE;
1670
 
                o_stream_send_str(conn->output, "DONE\r\n");
 
1692
                o_stream_nsend_str(conn->output, "DONE\r\n");
1671
1693
        }
1672
1694
}
1673
1695
 
1689
1711
                /* add timeout for commands if there's not one yet
1690
1712
                   (pre-login has its own timeout) */
1691
1713
                if (conn->to == NULL) {
1692
 
                        conn->to = timeout_add(IMAPC_COMMAND_TIMEOUT_MSECS,
 
1714
                        conn->to = timeout_add(conn->client->set.cmd_timeout_msecs,
1693
1715
                                               imapc_command_timeout, conn);
1694
1716
                }
1695
1717
        }
1817
1839
                        const char *arg = va_arg(args, const char *);
1818
1840
 
1819
1841
                        if (!need_literal(arg))
1820
 
                                imap_dquote_append(cmd->data, arg);
 
1842
                                imap_append_quoted(cmd->data, arg);
1821
1843
                        else if ((cmd->conn->capabilities &
1822
1844
                                  IMAPC_CAPABILITY_LITERALPLUS) != 0) {
1823
1845
                                str_printfa(cmd->data, "{%"PRIuSIZE_T"+}\r\n%s",