From cfb6f03224297750164c5bafeb5b3e59866fca50 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 6 Jan 2013 22:25:14 +0000 Subject: imap: Added support for sasl plain text authentication --- lib/imap.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- lib/imap.h | 3 ++ 2 files changed, 118 insertions(+), 2 deletions(-) (limited to 'lib') 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 */ -- cgit v1.2.3