~ubuntu-branches/ubuntu/quantal/curl/quantal

« back to all changes in this revision

Viewing changes to lib/smtp.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2012-05-28 12:21:13 UTC
  • mfrom: (3.4.29 sid)
  • Revision ID: package-import@ubuntu.com-20120528122113-i5f42lajprljoudn
Tags: 7.26.0-1ubuntu1
* Resynchronise with 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.
* Adjust udeb configure flags handling to something easier to merge in
  future.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 * RFC3207 SMTP over TLS
23
23
 * RFC4954 SMTP Authentication
24
24
 * RFC2195 CRAM-MD5 authentication
 
25
 * RFC2831 DIGEST-MD5 authentication
25
26
 * RFC4616 PLAIN authentication
26
27
 *
27
28
 ***************************************************************************/
82
83
#include "rawstr.h"
83
84
#include "strtoofft.h"
84
85
#include "curl_base64.h"
 
86
#include "curl_rand.h"
85
87
#include "curl_md5.h"
86
88
#include "curl_hmac.h"
87
89
#include "curl_gethostname.h"
98
100
/* Local API functions */
99
101
static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
100
102
static CURLcode smtp_do(struct connectdata *conn, bool *done);
101
 
static CURLcode smtp_done(struct connectdata *conn,
102
 
                          CURLcode, bool premature);
 
103
static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
 
104
                          bool premature);
103
105
static CURLcode smtp_connect(struct connectdata *conn, bool *done);
104
106
static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
105
107
static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
106
108
static int smtp_getsock(struct connectdata *conn,
107
109
                        curl_socket_t *socks,
108
110
                        int numsocks);
109
 
static CURLcode smtp_doing(struct connectdata *conn,
110
 
                           bool *dophase_done);
 
111
static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
111
112
static CURLcode smtp_setup_connection(struct connectdata *conn);
112
113
static CURLcode smtp_state_upgrade_tls(struct connectdata *conn);
113
114
 
228
229
  size_t wordlen;
229
230
 
230
231
  if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
231
 
    return FALSE;       /* Nothing for us. */
 
232
    return FALSE;       /* Nothing for us */
232
233
 
233
234
  if((result = (line[3] == ' ')) != 0)
234
235
    *resp = curlx_sltosi(strtol(line, NULL, 10));
279
280
  return result;
280
281
}
281
282
 
 
283
#ifndef CURL_DISABLE_CRYPTO_AUTH
 
284
/* Retrieves the value for a corresponding key from the challenge string
 
285
 * returns TRUE if the key could be found, FALSE if it does not exists
 
286
 */
 
287
static bool smtp_digest_get_key_value(const unsigned char *chlg,
 
288
                                      const char *key,
 
289
                                      char *value,
 
290
                                      size_t max_val_len,
 
291
                                      char end_char)
 
292
{
 
293
  char *find_pos;
 
294
  size_t i;
 
295
 
 
296
  find_pos = strstr((const char *) chlg, key);
 
297
  if(!find_pos)
 
298
    return FALSE;
 
299
 
 
300
  find_pos += strlen(key);
 
301
 
 
302
  for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
 
303
    value[i] = *find_pos++;
 
304
  value[i] = '\0';
 
305
 
 
306
  return TRUE;
 
307
}
 
308
#endif
 
309
 
282
310
/* This is the ONLY way to change SMTP state! */
283
 
static void state(struct connectdata *conn,
284
 
                  smtpstate newstate)
 
