diff options
-rw-r--r-- | lib/pop3.c | 93 | ||||
-rw-r--r-- | lib/pop3.h | 2 | ||||
-rw-r--r-- | tests/data/test808 | 2 | ||||
-rw-r--r-- | tests/data/test809 | 2 | ||||
-rw-r--r-- | tests/data/test810 | 2 | ||||
-rw-r--r-- | tests/data/test811 | 2 | ||||
-rw-r--r-- | tests/data/test812 | 2 | ||||
-rw-r--r-- | tests/data/test813 | 2 | ||||
-rw-r--r-- | tests/data/test815 | 4 |
9 files changed, 107 insertions, 4 deletions
diff --git a/lib/pop3.c b/lib/pop3.c index ae540378f..2f47fd1a9 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -79,6 +79,7 @@ #include "url.h" #include "rawstr.h" #include "strtoofft.h" +#include "curl_sasl.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -208,11 +209,15 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { #endif /* Function that checks for an ending pop3 status code at the start of the - given string */ + given string, but also detects the allowed authentication mechanisms + according to the AUTH response. */ static int pop3_endofresp(struct pingpong *pp, int *resp) { char *line = pp->linestart_resp; size_t len = pp->nread_resp; + struct connectdata *conn = pp->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + size_t wordlen; if((len < 3 || memcmp("+OK", line, 3)) && (len < 4 || memcmp("-ERR", line, 4))) @@ -220,6 +225,46 @@ static int pop3_endofresp(struct pingpong *pp, int *resp) *resp = line[1]; /* O or E */ + if(pop3c->state == POP3_AUTH && len >= 3 && !memcmp(line, "+OK", 3)) { + line += 3; + len -= 3; + + for(;;) { + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + line++; + len--; + } + + if(!len || *line == '.') + break; + + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + if(wordlen == 5 && !memcmp(line, "LOGIN", 5)) + pop3c->authmechs |= SASL_AUTH_LOGIN; + else if(wordlen == 5 && !memcmp(line, "PLAIN", 5)) + pop3c->authmechs |= SASL_AUTH_PLAIN; + else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8)) + pop3c->authmechs |= SASL_AUTH_CRAM_MD5; + else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10)) + pop3c->authmechs |= SASL_AUTH_DIGEST_MD5; + else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6)) + pop3c->authmechs |= SASL_AUTH_GSSAPI; + else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) + pop3c->authmechs |= SASL_AUTH_EXTERNAL; + else if(wordlen == 4 && !memcmp(line, "NTLM", 4)) + pop3c->authmechs |= SASL_AUTH_NTLM; + + line += wordlen; + len -= wordlen; + } + } + return TRUE; } @@ -231,6 +276,7 @@ static void state(struct connectdata *conn, pop3state newstate) static const char * const names[]={ "STOP", "SERVERGREET", + "AUTH", "USER", "PASS", "STARTTLS", @@ -248,6 +294,24 @@ static void state(struct connectdata *conn, pop3state newstate) pop3c->state = newstate; } +static CURLcode pop3_state_auth(struct connectdata *conn) +{ + CURLcode result; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + pop3c->authmechs = 0; /* No known authentication mechanisms yet */ + + /* send AUTH */ + result = Curl_pp_sendf(&pop3c->pp, "AUTH"); + + if(result) + return result; + + state(conn, POP3_AUTH); + + return CURLE_OK; +} + static CURLcode pop3_state_user(struct connectdata *conn) { CURLcode result; @@ -303,7 +367,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, state(conn, POP3_STARTTLS); } else - result = pop3_state_user(conn); + result = pop3_state_auth(conn); return result; } @@ -325,14 +389,14 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, state(conn, POP3_STOP); } else - result = pop3_state_user(conn); + result = pop3_state_auth(conn); } else { /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(CURLE_OK == result) { pop3_to_pop3s(conn); - result = pop3_state_user(conn); + result = pop3_state_auth(conn); } else { state(conn, POP3_STOP); @@ -342,6 +406,23 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, return result; } +/* For AUTH responses */ +static CURLcode pop3_state_auth_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *pop3 = data->state.proto.pop3; + + (void)instate; /* no use for this yet */ + + /* Proceed with clear text authentication as we used to for now */ + result = pop3_state_user(conn); + + return result; +} + /* For USER responses */ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, @@ -506,6 +587,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); break; + case POP3_AUTH: + result = pop3_state_auth_resp(conn, pop3code, pop3c->state); + break; + case POP3_USER: result = pop3_state_user_resp(conn, pop3code, pop3c->state); break; diff --git a/lib/pop3.h b/lib/pop3.h index 99b514e4c..01701e4d7 100644 --- a/lib/pop3.h +++ b/lib/pop3.h @@ -29,6 +29,7 @@ typedef enum { POP3_STOP, /* do nothing state, stops the state machine */ POP3_SERVERGREET, /* waiting for the initial greeting immediately after a connect */ + POP3_AUTH, POP3_USER, POP3_PASS, POP3_STARTTLS, @@ -46,6 +47,7 @@ struct pop3_conn { size_t eob; /* number of bytes of the EOB (End Of Body) that has been received thus far */ size_t strip; /* number of bytes from the start to ignore as non-body */ + unsigned int authmechs; /* Accepted authentication methods */ pop3state state; /* always use pop3.c:state() to change state! */ }; diff --git a/tests/data/test808 b/tests/data/test808 index 756801c6b..57e1382b1 100644 --- a/tests/data/test808 +++ b/tests/data/test808 @@ -10,6 +10,7 @@ LIST # Server-side <reply> <servercmd> +REPLY AUTH -ERR unsupported command
REPLY LIST +OK 808 100 </servercmd> </reply> @@ -32,6 +33,7 @@ pop3://%HOSTIP:%POP3PORT/808 -l -u user:secret # Verify data after the test has been "shot" <verify> <protocol> +AUTH
USER user
PASS secret
LIST 808
diff --git a/tests/data/test809 b/tests/data/test809 index e9f22dd83..7cd04c891 100644 --- a/tests/data/test809 +++ b/tests/data/test809 @@ -11,6 +11,7 @@ FAILURE # Server-side <reply> <servercmd> +REPLY AUTH -ERR unsupported command
REPLY LIST -ERR no such message </servercmd> </reply> @@ -36,6 +37,7 @@ pop3://%HOSTIP:%POP3PORT/809 -l -u user:secret 56 </errorcode> <protocol> +AUTH
USER user
PASS secret
LIST 809
diff --git a/tests/data/test810 b/tests/data/test810 index 09f9562a3..2e24c295b 100644 --- a/tests/data/test810 +++ b/tests/data/test810 @@ -13,6 +13,7 @@ LIST # packets <servercmd> SLOWDOWN +REPLY AUTH -ERR unsupported command
</servercmd> # When doing LIST, we get the default list output hard-coded in the test # POP3 server @@ -41,6 +42,7 @@ pop3://%HOSTIP:%POP3PORT/ -u user:secret # Verify data after the test has been "shot" <verify> <protocol> +AUTH
USER user
PASS secret
LIST
diff --git a/tests/data/test811 b/tests/data/test811 index ca107abcc..06fa57dcb 100644 --- a/tests/data/test811 +++ b/tests/data/test811 @@ -10,6 +10,7 @@ LIST # Server-side <reply> <servercmd> +REPLY AUTH -ERR unsupported command
REPLY LIST +OK but no messages\r\n. </servercmd> <datacheck> @@ -34,6 +35,7 @@ pop3://%HOSTIP:%POP3PORT/ -u user:secret # Verify data after the test has been "shot" <verify> <protocol> +AUTH
USER user
PASS secret
LIST
diff --git a/tests/data/test812 b/tests/data/test812 index eb2a83669..9f1ba9296 100644 --- a/tests/data/test812 +++ b/tests/data/test812 @@ -11,6 +11,7 @@ FAILURE # Server-side <reply> <servercmd> +REPLY AUTH -ERR unsupported command
REPLY RETR -ERR no such message </servercmd> </reply> @@ -36,6 +37,7 @@ pop3://%HOSTIP:%POP3PORT/812 -u user:secret 56 </errorcode> <protocol> +AUTH
USER user
PASS secret
RETR 812
diff --git a/tests/data/test813 b/tests/data/test813 index 4953af413..13cfd7074 100644 --- a/tests/data/test813 +++ b/tests/data/test813 @@ -10,6 +10,7 @@ FAILURE # Server-side <reply> <servercmd> +REPLY AUTH -ERR unsupported command
REPLY PASS -ERR invalid login </servercmd> </reply> @@ -35,6 +36,7 @@ pop3://%HOSTIP:%POP3PORT/813 -u user:wrong 67 </errorcode> <protocol> +AUTH
USER user
PASS wrong
QUIT
diff --git a/tests/data/test815 b/tests/data/test815 index df7b1b6dd..9779fe690 100644 --- a/tests/data/test815 +++ b/tests/data/test815 @@ -9,6 +9,9 @@ RETR # # Server-side <reply> +<servercmd>
+REPLY AUTH -ERR unsupported command
+</servercmd>
<data> From: me@somewhere
To: fake@nowhere
@@ -49,6 +52,7 @@ pop3://%HOSTIP:%POP3PORT/815 -u user:secret # Verify data after the test has been "shot" <verify> <protocol> +AUTH
USER user
PASS secret
RETR 815
|