~ubuntu-branches/ubuntu/precise/curl/precise-proposed

« back to all changes in this revision

Viewing changes to lib/smtp.c

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2011-11-25 17:30:45 UTC
  • mfrom: (3.4.23 sid)
  • Revision ID: package-import@ubuntu.com-20111125173045-2l3ni88jv16kath0
Tags: 7.22.0-3ubuntu1
* Merge from Debian unstable, remaining changes:
  - Drop dependencies not in main:
    + Build-Depends: Drop stunnel4 and libssh2-1-dev.
    + Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.
  - Add new libcurl3-udeb package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include "setup.h"
30
30
 
31
31
#ifndef CURL_DISABLE_SMTP
32
 
#include <stdio.h>
33
 
#include <string.h>
34
 
#include <stdlib.h>
35
 
#include <stdarg.h>
36
 
#include <ctype.h>
37
32
 
38
33
#ifdef HAVE_UNISTD_H
39
34
#include <unistd.h>
288
283
  struct smtp_conn *smtpc = &conn->proto.smtpc;
289
284
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
290
285
  /* for debug purposes */
291
 
  static const char * const names[]={
 
286
  static const char * const names[] = {
292
287
    "STOP",
293
288
    "SERVERGREET",
294
289
    "EHLO",
346
341
  return CURLE_OK;
347
342
}
348
343
 
349
 
static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr)
 
344
static CURLcode smtp_auth_plain_data(struct connectdata *conn,
 
345
                                     char **outptr, size_t *outlen)
350
346
{
351
347
  char plainauth[2 * MAX_CURL_USER_LENGTH + MAX_CURL_PASSWORD_LENGTH];
352
348
  size_t ulen;
355
351
  ulen = strlen(conn->user);
356
352
  plen = strlen(conn->passwd);
357
353
 
358
 
  if(2 * ulen + plen + 2 > sizeof plainauth)
359
 
    return 0;
 
354
  if(2 * ulen + plen + 2 > sizeof plainauth) {
 
355
    *outlen = 0;
 
356
    *outptr = NULL;
 
357
    return CURLE_OUT_OF_MEMORY; /* plainauth too small */
 
358
  }
360
359
 
361
360
  memcpy(plainauth, conn->user, ulen);
362
361
  plainauth[ulen] = '\0';
364
363
  plainauth[2 * ulen + 1] = '\0';
365
364
  memcpy(plainauth + 2 * ulen + 2, conn->passwd, plen);
366
365
  return Curl_base64_encode(conn->data, plainauth, 2 * ulen + plen + 2,
367
 
                            outptr);
 
366
                            outptr, outlen);
368
367
}
369
368
 
370
 
static size_t smtp_auth_login_user(struct connectdata * conn, char * * outptr)
 
369
static CURLcode smtp_auth_login_user(struct connectdata *conn,
 
370
                                     char **outptr, size_t *outlen)
371
371
{
372
 
  size_t ulen;
373
 
 
374
 
  ulen = strlen(conn->user);
 
372
  size_t ulen = strlen(conn->user);
375
373
 
376
374
  if(!ulen) {
377
375
    *outptr = strdup("=");
378
 
    return *outptr? 1: 0;
 
376
    if(*outptr) {
 
377
      *outlen = (size_t) 1;
 
378
      return CURLE_OK;
 
379
    }
 
380
    *outlen = 0;
 
381
    return CURLE_OUT_OF_MEMORY;
379
382
  }
380
383
 
381
 
  return Curl_base64_encode(conn->data, conn->user, ulen, outptr);
 
384
  return Curl_base64_encode(conn->data, conn->user, ulen, outptr, outlen);
382
385
}
383
386
 
384
387
static CURLcode smtp_authenticate(struct connectdata *conn)
398
401
    l = 1;
399
402
 
400
403
    /* Check supported authentication mechanisms by decreasing order of
401
 
       preference. */
 
404
       security. */
402
405
    mech = (const char *) NULL;         /* Avoid compiler warnings. */
403
406
    state1 = SMTP_STOP;
404
407
    state2 = SMTP_STOP;
410
413
    }
411
414
    else