311
static void state(struct connectdata *conn, smtpstate newstate)
285
312
{
286
313
  struct smtp_conn *smtpc = &conn->proto.smtpc;
287
314
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
297
324
    "AUTHLOGIN",
298
325
    "AUTHPASSWD",
299
326
    "AUTHCRAM",
 
327
    "AUTHDIGESTMD5",
 
328
    "AUTHDIGESTMD5_RESP",
300
329
    "AUTHNTLM",
301
330
    "AUTHNTLM_TYPE2MSG",
302
331
    "AUTH",
363
392
  ulen = strlen(conn->user);
364
393
  plen = strlen(conn->passwd);
365
394
 
366
 
  if(2 * ulen + plen + 2 > sizeof plainauth) {
 
395
  if(2 * ulen + plen + 2 > sizeof(plainauth)) {
367
396
    *outlen = 0;
368
397
    *outptr = NULL;
369
398
    return CURLE_OUT_OF_MEMORY; /* plainauth too small */
374
403
  memcpy(plainauth + ulen + 1, conn->user, ulen);
375
404
  plainauth[2 * ulen + 1] = '\0';
376
405
  memcpy(plainauth + 2 * ulen + 2, conn->passwd, plen);
 
406
 
377
407
  return Curl_base64_encode(conn->data, plainauth, 2 * ulen + plen + 2,
378
408
                            outptr, outlen);
379
409
}
416
446
  smtpstate state2 = SMTP_STOP;
417
447
 
418
448
  /* Check we have a username and password to authenticate with and end the
419
 
     connect phase if we don't. */
 
449
     connect phase if we don't */
420
450
  if(!conn->bits.user_passwd) {
421
451
    state(conn, SMTP_STOP);
422
452
 
424
454
  }
425
455
 
426
456
  /* Check supported authentication mechanisms by decreasing order of
427
 
     security. */
 
457
     security */
428
458
#ifndef CURL_DISABLE_CRYPTO_AUTH
429
 
  if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) {
 
459
  if(smtpc->authmechs & SMTP_AUTH_DIGEST_MD5) {
 
460
    mech = "DIGEST-MD5";
 
461
    state1 = SMTP_AUTHDIGESTMD5;
 
462
    smtpc->authused = SMTP_AUTH_DIGEST_MD5;
 
463
  }
 
464
  else if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) {
430
465
    mech = "CRAM-MD5";
431
466
    state1 = SMTP_AUTHCRAMMD5;
432
467
    smtpc->authused = SMTP_AUTH_CRAM_MD5;
459
494
  }
460
495
  else {
461
496
    infof(conn->data, "No known auth mechanisms supported!\n");
462
 
    result = CURLE_LOGIN_DENIED;      /* Other mechanisms not supported. */
 
497
    result = CURLE_LOGIN_DENIED;      /* Other mechanisms not supported */
463
498
  }
464
499
 
465
500
  if(!result) {
499
534
#define smtp_to_smtps(x) Curl_nop_stmt
500
535
#endif
501
536
 
 
537
/* for the initial server greeting */
 
538
static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
 
539
                                            int smtpcode,
 
540
                                            smtpstate instate)
 
541
{
 
542
  CURLcode result = CURLE_OK;
 
543
  struct SessionHandle *data = conn->data;
 
544
 
 
545
  (void)instate; /* no use for this yet */
 
546
 
 
547
  if(smtpcode/100 != 2) {
 
548
    failf(data, "Got unexpected smtp-server response: %d", smtpcode);
 
549
    return CURLE_FTP_WEIRD_SERVER_REPLY;
 
550
  }
 
551
 
 
552
  result = smtp_state_ehlo(conn);
 
553
 
 
554
  return result;
 
555
}
 
556
 
502
557
/* for STARTTLS responses */
503
558
static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
504
559
                                         int smtpcode,
506
561
{
507
562
  CURLcode result = CURLE_OK;
508
563
  struct SessionHandle *data = conn->data;
 
564
 
509
565
  (void)instate; /* no use for this yet */
510
566
 
511
567
  if(smtpcode != 220) {
667
723
  return result;
668
724
}
669
725
 
670
 
/* for responses to user entry of AUTH LOGIN. */
 
726
/* for responses to user entry of AUTH LOGIN */
671
727
static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn,
672
728
                                           int smtpcode,
673
729
                                           smtpstate instate)
709
765
 
710
766
#ifndef CURL_DISABLE_CRYPTO_AUTH
711
767
 
712
 
/* for AUTH CRAM-MD5 responses. */
 
768
/* for AUTH CRAM-MD5 responses */
713
769
static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
714
770
                                         int smtpcode,
715
771
                                         smtpstate instate)
722
778
  size_t len = 0;
723
779
  char *rplyb64 = NULL;
724
780
  HMAC_context *ctxt;
725
 
  unsigned char digest[16];
726
 
  char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1];
 
781
  unsigned char digest[MD5_DIGEST_LEN];
 
