diff options
-rw-r--r-- | lib/pop3.c | 112 | ||||
-rw-r--r-- | lib/pop3.h | 3 |
2 files changed, 110 insertions, 5 deletions
diff --git a/lib/pop3.c b/lib/pop3.c index d3b84f342..38cde50d0 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -18,9 +18,11 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * RFC1734 POP3 Authentication * RFC1939 POP3 protocol * RFC2384 POP URL Scheme * RFC2595 Using TLS with IMAP, POP3 and ACAP + * RFC4616 PLAIN authentication * ***************************************************************************/ @@ -279,6 +281,8 @@ static void state(struct connectdata *conn, pop3state newstate) "SERVERGREET", "STARTTLS", "AUTH", + "AUTH_PLAIN", + "AUTH_FINAL", "USER", "PASS", "COMMAND", @@ -301,6 +305,7 @@ static CURLcode pop3_state_auth(struct connectdata *conn) struct pop3_conn *pop3c = &conn->proto.pop3c; pop3c->authmechs = 0; /* No known authentication mechanisms yet */ + pop3c->authused = 0; /* Clear the authentication mechanism used */ /* send AUTH */ result = Curl_pp_sendf(&pop3c->pp, "AUTH"); @@ -329,6 +334,35 @@ static CURLcode pop3_state_user(struct connectdata *conn) return CURLE_OK; } +static CURLcode pop3_authenticate(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *mech = NULL; + pop3state authstate = POP3_STOP; + + /* Check supported authentication mechanisms by decreasing order of + security */ + if(pop3c->authmechs & SASL_AUTH_PLAIN) { + mech = "PLAIN"; + authstate = POP3_AUTH_PLAIN; + pop3c->authused = SASL_AUTH_PLAIN; + } + else { + infof(conn->data, "No known SASL auth mechanisms supported!\n"); + result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported */ + } + + if(!result) { + result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); + + if(!result) + state(conn, authstate); + } + + return result; +} + /* For the POP3 "protocol connect" and "doing" phases only */ static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) @@ -408,12 +442,72 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, } /* For AUTH responses */ -static CURLcode pop3_state_auth_resp(struct connectdata *conn) +static CURLcode pop3_state_auth_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') + result = pop3_state_user(conn); + else + result = pop3_authenticate(conn); + + return result; +} + +/* For AUTH PLAIN responses */ +static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + size_t len = 0; + char *plainauth = NULL; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Access denied. %c", pop3code); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_sasl_create_plain_message(conn->data, conn->user, + conn->passwd, &plainauth, &len); + + if(!result) { + if(plainauth) { + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth); + + if(!result) + state(conn, POP3_AUTH_FINAL); + } + Curl_safefree(plainauth); + } + } + + return result; +} + +/* For final responses in the AUTH sequence */ +static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, + int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Authentication failed: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } - /* Proceed with clear text authentication as we used to for now */ - result = pop3_state_user(conn); + state(conn, POP3_STOP); /* End of connect phase */ return result; } @@ -460,7 +554,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } - state(conn, POP3_STOP); + state(conn, POP3_STOP); /* End of connect phase */ return result; } @@ -587,7 +681,15 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) break; case POP3_AUTH: - result = pop3_state_auth_resp(conn); + result = pop3_state_auth_resp(conn, pop3code, pop3c->state); + break; + + case POP3_AUTH_PLAIN: + result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state); + break; + + case POP3_AUTH_FINAL: + result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); break; case POP3_USER: diff --git a/lib/pop3.h b/lib/pop3.h index 000284d62..953fce7da 100644 --- a/lib/pop3.h +++ b/lib/pop3.h @@ -31,6 +31,8 @@ typedef enum { a connect */ POP3_STARTTLS, POP3_AUTH, + POP3_AUTH_PLAIN, + POP3_AUTH_FINAL, POP3_USER, POP3_PASS, POP3_COMMAND, @@ -48,6 +50,7 @@ struct pop3_conn { received thus far */ size_t strip; /* number of bytes from the start to ignore as non-body */ unsigned int authmechs; /* Accepted authentication methods */ + unsigned int authused; /* Authentication method used for the connection */ pop3state state; /* always use pop3.c:state() to change state! */ }; |