412
415
#endif
413
 
    if(smtpc->authmechs & SMTP_AUTH_PLAIN) {
 
416
    if(smtpc->authmechs & SMTP_AUTH_LOGIN) {
 
417
      mech = "LOGIN";
 
418
      state1 = SMTP_AUTHLOGIN;
 
419
      state2 = SMTP_AUTHPASSWD;
 
420
      result = smtp_auth_login_user(conn, &initresp, &l);
 
421
    }
 
422
    else if(smtpc->authmechs & SMTP_AUTH_PLAIN) {
414
423
      mech = "PLAIN";
415
424
      state1 = SMTP_AUTHPLAIN;
416
425
      state2 = SMTP_AUTH;
417
 
      l = smtp_auth_plain_data(conn, &initresp);
418
 
    }
419
 
    else if(smtpc->authmechs & SMTP_AUTH_LOGIN) {
420
 
      mech = "LOGIN";
421
 
      state1 = SMTP_AUTHLOGIN;
422
 
      state2 = SMTP_AUTHPASSWD;
423
 
      l = smtp_auth_login_user(conn, &initresp);
 
426
      result = smtp_auth_plain_data(conn, &initresp, &l);
424
427
    }
425
428
    else {
426
429
      infof(conn->data, "No known auth mechanisms supported!\n");
428
431
    }
429
432
 
430
433
    if(!result) {
431
 
      if(!l)
432
 
        result = CURLE_OUT_OF_MEMORY;
433
 
      else if(initresp &&
434
 
              l + strlen(mech) <= 512 - 8) {   /* AUTH <mech> ...<crlf> */
 
434
      if(initresp &&
 
435
         l + strlen(mech) <= 512 - 8) { /* AUTH <mech> ...<crlf> */
435
436
        result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
436
 
        free(initresp);
437
437
 
438
438
        if(!result)
439
439
          state(conn, state2);
440
440
      }
441
441
      else {
442
 
        Curl_safefree(initresp);
443
 
 
444
442
        result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
445
443
 
446
444
        if(!result)
447
445
          state(conn, state1);
448
446
      }
 
447
      Curl_safefree(initresp);
449
448
    }
450
449
  }
451
450
 
466
465
  conn->handler = &Curl_handler_smtps;
467
466
}
468
467
#else
469
 
#define smtp_to_smtps(x)
 
468
#define smtp_to_smtps(x) Curl_nop_stmt
470
469
#endif
471
470
 
472
471
/* for STARTTLS responses */
576
575
{
577
576
  CURLcode result = CURLE_OK;
578
577
  struct SessionHandle *data = conn->data;
579
 
  size_t l;
580
 
  char * plainauth;
 
578
  size_t l = 0;
 
579
  char * plainauth = NULL;
581
580
 
582
581
  (void)instate; /* no use for this yet */
583
582
 
586
585
    result = CURLE_LOGIN_DENIED;
587
586
  }