782
  char reply[MAX_CURL_USER_LENGTH + 2 * MD5_DIGEST_LEN + 1];
727
783
 
728
784
  (void)instate; /* no use for this yet */
729
785
 
732
788
    return CURLE_LOGIN_DENIED;
733
789
  }
734
790
 
735
 
  /* Get the challenge. */
 
791
  /* Get the challenge */
736
792
  for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
737
793
    ;
738
794
 
754
810
    }
755
811
  }
756
812
 
757
 
  /* Compute digest. */
 
813
  /* Compute digest */
758
814
  ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
759
815
                        (const unsigned char *) conn->passwd,
760
816
                        curlx_uztoui(strlen(conn->passwd)));
771
827
 
772
828
  Curl_HMAC_final(ctxt, digest);
773
829
 
774
 
  /* Prepare the reply. */
775
 
  snprintf(reply, sizeof reply,
 
830
  /* Prepare the reply */
 
831
  snprintf(reply, sizeof(reply),
776
832
   "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
777
833
           conn->user, digest[0], digest[1], digest[2], digest[3], digest[4],
778
834
           digest[5],
779
835
           digest[6], digest[7], digest[8], digest[9], digest[10], digest[11],
780
836
           digest[12], digest[13], digest[14], digest[15]);
781
837
 
782
 
  /* Encode it to base64 and send it. */
 
838
  /* Encode it to base64 and send it */
783
839
  result = Curl_base64_encode(data, reply, 0, &rplyb64, &len);
784
840
 
785
841
  if(!result) {
795
851
  return result;
796
852
}
797
853
 
 
854
/* for AUTH DIGEST-MD5 challenge responses */
 
855
static CURLcode smtp_state_authdigest_resp(struct connectdata *conn,
 
856
                                           int smtpcode,
 
857
                                           smtpstate instate)
 
858
{
 
859
  static const char table16[] = "0123456789abcdef";
 
860
 
 
861
  CURLcode result = CURLE_OK;
 
862
  struct SessionHandle *data = conn->data;
 
863
  char *chlg64 = data->state.buffer;
 
864
  unsigned char *chlg;
 
865
  size_t chlglen;
 
866
  size_t len = 0;
 
867
  size_t i;
 
868
  char *rplyb64 = NULL;
 
869
  MD5_context *ctxt;
 
870
  unsigned char digest[MD5_DIGEST_LEN];
 
871
  char HA1_hex[2 * MD5_DIGEST_LEN + 1];
 
872
  char HA2_hex[2 * MD5_DIGEST_LEN + 1];
 
873
  char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
 
874
 
 
875
  char nonce[64];
 
876
  char realm[128];
 
877
  char alg[64];
 
878
  char nonceCount[] = "00000001";
 
879
  char cnonce[]     = "12345678"; /* will be changed */
 
880
  char method[]     = "AUTHENTICATE";
 
881
  char qop[]        = "auth";
 
882
  char uri[128]     = "smtp/";
 
883
  char response[512];
 
884
 
 
885
  (void)instate; /* no use for this yet */
 
886
 
 
887
  if(smtpcode != 334) {
 
888
    failf(data, "Access denied: %d", smtpcode);
 
889
    return CURLE_LOGIN_DENIED;
 
890
  }
 
891
 
 
892
  /* Get the challenge */
 
893
  for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
 
894
    ;
 
895
 
 
896
  chlg = (unsigned char *) NULL;
 
897
  chlglen = 0;
 
898
 
 
899
  result = Curl_base64_decode(chlg64, &chlg, &chlglen);
 
900
 
 
901
  if(result)
 
902
    return result;
 
903
 
 
904
  /* Retrieve nonce string from the challenge */
 
905
  if(!smtp_digest_get_key_value(chlg, "nonce=\"", nonce,
 
906
                                sizeof(nonce), '\"')) {
 
907
    Curl_safefree(chlg);
 
908
    return CURLE_LOGIN_DENIED;
 
909
  }
 
910
 
 
911
  /* Retrieve realm string from the challenge */
 
912
  if(!smtp_digest_get_key_value(chlg, "realm=\"", realm,
 
913
                                sizeof(realm), '\"')) {
 
914
    /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
 
915
    strcpy(realm, "");
 
916
  }
 
917
 
 
918
  /* Retrieve algorithm string from the challenge */
 
919
  if(!smtp_digest_get_key_value(chlg, "algorithm=", alg, sizeof(alg), ',')) {
 
920
    Curl_safefree(chlg);
 
921
    return CURLE_LOGIN_DENIED;
 
922
  }
 
923
 
 
924
  Curl_safefree(chlg);
 
925
 
 
926
  /* We do not support other algorithms */
 
927
  if(strcmp(alg, "md5-sess") != 0)
 
928
    return CURLE_LOGIN_DENIED;
 
929
 
 
930
  /* Generate 64 bits of random data */
 
931
  for(i = 0; i < 8; i++)
 
932
    cnonce[i] = table16[Curl_rand()%16];
 
933
 
 
934
  /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
 
935
  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
 
936
  if(!ctxt)
 
937
    return CURLE_OUT_OF_MEMORY;
 
938
 
 
939
  Curl_MD5_update(ctxt, (const unsigned char *) conn->user,
 
940
                  curlx_uztoui(strlen(conn->user)));
 
941
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
942
  Curl_MD5_update(ctxt, (const unsigned char *) realm,
 
943
                  curlx_uztoui(strlen(realm)));
 
944
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
945
  Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
 
946
                  curlx_uztoui(strlen(conn->passwd)));
 
947
  Curl_MD5_final(ctxt, digest);
 
948
 
 
949
  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
 
950
  if(!ctxt)
 
951
    return CURLE_OUT_OF_MEMORY;
 
952
 
 
953
  Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
 
954
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
955
  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
 
956
                  curlx_uztoui(strlen(nonce)));
 
