aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/pop3.c112
-rw-r--r--lib/pop3.h3
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! */
};