~ubuntu-branches/ubuntu/trusty/curl/trusty-updates

« back to all changes in this revision

Viewing changes to lib/imap.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher
  • Date: 2013-11-06 10:45:28 UTC
  • mfrom: (3.4.42 sid)
  • Revision ID: package-import@ubuntu.com-20131106104528-p8v5mc6yduc7hbsw
Tags: 7.33.0-1ubuntu1
* Resynchronize on Debian, remaining changes
  - Drop dependencies not in main:
    + Build-Depends: Drop stunnel4 and libssh2-1-dev.
    + Drop libssh2-1-dev from binary package Depends.
  - Add new libcurl3-udeb package.
  - Add new curl-udeb package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
29
30
 *
30
31
 ***************************************************************************/
31
32
 
163
164
 
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 */
188
189
 
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,
269
270
                           int *resp)
270
271
{
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")))
311
317
          return FALSE;
312
318
        break;
313
319
 
330
336
    return TRUE;
331
337
  }
332
338
 
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:
348
358
        *resp = '+';
385
395
    "AUTHENTICATE_DIGESTMD5_RESP",
386
396
    "AUTHENTICATE_NTLM",
387
397
    "AUTHENTICATE_NTLM_TYPE2MSG",
 
398
    "AUTHENTICATE_XOAUTH2",
388
399
    "AUTHENTICATE_FINAL",
389
400
    "LOGIN",
390
401
    "LIST",
547
558
#ifndef CURL_DISABLE_CRYPTO_AUTH
548
559
  if((imapc->authmechs & SASL_MECH_DIGEST_MD5) &&
549
560
     (imapc->prefmech & SASL_MECH_DIGEST_MD5)) {
550
 
    mech = "DIGEST-MD5";
 
561
    mech = SASL_MECH_STRING_DIGEST_MD5;
551
562
    state1 = IMAP_AUTHENTICATE_DIGESTMD5;
552
563
    imapc->authused = SASL_MECH_DIGEST_MD5;
553
564
  }
554
565
  else if((imapc->authmechs & SASL_MECH_CRAM_MD5) &&
555
566
          (imapc->prefmech & SASL_MECH_CRAM_MD5)) {
556
 
    mech = "CRAM-MD5";
 
567
    mech = SASL_MECH_STRING_CRAM_MD5;
557
568
    state1 = IMAP_AUTHENTICATE_CRAMMD5;
558
569
    imapc->authused = SASL_MECH_CRAM_MD5;
559
570
  }
562
573
#ifdef USE_NTLM
563
574
    if((imapc->authmechs & SASL_MECH_NTLM) &&
564
575
       (imapc->prefmech & SASL_MECH_NTLM)) {
565
 
    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;
574
585
  }
575
586
  else
576
587
#endif
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;
 
595
 
 
596
    if(imapc->ir_supported || data->set.sasl_ir)
 
597
      result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
 
598
                                                conn->xoauth2_bearer,
 
599
                                                &initresp, &len);
 
600
  }
 
601
  else if((imapc->authmechs & SASL_MECH_LOGIN) &&
578
602
     (imapc->prefmech & SASL_MECH_LOGIN)) {
579
 
    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;
587
611
  }
