aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/pop3.c93
-rw-r--r--lib/pop3.h2
2 files changed, 91 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! */
};