588
587
  else {
589
 
    l = smtp_auth_plain_data(conn, &plainauth);
590
 
 
591
 
    if(!l)
592
 
      result = CURLE_OUT_OF_MEMORY;
593
 
    else {
594
 
      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
595
 
      free(plainauth);
596
 
 
597
 
      if(!result)
598
 
        state(conn, SMTP_AUTH);
 
588
    result = smtp_auth_plain_data(conn, &plainauth, &l);
 
589
 
 
590
    if(!result) {
 
591
      if(plainauth) {
 
592
        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
 
593
 
 
594
        if(!result)
 
595
          state(conn, SMTP_AUTH);
 
596
      }
 
597
      Curl_safefree(plainauth);
599
598
    }
600
599
  }
601
600
 
609
608
{
610
609
  CURLcode result = CURLE_OK;
611
610
  struct SessionHandle *data = conn->data;
612
 
  size_t l;
613
 
  char * authuser;
 
611
  size_t l = 0;
 
612
  char * authuser = NULL;
614
613
 
615
614
  (void)instate; /* no use for this yet */
616
615
 
619
618
    result = CURLE_LOGIN_DENIED;
620
619
  }
621
620
  else {
622
 
    l = smtp_auth_login_user(conn, &authuser);
623
 
 
624
 
    if(!l)
625
 
      result = CURLE_OUT_OF_MEMORY;
626
 
    else {
627
 
      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
628
 
      free(authuser);
629
 
 
630
 
      if(!result)
631
 
        state(conn, SMTP_AUTHPASSWD);
 
621
    result = smtp_auth_login_user(conn, &authuser, &l);
 
622
 
 
623
    if(!result) {
 
624
      if(authuser) {
 
625
        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
 
626
 
 
627
        if(!result)
 
628
          state(conn, SMTP_AUTHPASSWD);
 
629
      }
 
630
      Curl_safefree(authuser);
632
631
    }
633
632
  }
634
633
 
643
642
  CURLcode result = CURLE_OK;
644
643
  struct SessionHandle *data = conn->data;
645
644
  size_t plen;
646
 
  size_t l;
647
 
  char *authpasswd;
 
645
  size_t l = 0;
 
646
  char *authpasswd = NULL;
648
647
 
649
648
  (void)instate; /* no use for this yet */
650
649
 
658
657
    if(!plen)
659
658
      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "=");
660
659
    else {
661
 
      l = Curl_base64_encode(data, conn->passwd, plen, &authpasswd);
662
 
 
663
 
      if(!l)
664
 
        result = CURLE_OUT_OF_MEMORY;
665
 
      else {
666
 
        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
667
 
        free(authpasswd);
668
 
 
669
 
        if(!result)
670
 
          state(conn, SMTP_AUTH);
 
660
      result = Curl_base64_encode(data, conn->passwd, plen, &authpasswd, &l);
 
661
 
 
662
      if(!result) {
 
663
        if(authpasswd) {
 
664
          result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
 
665
 
 
666
          if(!result)
 
667
            state(conn, SMTP_AUTH);
 
668
        }
 
669
        Curl_safefree(authpasswd);
671
670
      }
672
671
    }
673
672
  }
687
686
  char * chlg64 = data->state.buffer;
688
687
  unsigned char * chlg;
689
688
  size_t chlglen;
690
 
  size_t l;
691
 
  char * rplyb64;
 
689
  size_t l = 0;
 
690
  char * rplyb64 = NULL;
692
691
  HMAC_context * ctxt;
693
692
  unsigned char digest[16];
694
693
  char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1];
716
715
    if(++l) {
717
716
      chlg64[l] = '\0';
718
717
 
719
 
      chlglen = Curl_base64_decode(chlg64, &chlg);
720
 
      if(!chlglen)
721
 
        return CURLE_OUT_OF_MEMORY;
 
718
      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
 
719
      if(result)
 
720
        return result;
722
721
    }
723
722
  }
724
723
 
728
727
                        (unsigned int)(strlen(conn->passwd)));
729
728
 
730
729
  if(!ctxt) {
731
 
    if(chlg)
732
 
      free(chlg);
733
 
 
 
730
    Curl_safefree(chlg);
734
731
    return CURLE_OUT_OF_MEMORY;
735
732
  }
736
733
 
737
734
  if(chlglen > 0)
738
735
    Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen));
739
736
 
740
 
  if(chlg)
741
 
    free(chlg);
 
737
  Curl_safefree(chlg);
742
738
 
743
739
  Curl_HMAC_final(ctxt, digest);
744
740
 
751
747
           digest[12], digest[13], digest[14], digest[15]);
752
748
 
753
749
  /* Encode it to base64 and send it. */
754
 
  l = Curl_base64_encode(data, reply, 0, &rplyb64);
755
 
 
756
 
  if(!l)
757
 
    result = CURLE_OUT_OF_MEMORY;