957
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
958
  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
 
959
                  curlx_uztoui(strlen(cnonce)));
 
960
  Curl_MD5_final(ctxt, digest);
 
961
 
 
962
  /* Convert calculated 16 octet hex into 32 bytes string */
 
963
  for(i = 0; i < MD5_DIGEST_LEN; i++)
 
964
    snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
 
965
 
 
966
  /* Orepare URL string, append realm to the protocol */
 
967
  strcat(uri, realm);
 
968
 
 
969
  /* Calculate H(A2) */
 
970
  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
 
971
  if(!ctxt)
 
972
    return CURLE_OUT_OF_MEMORY;
 
973
 
 
974
  Curl_MD5_update(ctxt, (const unsigned char *) method,
 
975
                  curlx_uztoui(strlen(method)));
 
976
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
977
  Curl_MD5_update(ctxt, (const unsigned char *) uri,
 
978
                  curlx_uztoui(strlen(uri)));
 
979
  Curl_MD5_final(ctxt, digest);
 
980
 
 
981
  for(i = 0; i < MD5_DIGEST_LEN; i++)
 
982
    snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
 
983
 
 
984
  /* Now calculate the response hash */
 
985
  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
 
986
  if(!ctxt)
 
987
    return CURLE_OUT_OF_MEMORY;
 
988
 
 
989
  Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
 
990
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
991
  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
 
992
                  curlx_uztoui(strlen(nonce)));
 
993
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
994
 
 
995
  Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
 
996
                  curlx_uztoui(strlen(nonceCount)));
 
997
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
998
  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
 
999
                  curlx_uztoui(strlen(cnonce)));
 
1000
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
1001
  Curl_MD5_update(ctxt, (const unsigned char *) qop,
 
1002
                  curlx_uztoui(strlen(qop)));
 
1003
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
 
1004
 
 
1005
  Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
 
1006
  Curl_MD5_final(ctxt, digest);
 
1007
 
 
1008
  for(i = 0; i < MD5_DIGEST_LEN; i++)
 
1009
    snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
 
1010
 
 
1011
  strcpy(response, "username=\"");
 
1012
  strcat(response, conn->user);
 
1013
  strcat(response, "\",realm=\"");
 
1014
  strcat(response, realm);
 
1015
  strcat(response, "\",nonce=\"");
 
1016
  strcat(response, nonce);
 
1017
  strcat(response, "\",cnonce=\"");
 
1018
  strcat(response, cnonce);
 
