245
/* Are we processing servergreet responses? */
246
if(pop3c->state == POP3_SERVERGREET) {
247
/* Look for the APOP timestamp */
248
if(len >= 3 && line[len - 3] == '>') {
249
for(i = 0; i < len - 3; ++i) {
251
/* Calculate the length of the timestamp */
252
size_t timestamplen = len - 2 - i;
254
/* Allocate some memory for the timestamp */
255
pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
257
if(!pop3c->apoptimestamp)
260
/* Copy the timestamp */
261
memcpy(pop3c->apoptimestamp, line + i, timestamplen);
262
pop3c->apoptimestamp[timestamplen] = '\0';
268
247
/* Are we processing CAPA command responses? */
269
else if(pop3c->state == POP3_CAPA) {
248
if(pop3c->state == POP3_CAPA) {
270
249
/* Do we have the terminating line? */
271
if(len >= 1 && !memcmp(line, ".", 1)) {
250
if(len >= 1 && !memcmp(line, ".", 1))
277
/* Does the server support the STLS capability? */
278
if(len >= 4 && !memcmp(line, "STLS", 4))
279
pop3c->tls_supported = TRUE;
281
/* Does the server support clear text authentication? */
282
else if(len >= 4 && !memcmp(line, "USER", 4))
283
pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
285
/* Does the server support APOP authentication? */
286
else if(len >= 4 && !memcmp(line, "APOP", 4))
287
pop3c->authtypes |= POP3_TYPE_APOP;
289
/* Does the server support SASL based authentication? */
290
else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
291
pop3c->authtypes |= POP3_TYPE_SASL;
293
/* Advance past the SASL keyword */
297
/* Loop through the data line */
300
(*line == ' ' || *line == '\t' ||
301
*line == '\r' || *line == '\n')) {
310
/* Extract the word */
311
for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
312
line[wordlen] != '\t' && line[wordlen] != '\r' &&
313
line[wordlen] != '\n';)
316
/* Test the word for a matching authentication mechanism */
317
if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
318
pop3c->authmechs |= SASL_MECH_LOGIN;
319
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
320
pop3c->authmechs |= SASL_MECH_PLAIN;
321
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
322
pop3c->authmechs |= SASL_MECH_CRAM_MD5;
323
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
324
pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
325
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
326
pop3c->authmechs |= SASL_MECH_GSSAPI;
327
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
328
pop3c->authmechs |= SASL_MECH_EXTERNAL;
329
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
330
pop3c->authmechs |= SASL_MECH_NTLM;
331
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
332
pop3c->authmechs |= SASL_MECH_XOAUTH2;
342
258
/* Do we have a command or continuation response? */
575
491
/***********************************************************************
577
* pop3_perform_authenticate()
579
* Sends an AUTH command allowing the client to login with the appropriate
580
* SASL authentication mechanism.
582
* Additionally, the function will perform fallback to APOP and USER commands
583
* should a common mechanism not be available between the client and server.
585
static CURLcode pop3_perform_authenticate(struct connectdata *conn)
587
CURLcode result = CURLE_OK;
588
struct SessionHandle *data = conn->data;
493
* pop3_perform_auth()
495
* Sends an AUTH command allowing the client to login with the given SASL
496
* authentication mechanism.
498
static CURLcode pop3_perform_auth(struct connectdata *conn,
500
const char *initresp, size_t len,
501
pop3state state1, pop3state state2)
503
CURLcode result = CURLE_OK;
504
struct pop3_conn *pop3c = &conn->proto.pop3c;
506
if(initresp && 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */
507
/* Send the AUTH command with the initial response */
508
result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
514
/* Send the AUTH command */
515
result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
524
/***********************************************************************
526
* pop3_perform_authentication()
528
* Initiates the authentication sequence, with the appropriate SASL
529
* authentication mechanism, falling back to APOP and clear text should a
530
* common mechanism not be available between the client and server.
532
static CURLcode pop3_perform_authentication(struct connectdata *conn)
534
CURLcode result = CURLE_OK;
589
535
struct pop3_conn *pop3c = &conn->proto.pop3c;
590
536
const char *mech = NULL;
591
537
char *initresp = NULL;
604
/* Calculate the supported authentication mechanism, by decreasing order of
605
security, as well as the initial response where appropriate */
606
if(pop3c->authtypes & POP3_TYPE_SASL) {
607
#ifndef CURL_DISABLE_CRYPTO_AUTH
608
if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
609
(pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
610
mech = SASL_MECH_STRING_DIGEST_MD5;
611
state1 = POP3_AUTH_DIGESTMD5;
612
pop3c->authused = SASL_MECH_DIGEST_MD5;
614
else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
615
(pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
616
mech = SASL_MECH_STRING_CRAM_MD5;
617
state1 = POP3_AUTH_CRAMMD5;
618
pop3c->authused = SASL_MECH_CRAM_MD5;
623
if((pop3c->authmechs & SASL_MECH_NTLM) &&
624
(pop3c->prefmech & SASL_MECH_NTLM)) {
625
mech = SASL_MECH_STRING_NTLM;
626
state1 = POP3_AUTH_NTLM;
627
state2 = POP3_AUTH_NTLM_TYPE2MSG;
628
pop3c->authused = SASL_MECH_NTLM;
630
if(data->set.sasl_ir)
631
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
637
if(((pop3c->authmechs & SASL_MECH_XOAUTH2) &&
638
(pop3c->prefmech & SASL_MECH_XOAUTH2) &&
639
(pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
640
mech = SASL_MECH_STRING_XOAUTH2;
641
state1 = POP3_AUTH_XOAUTH2;
642
state2 = POP3_AUTH_FINAL;
643
pop3c->authused = SASL_MECH_XOAUTH2;
645
if(data->set.sasl_ir)
646
result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
647
conn->xoauth2_bearer,
650
else if((pop3c->authmechs & SASL_MECH_LOGIN) &&
651
(pop3c->prefmech & SASL_MECH_LOGIN)) {
652
mech = SASL_MECH_STRING_LOGIN;
653
state1 = POP3_AUTH_LOGIN;
654
state2 = POP3_AUTH_LOGIN_PASSWD;
655
pop3c->authused = SASL_MECH_LOGIN;
657
if(data->set.sasl_ir)
658
result = Curl_sasl_create_login_message(conn->data, conn->user,
661
else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
662
(pop3c->prefmech & SASL_MECH_PLAIN)) {
663
mech = SASL_MECH_STRING_PLAIN;
664
state1 = POP3_AUTH_PLAIN;
665
state2 = POP3_AUTH_FINAL;
666
pop3c->authused = SASL_MECH_PLAIN;
668
if(data->set.sasl_ir)
669
result = Curl_sasl_create_plain_message(conn->data, conn->user,
670
conn->passwd, &initresp,
550
/* Calculate the SASL login details */
551
if(pop3c->authtypes & POP3_TYPE_SASL)
552
result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
676
556
if(mech && (pop3c->preftype & POP3_TYPE_SASL)) {
677
557
/* Perform SASL based authentication */
679
8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */
680
result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
686
result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
558
result = pop3_perform_auth(conn, mech, initresp, len, state1, state2);
692
560
Curl_safefree(initresp);
784
656
failf(data, "Got unexpected pop3-server response");
785
657
result = CURLE_FTP_WEIRD_SERVER_REPLY;
660
/* Does the server support APOP authentication? */
661
if(len >= 4 && line[len - 2] == '>') {
662
/* Look for the APOP timestamp */
663
for(i = 3; i < len - 2; ++i) {
665
/* Calculate the length of the timestamp */
666
size_t timestamplen = len - 1 - i;
670
/* Allocate some memory for the timestamp */
671
pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
673
if(!pop3c->apoptimestamp)
676
/* Copy the timestamp */
677
memcpy(pop3c->apoptimestamp, line + i, timestamplen);
678
pop3c->apoptimestamp[timestamplen] = '\0';
680
/* Store the APOP capability */
681
pop3c->authtypes |= POP3_TYPE_APOP;
788
687
result = pop3_perform_capa(conn);
797
697
CURLcode result = CURLE_OK;
798
698
struct SessionHandle *data = conn->data;
799
699
struct pop3_conn *pop3c = &conn->proto.pop3c;
700
const char *line = data->state.buffer;
701
size_t len = strlen(line);
801
704
(void)instate; /* no use for this yet */
804
result = pop3_perform_user(conn);
805
else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
806
/* We don't have a SSL/TLS connection yet, but SSL is requested */
807
if(pop3c->tls_supported)
808
/* Switch to TLS connection now */
809
result = pop3_perform_starttls(conn);
810
else if(data->set.use_ssl == CURLUSESSL_TRY)
811
/* Fallback and carry on with authentication */
812
result = pop3_perform_authenticate(conn);
814
failf(data, "STLS not supported.");
815
result = CURLE_USE_SSL_FAILED;
819
result = pop3_perform_authenticate(conn);
706
/* Do we have a untagged response? */
707
if(pop3code == '*') {
708
/* Does the server support the STLS capability? */
709
if(len >= 4 && !memcmp(line, "STLS", 4))
710
pop3c->tls_supported = TRUE;
712
/* Does the server support clear text authentication? */
713
else if(len >= 4 && !memcmp(line, "USER", 4))
714
pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
716
/* Does the server support SASL based authentication? */
717
else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
718
pop3c->authtypes |= POP3_TYPE_SASL;
720
/* Advance past the SASL keyword */
724
/* Loop through the data line */
727
(*line == ' ' || *line == '\t' ||
728
*line == '\r' || *line == '\n')) {
737
/* Extract the word */
738
for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
739
line[wordlen] != '\t' && line[wordlen] != '\r' &&
740
line[wordlen] != '\n';)
743
/* Test the word for a matching authentication mechanism */
744
if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
745
pop3c->authmechs |= SASL_MECH_LOGIN;
746
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
747
pop3c->authmechs |= SASL_MECH_PLAIN;
748
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
749
pop3c->authmechs |= SASL_MECH_CRAM_MD5;
750
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
751
pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
752
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
753
pop3c->authmechs |= SASL_MECH_GSSAPI;
754
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
755
pop3c->authmechs |= SASL_MECH_EXTERNAL;
756
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
757
pop3c->authmechs |= SASL_MECH_NTLM;
758
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
759
pop3c->authmechs |= SASL_MECH_XOAUTH2;
766
else if(pop3code == '+') {
767
if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
768
/* We don't have a SSL/TLS connection yet, but SSL is requested */
769
if(pop3c->tls_supported)
770
/* Switch to TLS connection now */
771
result = pop3_perform_starttls(conn);
772
else if(data->set.use_ssl == CURLUSESSL_TRY)
773
/* Fallback and carry on with authentication */
774
result = pop3_perform_authentication(conn);
776
failf(data, "STLS not supported.");
777
result = CURLE_USE_SSL_FAILED;
781
result = pop3_perform_authentication(conn);
784
/* Clear text is supported when CAPA isn't recognised */
785
pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
787
result = pop3_perform_authentication(conn);
1206
1175
pop3state instate)
1177
CURLcode result = CURLE_OK;
1208
1178
struct SessionHandle *data = conn->data;
1179
struct pop3_conn *pop3c = &conn->proto.pop3c;
1180
const char *mech = NULL;
1181
char *initresp = NULL;
1183
pop3state state1 = POP3_STOP;
1184
pop3state state2 = POP3_STOP;
1210
1186
(void)pop3code;
1211
1187
(void)instate; /* no use for this yet */
1213
failf(data, "Authentication cancelled");
1215
return CURLE_LOGIN_DENIED;
1189
/* Remove the offending mechanism from the supported list */
1190
pop3c->authmechs ^= pop3c->authused;
1192
/* Calculate alternative SASL login details */
1193
result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
1197
/* Do we have any mechanisms left or can we fallback to another
1198
authentication type? */
1200
/* Retry SASL based authentication */
1201
result = pop3_perform_auth(conn, mech, initresp, len, state1, state2);
1203
Curl_safefree(initresp);
1205
#ifndef CURL_DISABLE_CRYPTO_AUTH
1206
else if((pop3c->authtypes & POP3_TYPE_APOP) &&
1207
(pop3c->preftype & POP3_TYPE_APOP))
1208
/* Perform APOP authentication */
1209
result = pop3_perform_apop(conn);
1211
else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
1212
(pop3c->preftype & POP3_TYPE_CLEARTEXT))
1213
/* Perform clear text authentication */
1214
result = pop3_perform_user(conn);
1216
failf(data, "Authentication cancelled");
1218
result = CURLE_LOGIN_DENIED;
1218
1225
/* For final responses in the AUTH sequence */
1824
1834
struct pop3_conn *pop3c = &conn->proto.pop3c;
1825
1835
const char *options = conn->options;
1826
1836
const char *ptr = options;
1839
while(ptr && *ptr) {
1829
1840
const char *key = ptr;
1831
1842
while(*ptr && *ptr != '=')
1834
1845
if(strnequal(key, "AUTH", 4)) {
1835
const char *value = ptr + 1;
1837
if(strequal(value, "*")) {
1847
const char *value = ++ptr;
1851
pop3c->preftype = POP3_TYPE_NONE;
1852
pop3c->prefmech = SASL_AUTH_NONE;
1855
while(*ptr && *ptr != ';') {
1860
if(strnequal(value, "*", len)) {
1838
1861
pop3c->preftype = POP3_TYPE_ANY;
1839
1862
pop3c->prefmech = SASL_AUTH_ANY;
1841
else if(strequal(value, "+APOP")) {
1864
else if(strnequal(value, "+APOP", len)) {
1842
1865
pop3c->preftype = POP3_TYPE_APOP;
1843
1866
pop3c->prefmech = SASL_AUTH_NONE;
1845
else if(strequal(value, SASL_MECH_STRING_LOGIN)) {
1846
pop3c->preftype = POP3_TYPE_SASL;
1847
pop3c->prefmech = SASL_MECH_LOGIN;
1849
else if(strequal(value, SASL_MECH_STRING_PLAIN)) {
1850
pop3c->preftype = POP3_TYPE_SASL;
1851
pop3c->prefmech = SASL_MECH_PLAIN;
1853
else if(strequal(value, SASL_MECH_STRING_CRAM_MD5)) {
1854
pop3c->preftype = POP3_TYPE_SASL;
1855
pop3c->prefmech = SASL_MECH_CRAM_MD5;
1857
else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5)) {
1858
pop3c->preftype = POP3_TYPE_SASL;
1859
pop3c->prefmech = SASL_MECH_DIGEST_MD5;
1861
else if(strequal(value, SASL_MECH_STRING_GSSAPI)) {
1862
pop3c->preftype = POP3_TYPE_SASL;
1863
pop3c->prefmech = SASL_MECH_GSSAPI;
1865
else if(strequal(value, SASL_MECH_STRING_NTLM)) {
1866
pop3c->preftype = POP3_TYPE_SASL;
1867
pop3c->prefmech = SASL_MECH_NTLM;
1869
else if(strequal(value, SASL_MECH_STRING_XOAUTH2)) {
1870
pop3c->preftype = POP3_TYPE_SASL;
1871
pop3c->prefmech = SASL_MECH_XOAUTH2;
1874
pop3c->preftype = POP3_TYPE_NONE;
1875
pop3c->prefmech = SASL_AUTH_NONE;
1868
else if(strnequal(value, SASL_MECH_STRING_LOGIN, len)) {
1869
pop3c->preftype = POP3_TYPE_SASL;
1870
pop3c->prefmech |= SASL_MECH_LOGIN;
1872
else if(strnequal(value, SASL_MECH_STRING_PLAIN, len)) {
1873
pop3c->preftype = POP3_TYPE_SASL;
1874
pop3c->prefmech |= SASL_MECH_PLAIN;
1876
else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len)) {
1877
pop3c->preftype = POP3_TYPE_SASL;
1878
pop3c->prefmech |= SASL_MECH_CRAM_MD5;
1880
else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len)) {
1881
pop3c->preftype = POP3_TYPE_SASL;
1882
pop3c->prefmech |= SASL_MECH_DIGEST_MD5;
1884
else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len)) {
1885
pop3c->preftype = POP3_TYPE_SASL;
1886
pop3c->prefmech |= SASL_MECH_GSSAPI;
1888
else if(strnequal(value, SASL_MECH_STRING_NTLM, len)) {
1889
pop3c->preftype = POP3_TYPE_SASL;
1890
pop3c->prefmech |= SASL_MECH_NTLM;
1892
else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len)) {
1893
pop3c->preftype = POP3_TYPE_SASL;
1894
pop3c->prefmech |= SASL_MECH_XOAUTH2;
1879
1901
result = CURLE_URL_MALFORMAT;
1922
1944
/***********************************************************************
1946
* pop3_calc_sasl_details()
1948
* Calculate the required login details for SASL authentication.
1950
static CURLcode pop3_calc_sasl_details(struct connectdata *conn,
1952
char **initresp, size_t *len,
1953
pop3state *state1, pop3state *state2)
1955
CURLcode result = CURLE_OK;
1956
struct SessionHandle *data = conn->data;
1957
struct pop3_conn *pop3c = &conn->proto.pop3c;
1959
/* Calculate the supported authentication mechanism, by decreasing order of
1960
security, as well as the initial response where appropriate */
1961
#ifndef CURL_DISABLE_CRYPTO_AUTH
1962
if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
1963
(pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
1964
*mech = SASL_MECH_STRING_DIGEST_MD5;
1965
*state1 = POP3_AUTH_DIGESTMD5;
1966
pop3c->authused = SASL_MECH_DIGEST_MD5;
1968
else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
1969
(pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
1970
*mech = SASL_MECH_STRING_CRAM_MD5;
1971
*state1 = POP3_AUTH_CRAMMD5;
1972
pop3c->authused = SASL_MECH_CRAM_MD5;
1977
if((pop3c->authmechs & SASL_MECH_NTLM) &&
1978
(pop3c->prefmech & SASL_MECH_NTLM)) {
1979
*mech = SASL_MECH_STRING_NTLM;
1980
*state1 = POP3_AUTH_NTLM;
1981
*state2 = POP3_AUTH_NTLM_TYPE2MSG;
1982
pop3c->authused = SASL_MECH_NTLM;
1984
if(data->set.sasl_ir)
1985
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1991
if(((pop3c->authmechs & SASL_MECH_XOAUTH2) &&
1992
(pop3c->prefmech & SASL_MECH_XOAUTH2) &&
1993
(pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
1994
*mech = SASL_MECH_STRING_XOAUTH2;
1995
*state1 = POP3_AUTH_XOAUTH2;
1996
*state2 = POP3_AUTH_FINAL;
1997
pop3c->authused = SASL_MECH_XOAUTH2;
1999
if(data->set.sasl_ir)
2000
result = Curl_sasl_create_xoauth2_message(data, conn->user,
2001
conn->xoauth2_bearer,
2004
else if((pop3c->authmechs & SASL_MECH_LOGIN) &&
2005
(pop3c->prefmech & SASL_MECH_LOGIN)) {
2006
*mech = SASL_MECH_STRING_LOGIN;
2007
*state1 = POP3_AUTH_LOGIN;
2008
*state2 = POP3_AUTH_LOGIN_PASSWD;
2009
pop3c->authused = SASL_MECH_LOGIN;
2011
if(data->set.sasl_ir)
2012
result = Curl_sasl_create_login_message(data, conn->user, initresp, len);
2014
else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
2015
(pop3c->prefmech & SASL_MECH_PLAIN)) {
2016
*mech = SASL_MECH_STRING_PLAIN;
2017
*state1 = POP3_AUTH_PLAIN;
2018
*state2 = POP3_AUTH_FINAL;
2019
pop3c->authused = SASL_MECH_PLAIN;
2021
if(data->set.sasl_ir)
2022
result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
2029
/***********************************************************************
1924
2031
* Curl_pop3_write()
1926
2033
* This function scans the body after the end-of-body and writes everything