758
 
  else {
759
 
    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
760
 
    free(rplyb64);
761
 
 
762
 
    if(!result)
763
 
      state(conn, SMTP_AUTH);
 
750
  result = Curl_base64_encode(data, reply, 0, &rplyb64, &l);
 
751
 
 
752
  if(!result) {
 
753
    if(rplyb64) {
 
754
      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
 
755
 
 
756
      if(!result)
 
757
        state(conn, SMTP_AUTH);
 
758
    }
 
759
    Curl_safefree(rplyb64);
764
760
  }
765
761
 
766
762
  return result;
931
927
{
932
928
  CURLcode result;
933
929
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
934
 
  struct SessionHandle *data=conn->data;
 
930
  struct SessionHandle *data = conn->data;
935
931
  int smtpcode;
936
932
  struct smtp_conn *smtpc = &conn->proto.smtpc;
937
933
  struct pingpong *pp = &smtpc->pp;
1036
1032
  else
1037
1033
    result = Curl_pp_multi_statemach(&smtpc->pp);
1038
1034
 
1039
 
  *done = (bool)(smtpc->state == SMTP_STOP);
 
1035
  *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
1040
1036
 
1041
1037
  return result;
1042
1038
}
1087
1083
 * smtp_connect() should do everything that is to be considered a part of
1088
1084
 * the connection phase.
1089
1085
 *
1090
 
 * The variable 'done' points to will be TRUE if the protocol-layer connect
1091
 
 * phase is done when this function returns, or FALSE is not. When called as
1092
 
 * a part of the easy interface, it will always be TRUE.
 
1086
 * The variable pointed to by 'done' will be TRUE if the protocol-layer
 
1087
 * connect phase is done when this function returns, or FALSE if not. When
 
1088
 * called as a part of the easy interface, it will always be TRUE.
1093
1089
 */
1094
1090
static CURLcode smtp_connect(struct connectdata *conn,
1095
1091
                             bool *done) /* see description above */
1096
1092
{
1097
1093
  CURLcode result;
1098
1094
  struct smtp_conn *smtpc = &conn->proto.smtpc;
1099
 
  struct SessionHandle *data=conn->data;
1100
 
  struct pingpong *pp=&smtpc->pp;
 
1095
  struct SessionHandle *data = conn->data;
 
1096
  struct pingpong *pp = &smtpc->pp;
1101
1097
  const char *path = conn->data->state.path;
1102
1098
  int len;
1103
1099
  char localhost[1024 + 1];
1204
1200
{
1205
1201
  struct SessionHandle *data = conn->data;
1206
1202
  struct FTP *smtp = data->state.proto.smtp;
1207
 
  CURLcode result=CURLE_OK;
 
1203
  CURLcode result = CURLE_OK;
1208
1204
  ssize_t bytes_written;
1209
1205
  (void)premature;
1210
1206
 
1234
1230
 
1235
1231
  if(status == CURLE_OK) {
1236
1232
    struct smtp_conn *smtpc = &conn->proto.smtpc;
1237
 
    struct pingpong *pp= &smtpc->pp;
 
1233
    struct pingpong *pp = &smtpc->pp;
1238
1234
    pp->response = Curl_tvnow(); /* timeout relative now */
1239
1235
 
1240
1236
    state(conn, SMTP_POSTDATA);
1268
1264
                     bool *dophase_done)
1269
1265
{
1270
1266
  /* this is SMTP and no proxy */
1271
 
  CURLcode result=CURLE_OK;
 
1267
  CURLcode result = CURLE_OK;
1272
1268
 
1273
1269
  DEBUGF(infof(conn->data, "DO phase starts\n"));
1274
1270
 
1292
1288
    result = smtp_easy_statemach(conn);
1293
1289
    *dophase_done = TRUE; /* with the easy interface we are done here */
1294
1290
  }
1295
 
  *connected = conn->bits.tcpconnect;
 
1291
  *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1296
1292
 
1297
1293
  if(*dophase_done)
1298
1294
    DEBUGF(infof(conn->data, "DO phase is complete\n"));
1361
1357
 * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
1362
1358
 * resources. BLOCKING.
1363
1359
 */
1364
 
static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
 
1360
static CURLcode smtp_disconnect(struct connectdata *conn,
 
1361
                                bool dead_connection)
1365
1362
{
1366
 
  struct smtp_conn *smtpc= &conn->proto.smtpc;
 
1363
  struct smtp_conn *smtpc = &conn->proto.smtpc;
1367
1364
 
1368
1365
  /* We cannot send quit unconditionally. If this connection is stale or
1369
1366
     bad in any way, sending quit and waiting around here will make the
1389
1386
                                  bool connected)
1390
1387
{
1391
1388
  struct FTP *smtp = conn->data->state.proto.smtp;
1392
 
  struct smtp_conn *smtpc= &conn->proto.smtpc;
 
1389
  struct smtp_conn *smtpc = &conn->proto.smtpc;
1393
1390
  (void)connected;
1394
1391
 
1395
1392
  if(smtp->transfer != FTPTRANSFER_BODY)
1404
1401
 
1405
1402
/* called from multi.c while DOing */
1406
1403
static CURLcode smtp_doing(struct connectdata *conn,
1407
 
                               bool *dophase_done)
 
1404
                           bool *dophase_done)
1408
1405
{
1409
1406
  CURLcode result;
1410
1407
  result = smtp_multi_statemach(conn, dophase_done);
1428
1425
 */
1429
1426
static
1430
1427
CURLcode smtp_regular_transfer(struct connectdata *conn,
1431
 
                              bool *dophase_done)
 
1428
                               bool *dophase_done)
1432
1429
{
1433
 
  CURLcode result=CURLE_OK;
1434
 
  bool connected=FALSE;
 
1430
  CURLcode result = CURLE_OK;
 
1431
  bool connected = FALSE;
1435
1432
  struct SessionHandle *data = conn->data;
1436
1433
  data->req.size = -1; /* make sure this is unknown at this point */
1437
1434
 
1458
1455
  return result;
1459
1456
}
1460
1457
 
1461
 
static CURLcode smtp_setup_connection(struct connectdata * conn)
 
1458
static CURLcode smtp_setup_connection(struct connectdata *conn)
1462
1459
{
1463
1460
  struct SessionHandle *data = conn->data;
1464
1461
 
1505
1502
  struct SessionHandle *data = conn->data;
1506
1503
 
1507
1504
  if(data->state.scratch == NULL)
1508
 
    data->state.scratch = malloc(2*BUFSIZE);
 
1505
    data->state.scratch = malloc(2 * BUFSIZE);
1509
1506
  if(data->state.scratch == NULL) {
1510
1507
    failf (data, "Failed to alloc scratch buffer!");
1511
1508
    return CURLE_OUT_OF_MEMORY;
1515
1512
  for(i = 0, si = 0; i < nread; i++, si++) {
1516
1513
    ssize_t left = nread - i;
1517
1514
 
1518
 
    if(left>= (ssize_t)(SMTP_EOB_LEN-smtpc->eob)) {
1519
 
      if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i],
1520
 
                 SMTP_EOB_LEN-smtpc->eob)) {
 
1515
    if(left >= (ssize_t)(SMTP_EOB_LEN - smtpc->eob)) {
 
1516
      if(!memcmp(SMTP_EOB + smtpc->eob, &data->req.upload_fromhere[i],
 
1517
                 SMTP_EOB_LEN - smtpc->eob)) {
1521
1518
        /* It matched, copy the replacement data to the target buffer
1522
1519
           instead. Note that the replacement does not contain the
1523
1520
           trailing CRLF but we instead continue to match on that one
1525
1522
        */
1526
1523
        memcpy(&data->state.scratch[si], SMTP_EOB_REPL,
1527
1524
               SMTP_EOB_REPL_LEN);
1528
 
        si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments
1529
 
                                          it */
1530
 
        i+=SMTP_EOB_LEN-smtpc->eob-1-2;
 
1525
        si += SMTP_EOB_REPL_LEN - 1; /* minus one since the for() increments
 
1526
                                        it */
 
1527
        i += SMTP_EOB_LEN - smtpc->eob - 1 - 2;
1531
1528
        smtpc->eob = 0; /* start over */
1532
1529
        continue;
1533
1530
      }
1534
1531
    }
1535
 
    else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i],
 
1532
    else if(!memcmp(SMTP_EOB + smtpc->eob, &data->req.upload_fromhere[i],
1536
1533
                    left)) {
1537
1534
      /* the last piece of the data matches the EOB so we can't send that
1538
1535
         until we know the rest of it */