1019
  strcat(response, "\",nc=");
 
1020
  strcat(response, nonceCount);
 
1021
  strcat(response, ",digest-uri=\"");
 
1022
  strcat(response, uri);
 
1023
  strcat(response, "\",response=");
 
1024
  strcat(response, resp_hash_hex);
 
1025
 
 
1026
  /* Encode it to base64 and send it */
 
1027
  result = Curl_base64_encode(data, response, 0, &rplyb64, &len);
 
1028
 
 
1029
  if(!result) {
 
1030
    if(rplyb64) {
 
1031
      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
 
1032
 
 
1033
      if(!result)
 
1034
        state(conn, SMTP_AUTHDIGESTMD5_RESP);
 
1035
    }
 
1036
 
 
1037
    Curl_safefree(rplyb64);
 
1038
  }
 
1039
 
 
1040
  return result;
 
1041
}
 
1042
 
 
1043
/* For AUTH DIGEST-MD5 challenge-response responses */
 
1044
static CURLcode smtp_state_authdigest_resp_resp(struct connectdata *conn,
 
1045
                                                int smtpcode,
 
1046
                                                smtpstate instate)
 
1047
{
 
1048
  CURLcode result = CURLE_OK;
 
1049
  struct SessionHandle *data = conn->data;
 
1050
 
 
1051
  (void)instate; /* no use for this yet */
 
1052
 
 
1053
  if(smtpcode != 334) {
 
1054
    failf(data, "Authentication failed: %d", smtpcode);
 
1055
    result = CURLE_LOGIN_DENIED;
 
1056
  }
 
1057
  else {
 
1058
    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "");
 
1059
 
 
1060
    if(!result)
 
1061
      state(conn, SMTP_AUTH);
 
1062
  }
 
1063
 
 
1064
  return result;
 
1065
}
 
1066
 
798
1067
#endif
799
1068
 
800
1069
#ifdef USE_NTLM
801
 
/* for the AUTH NTLM (without initial response) response. */
 
1070
/* for the AUTH NTLM (without initial response) response */
802
1071
static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn,
803
1072
                                          int smtpcode,
804
1073
                                          smtpstate instate)
824
1093
        if(!result)
825
1094
          state(conn, SMTP_AUTHNTLM_TYPE2MSG);
826
1095
      }
 
1096
 
827
1097
      Curl_safefree(type1msg);
828
1098
    }
829
1099
  }
831
1101
  return result;
832
1102
}
833
1103
 
834
 
/* for the NTLM type-2 response (sent in reponse to our type-1 message). */
 
1104
/* for the NTLM type-2 response (sent in reponse to our type-1 message) */
835
1105
static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
836
1106
                                                   int smtpcode,
837
1107
                                                   smtpstate instate)
861
1131
          if(!result)
862
1132
            state(conn, SMTP_AUTH);
863
1133
        }
 
1134
 
864
1135
        Curl_safefree(type3msg);
865
1136
      }
866
1137
    }
870
1141
}
871
1142
#endif
872
1143
 
873
 
/* for final responses to AUTH sequences. */
 
1144
/* for the final responses to the AUTH sequence */
874
1145
static CURLcode smtp_state_auth_resp(struct connectdata *conn,
875
1146
                                     int smtpcode,
876
1147
                                     smtpstate instate)
885
1156
    result = CURLE_LOGIN_DENIED;
886
1157
  }
887
1158
  else
888
 
    state(conn, SMTP_STOP);             /* End of connect phase. */
 
1159
    state(conn, SMTP_STOP);             /* End of connect phase */
889
1160
 
890
1161
  return result;
891
1162
}
991
1262
{
992
1263
  CURLcode result = CURLE_OK;
993
1264
  struct SessionHandle *data = conn->data;
 
1265
 
994
1266
  (void)instate; /* no use for this yet */
995
1267
 
996
1268
  if(smtpcode/100 != 2) {
1015
1287
{
1016
1288
  CURLcode result = CURLE_OK;
1017
1289
  struct SessionHandle *data = conn->data;
 
1290
 
1018
1291
  (void)instate; /* no use for this yet */
1019
1292
 
1020
1293
  if(smtpcode/100 != 2) {
1066
1339
                      FIRSTSOCKET, smtp->bytecountp);
1067
1340
 
1068
1341
  state(conn, SMTP_STOP);
 
1342
 
1069
1343
  return CURLE_OK;
1070
1344
}
1071
1345
 
1072
1346
/* for the POSTDATA response, which is received after the entire DATA
1073
1347
   part has been sent off to the server */
1074
1348
static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
1075
 
                                     int smtpcode,
1076
 
                                     smtpstate instate)
 
1349
                                         int smtpcode,
 
1350
                                         smtpstate instate)