588
612
  else if((imapc->authmechs & SASL_MECH_PLAIN) &&
589
613
          (imapc->prefmech & SASL_MECH_PLAIN)) {
590
 
    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;
638
662
{
639
663
  CURLcode result = CURLE_OK;
640
664
  struct SessionHandle *data = conn->data;
641
 
  struct IMAP *imap = data->state.proto.imap;
 
665
  struct IMAP *imap = data->req.protop;
642
666
  char *mailbox;
643
667
 
644
668
  if(imap->custom)
673
697
{
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;
678
702
  char *mailbox;
679
703
 
712
736
static CURLcode imap_perform_fetch(struct connectdata *conn)
713
737
{
714
738
  CURLcode result = CURLE_OK;
715
 
  struct IMAP *imap = conn->data->state.proto.imap;
 
739
  struct IMAP *imap = conn->data->req.protop;
716
740
 
717
741
  /* Check we have a UID */
718
742
  if(!imap->uid) {
740
764
static CURLcode imap_perform_append(struct connectdata *conn)
741
765
{
742
766
  CURLcode result = CURLE_OK;
743
 
  struct IMAP *imap = conn->data->state.proto.imap;
 
767
  struct IMAP *imap = conn->data->req.protop;
744
768
  char *mailbox;
745
769
 
746
770
  /* Check we have a mailbox */
864
888
        wordlen -= 5;
865
889
 
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;
881
907
      }
882
908
 
883
909
      line += wordlen;
1243
1269
}
1244
1270
#endif
1245
1271
 
 
1272
/* For AUTH XOAUTH2 (without initial response) responses */
 
1273
static CURLcode imap_state_auth_xoauth2_resp(struct connectdata *conn,
 
1274
                                             int imapcode,
 
1275
                                             imapstate instate)
 
1276
{
 
1277
  CURLcode result = CURLE_OK;
 
1278
  struct SessionHandle *data = conn->data;
 
1279
  size_t len = 0;
 
1280
  char *xoauth = NULL;
 
1281
 
 
1282
  (void)instate; /* no use for this yet */
 
1283
 
 
1284
  if(imapcode != '+') {
 
1285
    failf(data, "Access denied: %d", imapcode);
 
1286
    result = CURLE_LOGIN_DENIED;
 
1287
  }
 
1288
  else {
 
1289
    /* Create the authorisation message */
 
1290
    result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
 
1291
                                              conn->xoauth2_bearer,
 
1292
                                              &xoauth, &len);
 
1293
 
 
1294
    /* Send the message */
 
1295
    if(!result) {
 
1296
      if(xoauth) {
 
1297
        result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", xoauth);
 
1298
 
 
1299
        if(!result)
 
1300
          state(conn, IMAP_AUTHENTICATE_FINAL);
 
1301
      }
 
1302
 
 
1303
      Curl_safefree(xoauth);
 
1304
    }
 
1305
  }
 
1306
 
 
1307
  return result;
 
1308
}
 
1309
 
1246
1310
/* For final responses to the AUTHENTICATE sequence */
1247
1311
static CURLcode imap_state_auth_final_resp(struct connectdata *conn,
1248
1312
                                           int imapcode,
1316
1380
{
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;
1322
1386
  char tmp[20];
1407
1471
        return result;
1408
1472
 
1409
1473
      data->req.bytecount += chunk;
1410
 
      size -= chunk;
1411
1474
 
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,
 
1477
            size - chunk);
1414
1478
 
1415
1479
      /* Have we used the entire cache or just part of it?*/
1416
1480
      if(pp->cache_size > chunk) {
1427
1491
      }
1428
1492
    }
1429
1493
 
1430
 
    if(!size)
 
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);
1433
1497
    else {
1592
1656
      break;
1593
1657
#endif
1594
1658
 
 
1659
    case IMAP_AUTHENTICATE_XOAUTH2:
 
1660
      result = imap_state_auth_xoauth2_resp(conn, imapcode, imapc->state);
 
1661
      break;
 
1662
 
1595
1663
    case IMAP_AUTHENTICATE_FINAL:
1596
1664
      result = imap_state_auth_final_resp(conn, imapcode, imapc->state);
1597
1665
      break;
1642
1710
  CURLcode result = CURLE_OK;
1643
1711
  struct imap_conn *imapc = &conn->proto.imapc;
1644
1712
 
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);
1647
 
  else
1648
 
    result = Curl_pp_statemach(&imapc->pp, FALSE);
 
1715
    if(result || !imapc->ssldone)
 
1716
      return result;
 
1717
  }
1649
1718
 
 
1719
  result = Curl_pp_statemach(&imapc->pp, FALSE);
1650
1720
  *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
1651
1721
 
1652
1722
  return result;
1669
1739
{
1670
1740
  CURLcode result = CURLE_OK;
1671
1741
  struct SessionHandle *data = conn->data;
1672
 
  struct IMAP *imap = data->state.proto.imap;
 
1742
  struct IMAP *imap;
1673
1743
 
1674
 
  if(!imap) {
1675
 
    imap = data->state.proto.imap = calloc(sizeof(struct IMAP), 1);
1676
 
    if(!imap)
1677
 
      result = CURLE_OUT_OF_MEMORY;
1678
 
  }
 
1744
  imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
 
1745
  if(!imap)
 
1746
    result = CURLE_OUT_OF_MEMORY;
1679
1747
 
1680
1748
  return result;
1681
1749
}
1705
1773
 
1706
1774
  *done = FALSE; /* default to not done yet */
1707
1775
 
1708
 
  /* If there already is a protocol-specific struct allocated for this
1709
 
     sessionhandle, deal with it */
1710
 
  Curl_reset_reqproto(conn);
1711
 
 
1712
 
  /* Initialise the IMAP layer */
1713
 
  result = imap_init(conn);
1714
 
  if(result)
1715
 
    return result;
1716
 
 
1717
1776
  /* We always support persistent connections in IMAP */
1718
1777
  conn->bits.close = FALSE;
1719
1778
 
1759
1818
{
1760
1819
  CURLcode result = CURLE_OK;
1761
1820
  struct SessionHandle *data = conn->data;
1762
 
  struct IMAP *imap = data->state.proto.imap;
 
1821
  struct IMAP *imap = data->req.protop;
1763
1822
 
1764
1823
  (void)premature;
1765
1824
 
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;
1830
1889
 
1891
1950
 
1892
1951
  *done = FALSE; /* default to false */
1893
1952
 
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);
1900
 
  if(result)
1901
 
    return result;
1902
 
 
1903
1953
  /* Parse the URL path */
1904
1954
  result = imap_parse_url_path(conn);
1905
1955
  if(result)
1952
2002
/* Call this when the DO phase has completed */
1953
2003
static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
1954
2004
{
1955
 
  struct IMAP *imap = conn->data->state.proto.imap;
 
2005
  struct IMAP *imap = conn->data->req.protop;
1956
2006
 
1957
2007
  (void)connected;
1958
2008
 
2018
2068
{
2019
2069
  struct SessionHandle *data = conn->data;
2020
2070
 
 
2071
  /* Initialise the IMAP layer */
 
2072
  CURLcode result = imap_init(conn);
 
2073
  if(result)
 
2074
    return result;
 
2075
 
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 */
2033
2088
#endif
2034
2089
    }
2035
2090
 
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
2038
 
       otherwise */
2039
 
    conn->bits.close = FALSE;
 
2091
    /* set it up as an HTTP connection instead */
 
2092
    return conn->handler->setup_connection(conn);
2040
2093
#else
2041
2094
    failf(data, "IMAP over http proxy requires HTTP support built-in!");
2042
2095
    return CURLE_UNSUPPORTED_PROTOCOL;
2225
2278
 
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;
2240
2295
      else
2241
2296
        imapc->prefmech = SASL_AUTH_NONE;
2242
2297
    }
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;
2265
2320
 
2367
2422
{
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];
2372
2427
 
2373
2428
  if(custom) {