aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/pop3.c93
-rw-r--r--lib/pop3.h2
-rw-r--r--tests/data/test8082
-rw-r--r--tests/data/test8092
-rw-r--r--tests/data/test8102
-rw-r--r--tests/data/test8112
-rw-r--r--tests/data/test8122
-rw-r--r--tests/data/test8132
-rw-r--r--tests/data/test8154
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