mirror of
https://github.com/curl/curl.git
synced 2024-11-27 05:50:21 +08:00
pop3: Added support for SASL based authentication mechanism detection
Added support for detecting the supported SASL authentication mechanisms via the AUTH command. There are two ways of detecting them, either by using the AUTH command, that will return -ERR if not supported or by using the CAPA command which will return SASL and the list of mechanisms if supported, not include SASL if SASL authentication is not supported or -ERR if the CAPA command is not supported. As such it seems simpler to use the AUTH command and fallback to normal clear text authentication if the the command is not supported. Additionally updated the test cases to return -ERR when the AUTH command is encountered. Additional test cases will be added when support for the individual authentication mechanisms is added.
This commit is contained in:
parent
dc454bd16b
commit
c267c53017
93
lib/pop3.c
93
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;
|
||||
|
@ -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! */
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user