aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/imap.c117
-rw-r--r--lib/imap.h3
2 files changed, 118 insertions, 2 deletions
diff --git a/lib/imap.c b/lib/imap.c
index 75fe3d4a4..4d587c782 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -18,7 +18,9 @@
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
+ * RFC2222 Simple Authentication and Security Layer (SASL)
* RFC3501 IMAPv4 protocol
+ * RFC4616 PLAIN authentication
* RFC5092 IMAP URL Scheme
*
***************************************************************************/
@@ -430,6 +432,8 @@ static void state(struct connectdata *conn,
"STARTTLS",
"UPGRADETLS",
"CAPABILITY",
+ "AUTHENTICATE_PLAIN",
+ "AUTHENTICATE",
"LOGIN",
"SELECT",
"FETCH",
@@ -452,6 +456,7 @@ static CURLcode imap_state_capability(struct connectdata *conn)
const char *str;
imapc->authmechs = 0; /* No known authentication mechanisms yet */
+ imapc->authused = 0; /* Clear the authentication mechanism used */
/* Check we have a username and password to authenticate with and end the
connect phase if we don't */
@@ -497,6 +502,37 @@ static CURLcode imap_state_login(struct connectdata *conn)
return CURLE_OK;
}
+static CURLcode imap_authenticate(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *mech = NULL;
+ imapstate authstate = IMAP_STOP;
+
+ /* Check supported authentication mechanisms by decreasing order of
+ security */
+ if(imapc->authmechs & SASL_MECH_PLAIN) {
+ mech = "PLAIN";
+ authstate = IMAP_AUTHENTICATE_PLAIN;
+ imapc->authused = SASL_MECH_PLAIN;
+ }
+ else {
+ infof(conn->data, "No known authentication mechanisms supported!\n");
+ result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported */
+ }
+
+ if(!result) {
+ const char *str = getcmdid(conn);
+
+ result = imap_sendf(conn, str, "%s AUTHENTICATE %s", str, mech);
+
+ if(!result)
+ state(conn, authstate);
+ }
+
+ return result;
+}
+
/* For the IMAP "protocol connect" and "doing" phases only */
static int imap_getsock(struct connectdata *conn,
curl_socket_t *socks,
@@ -597,10 +633,76 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
int imapcode,
imapstate instate)
{
- (void)imapcode; /* no use for this yet */
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
(void)instate; /* no use for this yet */
- return imap_state_login(conn);
+ if(imapcode == 'O' && imapc->authmechs)
+ result = imap_authenticate(conn);
+ else
+ result = imap_state_login(conn);
+
+ return result;
+}
+
+/* For AUTHENTICATE PLAIN responses */
+static CURLcode imap_state_auth_plain_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate 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(imapcode != '+') {
+ failf(data, "Access denied. %c", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the authorisation message */
+ result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
+ &plainauth, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(plainauth) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", plainauth);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE);
+ }
+
+ Curl_safefree(plainauth);
+ }
+ }
+
+ return result;
+}
+
+
+/* For final responses to the AUTHENTICATE sequence */
+static CURLcode imap_state_auth_final_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != 'O') {
+ failf(data, "Authentication failed: %d", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+
+ /* End of connect phase */
+ state(conn, IMAP_STOP);
+
+ return result;
}
/* For LOGIN responses */
@@ -807,6 +909,14 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
result = imap_state_capability_resp(conn, imapcode, imapc->state);
break;
+ case IMAP_AUTHENTICATE_PLAIN:
+ result = imap_state_auth_plain_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE:
+ result = imap_state_auth_final_resp(conn, imapcode, imapc->state);
+ break;
+
case IMAP_LOGIN:
result = imap_state_login_resp(conn, imapcode, imapc->state);
break;
@@ -1117,6 +1227,9 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
/* Disconnect from the server */
Curl_pp_disconnect(&imapc->pp);
+ /* Cleanup the SASL module */
+ Curl_sasl_cleanup(conn, imapc->authused);
+
/* Cleanup our connection based variables */
Curl_safefree(imapc->mailbox);
diff --git a/lib/imap.h b/lib/imap.h
index 60cb0465a..896f35ad4 100644
--- a/lib/imap.h
+++ b/lib/imap.h
@@ -35,6 +35,8 @@ typedef enum {
IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS
(multi mode only) */
IMAP_CAPABILITY,
+ IMAP_AUTHENTICATE_PLAIN,
+ IMAP_AUTHENTICATE,
IMAP_LOGIN,
IMAP_SELECT,
IMAP_FETCH,
@@ -48,6 +50,7 @@ struct imap_conn {
struct pingpong pp;
char *mailbox; /* Message ID to fetch */
unsigned int authmechs; /* Accepted authentication mechanisms */
+ unsigned int authused; /* Auth mechanism used for the connection */
imapstate state; /* Always use imap.c:state() to change state! */
int cmdid; /* Next command ID */
const char *idstr; /* String based response ID to wait for */