26
26
* RFC4616 PLAIN authentication
27
27
* RFC4959 IMAP Extension for SASL Initial Client Response
28
28
* RFC5092 IMAP URL Scheme
29
* RFC6749 OAuth 2.0 Authorization Framework
30
31
***************************************************************************/
164
165
static const struct Curl_handler Curl_handler_imap_proxy = {
165
166
"IMAP", /* scheme */
166
ZERO_NULL, /* setup_connection */
167
Curl_http_setup_conn, /* setup_connection */
167
168
Curl_http, /* do_it */
168
169
Curl_http_done, /* done */
169
170
ZERO_NULL, /* do_more */
189
190
static const struct Curl_handler Curl_handler_imaps_proxy = {
190
191
"IMAPS", /* scheme */
191
ZERO_NULL, /* setup_connection */
192
Curl_http_setup_conn, /* setup_connection */
192
193
Curl_http, /* do_it */
193
194
Curl_http_done, /* done */
194
195
ZERO_NULL, /* do_more */
268
269
static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
271
struct IMAP *imap = conn->data->state.proto.imap;
272
struct IMAP *imap = conn->data->req.protop;
272
273
struct imap_conn *imapc = &conn->proto.imapc;
273
274
const char *id = imapc->resptag;
274
275
size_t id_len = strlen(id);
307
308
(strcmp(imap->custom, "STORE") ||
308
309
!imap_matchresp(line, len, "FETCH")) &&
309
310
strcmp(imap->custom, "SELECT") &&
310
strcmp(imap->custom, "EXAMINE")))
311
strcmp(imap->custom, "EXAMINE") &&
312
strcmp(imap->custom, "SEARCH") &&
313
strcmp(imap->custom, "EXPUNGE") &&
314
strcmp(imap->custom, "LSUB") &&
315
strcmp(imap->custom, "UID") &&
316
strcmp(imap->custom, "NOOP")))
333
/* Do we have a continuation response? */
339
/* Do we have a continuation response? This should be a + symbol followed by
340
a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
341
APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
342
some e-mail servers ignore this and only send a single + instead. */
334
343
if((len == 3 && !memcmp("+", line, 1)) ||
335
344
(len >= 2 && !memcmp("+ ", line, 2))) {
336
345
switch(imapc->state) {
343
352
case IMAP_AUTHENTICATE_DIGESTMD5_RESP:
344
353
case IMAP_AUTHENTICATE_NTLM:
345
354
case IMAP_AUTHENTICATE_NTLM_TYPE2MSG:
355
case IMAP_AUTHENTICATE_XOAUTH2:
346
356
case IMAP_AUTHENTICATE_FINAL:
347
357
case IMAP_APPEND:
547
558
#ifndef CURL_DISABLE_CRYPTO_AUTH
548
559
if((imapc->authmechs & SASL_MECH_DIGEST_MD5) &&
549
560
(imapc->prefmech & SASL_MECH_DIGEST_MD5)) {
561
mech = SASL_MECH_STRING_DIGEST_MD5;
551
562
state1 = IMAP_AUTHENTICATE_DIGESTMD5;
552
563
imapc->authused = SASL_MECH_DIGEST_MD5;
554
565
else if((imapc->authmechs & SASL_MECH_CRAM_MD5) &&
555
566
(imapc->prefmech & SASL_MECH_CRAM_MD5)) {
567
mech = SASL_MECH_STRING_CRAM_MD5;
557
568
state1 = IMAP_AUTHENTICATE_CRAMMD5;
558
569
imapc->authused = SASL_MECH_CRAM_MD5;
563
574
if((imapc->authmechs & SASL_MECH_NTLM) &&
564
575
(imapc->prefmech & SASL_MECH_NTLM)) {
576
mech = SASL_MECH_STRING_NTLM;
566
577
state1 = IMAP_AUTHENTICATE_NTLM;
567
578
state2 = IMAP_AUTHENTICATE_NTLM_TYPE2MSG;
568
579
imapc->authused = SASL_MECH_NTLM;
577
if((imapc->authmechs & SASL_MECH_LOGIN) &&
588
if(((imapc->authmechs & SASL_MECH_XOAUTH2) &&
589
(imapc->prefmech & SASL_MECH_XOAUTH2) &&
590
(imapc->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
591
mech = SASL_MECH_STRING_XOAUTH2;
592
state1 = IMAP_AUTHENTICATE_XOAUTH2;
593
state2 = IMAP_AUTHENTICATE_FINAL;
594
imapc->authused = SASL_MECH_XOAUTH2;
596
if(imapc->ir_supported || data->set.sasl_ir)
597
result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
598
conn->xoauth2_bearer,
601
else if((imapc->authmechs & SASL_MECH_LOGIN) &&
578
602
(imapc->prefmech & SASL_MECH_LOGIN)) {
603
mech = SASL_MECH_STRING_LOGIN;
580
604
state1 = IMAP_AUTHENTICATE_LOGIN;
581
605
state2 = IMAP_AUTHENTICATE_LOGIN_PASSWD;
582
606
imapc->authused = SASL_MECH_LOGIN;
588
612
else if((imapc->authmechs & SASL_MECH_PLAIN) &&
589
613
(imapc->prefmech & SASL_MECH_PLAIN)) {
614
mech = SASL_MECH_STRING_PLAIN;
591
615
state1 = IMAP_AUTHENTICATE_PLAIN;
592
616
state2 = IMAP_AUTHENTICATE_FINAL;
593
617
imapc->authused = SASL_MECH_PLAIN;
674
698
CURLcode result = CURLE_OK;
675
699
struct SessionHandle *data = conn->data;
676
struct IMAP *imap = data->state.proto.imap;
700
struct IMAP *imap = data->req.protop;
677
701
struct imap_conn *imapc = &conn->proto.imapc;
712
736
static CURLcode imap_perform_fetch(struct connectdata *conn)
714
738
CURLcode result = CURLE_OK;
715
struct IMAP *imap = conn->data->state.proto.imap;
739
struct IMAP *imap = conn->data->req.protop;
717
741
/* Check we have a UID */
740
764
static CURLcode imap_perform_append(struct connectdata *conn)
742
766
CURLcode result = CURLE_OK;
743
struct IMAP *imap = conn->data->state.proto.imap;
767
struct IMAP *imap = conn->data->req.protop;
746
770
/* Check we have a mailbox */
866
890
/* Test the word for a matching authentication mechanism */
867
if(wordlen == 5 && !memcmp(line, "LOGIN", 5))
891
if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
868
892
imapc->authmechs |= SASL_MECH_LOGIN;
869
if(wordlen == 5 && !memcmp(line, "PLAIN", 5))
893
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
870
894
imapc->authmechs |= SASL_MECH_PLAIN;
871
else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8))
895
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
872
896
imapc->authmechs |= SASL_MECH_CRAM_MD5;
873
else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10))
897
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
874
898
imapc->authmechs |= SASL_MECH_DIGEST_MD5;
875
else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6))
899
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
876
900
imapc->authmechs |= SASL_MECH_GSSAPI;
877
else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
901
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
878
902
imapc->authmechs |= SASL_MECH_EXTERNAL;
879
else if(wordlen == 4 && !memcmp(line, "NTLM", 4))
903
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
880
904
imapc->authmechs |= SASL_MECH_NTLM;
905
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
906
imapc->authmechs |= SASL_MECH_XOAUTH2;
1272
/* For AUTH XOAUTH2 (without initial response) responses */
1273
static CURLcode imap_state_auth_xoauth2_resp(struct connectdata *conn,
1277
CURLcode result = CURLE_OK;
1278
struct SessionHandle *data = conn->data;
1280
char *xoauth = NULL;
1282
(void)instate; /* no use for this yet */
1284
if(imapcode != '+') {
1285
failf(data, "Access denied: %d", imapcode);
1286
result = CURLE_LOGIN_DENIED;
1289
/* Create the authorisation message */
1290
result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
1291
conn->xoauth2_bearer,
1294
/* Send the message */
1297
result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", xoauth);
1300
state(conn, IMAP_AUTHENTICATE_FINAL);
1303
Curl_safefree(xoauth);
1246
1310
/* For final responses to the AUTHENTICATE sequence */
1247
1311
static CURLcode imap_state_auth_final_resp(struct connectdata *conn,
1317
1381
CURLcode result = CURLE_OK;
1318
1382
struct SessionHandle *data = conn->data;
1319
struct IMAP *imap = conn->data->state.proto.imap;
1383
struct IMAP *imap = conn->data->req.protop;
1320
1384
struct imap_conn *imapc = &conn->proto.imapc;
1321
1385
const char *line = data->state.buffer;
1409
1473
data->req.bytecount += chunk;
1412
1475
infof(data, "Written %" FORMAT_OFF_TU " bytes, %" FORMAT_OFF_TU
1413
" bytes are left for transfer\n", (curl_off_t)chunk, size);
1476
" bytes are left for transfer\n", (curl_off_t)chunk,
1415
1479
/* Have we used the entire cache or just part of it?*/
1416
1480
if(pp->cache_size > chunk) {
1494
if(data->req.bytecount == size)
1431
1495
/* The entire data is already transferred! */
1432
1496
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1659
case IMAP_AUTHENTICATE_XOAUTH2:
1660
result = imap_state_auth_xoauth2_resp(conn, imapcode, imapc->state);
1595
1663
case IMAP_AUTHENTICATE_FINAL:
1596
1664
result = imap_state_auth_final_resp(conn, imapcode, imapc->state);
1642
1710
CURLcode result = CURLE_OK;
1643
1711
struct imap_conn *imapc = &conn->proto.imapc;
1645
if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone)
1713
if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
1646
1714
result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
1648
result = Curl_pp_statemach(&imapc->pp, FALSE);
1715
if(result || !imapc->ssldone)
1719
result = Curl_pp_statemach(&imapc->pp, FALSE);
1650
1720
*done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
1670
1740
CURLcode result = CURLE_OK;
1671
1741
struct SessionHandle *data = conn->data;
1672
struct IMAP *imap = data->state.proto.imap;
1675
imap = data->state.proto.imap = calloc(sizeof(struct IMAP), 1);
1677
result = CURLE_OUT_OF_MEMORY;
1744
imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
1746
result = CURLE_OUT_OF_MEMORY;
1706
1774
*done = FALSE; /* default to not done yet */
1708
/* If there already is a protocol-specific struct allocated for this
1709
sessionhandle, deal with it */
1710
Curl_reset_reqproto(conn);
1712
/* Initialise the IMAP layer */
1713
result = imap_init(conn);
1717
1776
/* We always support persistent connections in IMAP */
1718
1777
conn->bits.close = FALSE;
1824
1883
/* This is IMAP and no proxy */
1825
1884
CURLcode result = CURLE_OK;
1826
1885
struct SessionHandle *data = conn->data;
1827
struct IMAP *imap = data->state.proto.imap;
1886
struct IMAP *imap = data->req.protop;
1828
1887
struct imap_conn *imapc = &conn->proto.imapc;
1829
1888
bool selected = FALSE;
1892
1951
*done = FALSE; /* default to false */
1894
/* Since connections can be re-used between SessionHandles, there might be a
1895
connection already existing but on a fresh SessionHandle struct. As such
1896
we make sure we have a good IMAP struct to play with. For new connections
1897
the IMAP struct is allocated and setup in the imap_connect() function. */
1898
Curl_reset_reqproto(conn);
1899
result = imap_init(conn);
1903
1953
/* Parse the URL path */
1904
1954
result = imap_parse_url_path(conn);
1952
2002
/* Call this when the DO phase has completed */
1953
2003
static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
1955
struct IMAP *imap = conn->data->state.proto.imap;
2005
struct IMAP *imap = conn->data->req.protop;
1957
2007
(void)connected;
2019
2069
struct SessionHandle *data = conn->data;
2071
/* Initialise the IMAP layer */
2072
CURLcode result = imap_init(conn);
2021
2076
if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
2022
2077
/* Unless we have asked to tunnel IMAP operations through the proxy, we
2023
2078
switch and use HTTP operations only */
2036
/* We explicitly mark this connection as persistent here as we're doing
2037
IMAP over HTTP and thus we accidentally avoid setting this value
2039
conn->bits.close = FALSE;
2091
/* set it up as an HTTP connection instead */
2092
return conn->handler->setup_connection(conn);
2041
2094
failf(data, "IMAP over http proxy requires HTTP support built-in!");
2042
2095
return CURLE_UNSUPPORTED_PROTOCOL;
2226
2279
if(strequal(value, "*"))
2227
2280
imapc->prefmech = SASL_AUTH_ANY;
2228
else if(strequal(value, "LOGIN"))
2281
else if(strequal(value, SASL_MECH_STRING_LOGIN))
2229
2282
imapc->prefmech = SASL_MECH_LOGIN;
2230
else if(strequal(value, "PLAIN"))
2283
else if(strequal(value, SASL_MECH_STRING_PLAIN))
2231
2284
imapc->prefmech = SASL_MECH_PLAIN;
2232
else if(strequal(value, "CRAM-MD5"))
2285
else if(strequal(value, SASL_MECH_STRING_CRAM_MD5))
2233
2286
imapc->prefmech = SASL_MECH_CRAM_MD5;
2234
else if(strequal(value, "DIGEST-MD5"))
2287
else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5))
2235
2288
imapc->prefmech = SASL_MECH_DIGEST_MD5;
2236
else if(strequal(value, "GSSAPI"))
2289
else if(strequal(value, SASL_MECH_STRING_GSSAPI))
2237
2290
imapc->prefmech = SASL_MECH_GSSAPI;
2238
else if(strequal(value, "NTLM"))
2291
else if(strequal(value, SASL_MECH_STRING_NTLM))
2239
2292
imapc->prefmech = SASL_MECH_NTLM;
2293
else if(strequal(value, SASL_MECH_STRING_XOAUTH2))
2294
imapc->prefmech = SASL_MECH_XOAUTH2;
2241
2296
imapc->prefmech = SASL_AUTH_NONE;
2259
2314
/* The imap struct is already initialised in imap_connect() */
2260
2315
CURLcode result = CURLE_OK;
2261
2316
struct SessionHandle *data = conn->data;
2262
struct IMAP *imap = data->state.proto.imap;
2317
struct IMAP *imap = data->req.protop;
2263
2318
const char *begin = data->state.path;
2264
2319
const char *ptr = begin;
2368
2423
CURLcode result = CURLE_OK;
2369
2424
struct SessionHandle *data = conn->data;
2370
struct IMAP *imap = data->state.proto.imap;
2425
struct IMAP *imap = data->req.protop;
2371
2426
const char *custom = data->set.str[STRING_CUSTOMREQUEST];