1077
1351
{
1078
1352
  CURLcode result = CURLE_OK;
1079
1353
 
1117
1391
    /* we have now received a full SMTP server response */
1118
1392
    switch(smtpc->state) {
1119
1393
    case SMTP_SERVERGREET:
1120
 
      if(smtpcode/100 != 2) {
1121
 
        failf(data, "Got unexpected smtp-server response: %d", smtpcode);
1122
 
        return CURLE_FTP_WEIRD_SERVER_REPLY;
1123
 
      }
1124
 
 
1125
 
      result = smtp_state_ehlo(conn);
1126
 
      if(result)
1127
 
        return result;
 
1394
      result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
1128
1395
      break;
1129
1396
 
1130
1397
    case SMTP_EHLO:
1155
1422
    case SMTP_AUTHCRAMMD5:
1156
1423
      result = smtp_state_authcram_resp(conn, smtpcode, smtpc->state);
1157
1424
      break;
 
1425
 
 
1426
    case SMTP_AUTHDIGESTMD5:
 
1427
      result = smtp_state_authdigest_resp(conn, smtpcode, smtpc->state);
 
1428
      break;
 
1429
 
 
1430
    case SMTP_AUTHDIGESTMD5_RESP:
 
1431
      result = smtp_state_authdigest_resp_resp(conn, smtpcode, smtpc->state);
 
1432
      break;
1158
1433
#endif
1159
1434
 
1160
1435
#ifdef USE_NTLM
1201
1476
}
1202
1477
 
1203
1478
/* called repeatedly until done from multi.c */
1204
 
static CURLcode smtp_multi_statemach(struct connectdata *conn,
1205
 
                                     bool *done)
 
1479
static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
1206
1480
{
1207
1481
  struct smtp_conn *smtpc = &conn->proto.smtpc;
1208
1482
  CURLcode result;
1267
1541
 * connect phase is done when this function returns, or FALSE if not. When
1268
1542
 * called as a part of the easy interface, it will always be TRUE.
1269
1543
 */
1270
 
static CURLcode smtp_connect(struct connectdata *conn,
1271
 
                             bool *done) /* see description above */
 
1544
static CURLcode smtp_connect(struct connectdata *conn, bool *done)
1272
1545
{
1273
1546
  CURLcode result;
1274
1547
  struct smtp_conn *smtpc = &conn->proto.smtpc;
1304
1577
      return result;
1305
1578
  }
1306
1579
 
1307
 
  Curl_pp_init(pp); /* init the response reader stuff */
 
1580
  /* Initialise the response reader stuff */
 
1581
  Curl_pp_init(pp);
1308
1582
 
1309
1583
  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
1310
1584
  pp->statemach_act = smtp_statemach_act;
1548
1822
}
1549
1823
 
1550
1824
/* call this when the DO phase has completed */
1551
 
static CURLcode smtp_dophase_done(struct connectdata *conn,
1552
 
                                  bool connected)
 
1825
static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
1553
1826
{
1554
1827
  struct FTP *smtp = conn->data->state.proto.smtp;
1555
1828
  struct smtp_conn *smtpc = &conn->proto.smtpc;
1565
1838
}
1566
1839
 
1567
1840
/* called from multi.c while DOing */
1568
 
static CURLcode smtp_doing(struct connectdata *conn,
1569
 
                           bool *dophase_done)
 
1841
static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
1570
1842
{
1571
 
  CURLcode result;
1572
 
  result = smtp_multi_statemach(conn, dophase_done);
1573
 
 
1574
 
  if(*dophase_done) {
1575
 
    result = smtp_dophase_done(conn, FALSE /* not connected */);
1576
 
 
 
1843
  CURLcode result = smtp_multi_statemach(conn, dophase_done);
 
1844
 
 
1845
  if(result)
 
1846
    DEBUGF(infof(conn->data, "DO phase failed\n"));
 
1847
  else
1577
1848
    DEBUGF(infof(conn->data, "DO phase is complete\n"));
1578
 
  }
 
1849
 
 
1850
  if(*dophase_done)
 
1851
    smtp_dophase_done(conn, FALSE /* not connected */);
1579
1852
 
1580
1853
  return result;
1581
1854
}
1657
1930
 
1658
1931
CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
1659
1932
{
1660
 
  /* When sending SMTP payload, we must detect CRLF.CRLF sequences in
1661
 
   * the data and make sure it is sent as CRLF..CRLF instead, as
1662
 
   * otherwise it will wrongly be detected as end of data by the server.
1663
 
   */
 
1933
  /* When sending a SMTP payload we must detect CRLF. sequences making sure
 
1934
     they are sent as CRLF.. instead, as a . on the beginning of a line will
 
1935
     be deleted by the server when not part of an EOB terminator and a
 
1936
     genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
 
1937
     data by the server.
 
1938
  */
1664
1939
  ssize_t i;
1665
1940
  ssize_t si;
1666
1941
  struct smtp_conn *smtpc = &conn->proto.smtpc;
1667
1942
  struct SessionHandle *data = conn->data;
1668
1943
 
1669
1944
  /* Do we need to allocate the scatch buffer? */
1670
 
  if(!data->state.scratch)  {
 
1945
  if(!data->state.scratch) {
1671
1946
    data->state.scratch = malloc(2 * BUFSIZE);
1672
1947
 
1673
1948
    if(!data->state.scratch) {
1686
1961
      memcpy(&data->state.scratch[si], SMTP_EOB, smtpc->eob);
1687
1962
      si += smtpc->eob;
1688
1963
 
1689
 
      /* then compare the first byte */
 
1964
      /* Then compare the first byte */
1690
1965
      if(SMTP_EOB[0] == data->req.upload_fromhere[i])
1691
1966
        smtpc->eob = 1;
1692
1967
      else
1693
1968
        smtpc->eob = 0;
1694
1969
    }
1695
1970
 
1696
 
    if(SMTP_EOB_LEN == smtpc->eob) {
1697
 
      /* It matched, copy the replacement data to the target buffer
1698
 
         instead. Note that the replacement does not contain the
1699
 
         trailing CRLF but we instead continue to match on that one
1700
 
         to deal with repeated sequences. Like CRLF.CRLF.CRLF etc
1701
 
      */
1702
 
      memcpy(&data->state.scratch[si], SMTP_EOB_REPL,
1703
 
             SMTP_EOB_REPL_LEN);
 
1971
    /* Do we have a match for CRLF. as per RFC-2821, sect. 4.5.2 */
 
1972
    if(SMTP_EOB_FIND_LEN == smtpc->eob) {
 
1973
      /* Copy the replacement data to the target buffer */
 
1974
      memcpy(&data->state.scratch[si], SMTP_EOB_REPL, SMTP_EOB_REPL_LEN);
1704
1975
      si += SMTP_EOB_REPL_LEN;
1705
 
      smtpc->eob = 2; /* start over at two bytes */
 
1976
      smtpc->eob = 0;
1706
1977
    }
1707
1978
    else if(!smtpc->eob)
1708
1979
      data->state.scratch[si++] = data->req.upload_fromhere[i];
1716
1987
  }
1717
1988
 
1718
1989
  if(si != nread) {
1719
 
    /* only use the new buffer if we replaced something */
 
1990
    /* Only use the new buffer if we replaced something */
1720
1991
    nread = si;
1721
1992
 
1722
 
    /* upload from the new (replaced) buffer instead */
 
1993
    /* Upload from the new (replaced) buffer instead */
1723
1994
    data->req.upload_fromhere = data->state.scratch;
1724
1995
 
1725
 
    /* set the new amount too */
 
1996
    /* Set the new amount too */
1726
1997
    data->req.upload_present = nread;
1727
1998
  }
1728
1999