diff options
author | Steve Holme <steve_holme@hotmail.com> | 2013-01-06 19:13:58 +0000 |
---|---|---|
committer | Steve Holme <steve_holme@hotmail.com> | 2013-01-06 19:13:58 +0000 |
commit | db205177961218ebd8e358351dc9dd94490c79e6 (patch) | |
tree | 8a5e2313f13804ba32528e6b44428cf39c6fb8a7 /lib | |
parent | 4a5aa6682daeea7cd7cbbb47ce3e1c310e9261c2 (diff) |
imap: Added support for SASL based authentication mechanism detection
Added support for detecting the supported SASL authentication mechanisms
via the CAPABILITY command.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/imap.c | 120 | ||||
-rw-r--r-- | lib/imap.h | 16 |
2 files changed, 122 insertions, 14 deletions
diff --git a/lib/imap.c b/lib/imap.c index ab11464fb..388af0496 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -70,6 +70,7 @@ #include "multiif.h" #include "url.h" #include "rawstr.h" +#include "curl_sasl.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -320,7 +321,8 @@ static char* imap_atom(const char* str) } /* Function that checks for an ending imap status code at the start of the - given string. */ + given string but also detects the supported mechanisms from the CAPABILITY + response. */ static int imap_endofresp(struct pingpong *pp, int *resp) { char *line = pp->linestart_resp; @@ -328,6 +330,7 @@ static int imap_endofresp(struct pingpong *pp, int *resp) struct imap_conn *imapc = &pp->conn->proto.imapc; const char *id = imapc->idstr; size_t id_len = strlen(id); + size_t wordlen; /* Do we have a generic command response? */ if(len >= id_len + 3) { @@ -337,6 +340,64 @@ static int imap_endofresp(struct pingpong *pp, int *resp) } } + /* Are we processing CAPABILITY command responses? */ + if(imapc->state == IMAP_CAPABILITY) { + /* Do we have a valid response? */ + if(len >= 2 && !memcmp("* ", line, 2)) { + line += 2; + len -= 2; + + /* Loop through the data line */ + for(;;) { + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + if(*line == '\n') + return FALSE; + + line++; + len--; + } + + if(!len) + break; + + /* Extract the word */ + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Do we have an AUTH capability? */ + if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) { + line += 5; + len -= 5; + wordlen -= 5; + + /* Test the word for a matching authentication mechanism */ + if(wordlen == 5 && !memcmp(line, "LOGIN", 5)) + imapc->authmechs |= SASL_MECH_LOGIN; + if(wordlen == 5 && !memcmp(line, "PLAIN", 5)) + imapc->authmechs |= SASL_MECH_PLAIN; + else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8)) + imapc->authmechs |= SASL_MECH_CRAM_MD5; + else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10)) + imapc->authmechs |= SASL_MECH_DIGEST_MD5; + else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6)) + imapc->authmechs |= SASL_MECH_GSSAPI; + else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) + imapc->authmechs |= SASL_MECH_EXTERNAL; + else if(wordlen == 4 && !memcmp(line, "NTLM", 4)) + imapc->authmechs |= SASL_MECH_NTLM; + } + + line += wordlen; + len -= wordlen; + } + } + } + /* Are we processing FETCH command responses? */ if(imapc->state == IMAP_FETCH) { /* Do we have a valid response? */ @@ -346,7 +407,7 @@ static int imap_endofresp(struct pingpong *pp, int *resp) } } - return FALSE; /* nothing for us */ + return FALSE; /* Nothing for us */ } /* This is the ONLY way to change IMAP state! */ @@ -361,6 +422,7 @@ static void state(struct connectdata *conn, "SERVERGREET", "STARTTLS", "UPGRADETLS", + "CAPABILITY", "LOGIN", "SELECT", "FETCH", @@ -376,6 +438,35 @@ static void state(struct connectdata *conn, imapc->state = newstate; } +static CURLcode imap_state_capability(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + const char *str; + + imapc->authmechs = 0; /* No known authentication mechanisms yet */ + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't */ + if(!conn->bits.user_passwd) { + state(conn, IMAP_STOP); + + return result; + } + + str = getcmdid(conn); + + /* Send the CAPABILITY command */ + result = imap_sendf(conn, str, "%s CAPABILITY", str); + + if(result) + return result; + + state(conn, IMAP_CAPABILITY); + + return CURLE_OK; +} + static CURLcode imap_state_login(struct connectdata *conn) { CURLcode result; @@ -439,7 +530,7 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn, state(conn, IMAP_STARTTLS); } else - result = imap_state_login(conn); + result = imap_state_capability(conn); return result; } @@ -460,7 +551,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, result = CURLE_USE_SSL_FAILED; } else - result = imap_state_login(conn); + result = imap_state_capability(conn); } else { if(data->state.used_interface == Curl_if_multi) { @@ -471,7 +562,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, result = Curl_ssl_connect(conn, FIRSTSOCKET); if(CURLE_OK == result) { imap_to_imaps(conn); - result = imap_state_login(conn); + result = imap_state_capability(conn); } } } @@ -488,12 +579,23 @@ static CURLcode imap_state_upgrade_tls(struct connectdata *conn) if(imapc->ssldone) { imap_to_imaps(conn); - result = imap_state_login(conn); + result = imap_state_capability(conn); } return result; } +/* For CAPABILITY responses */ +static CURLcode imap_state_capability_resp(struct connectdata *conn, + int imapcode, + imapstate instate) +{ + (void)imapcode; /* no use for this yet */ + (void)instate; /* no use for this yet */ + + return imap_state_login(conn); +} + /* For LOGIN responses */ static CURLcode imap_state_login_resp(struct connectdata *conn, int imapcode, @@ -694,6 +796,10 @@ static CURLcode imap_statemach_act(struct connectdata *conn) result = imap_state_starttls_resp(conn, imapcode, imapc->state); break; + case IMAP_CAPABILITY: + result = imap_state_capability_resp(conn, imapcode, imapc->state); + break; + case IMAP_LOGIN: result = imap_state_login_resp(conn, imapcode, imapc->state); break; diff --git a/lib/imap.h b/lib/imap.h index 4cd6bc76a..60cb0465a 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2009 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,6 +34,7 @@ typedef enum { IMAP_STARTTLS, IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ + IMAP_CAPABILITY, IMAP_LOGIN, IMAP_SELECT, IMAP_FETCH, @@ -45,12 +46,13 @@ typedef enum { struct */ struct imap_conn { struct pingpong pp; - char *mailbox; /* Message ID to fetch */ - 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 */ - bool ssldone; /* Is connect() over SSL done? Only relevant in - multi mode */ + char *mailbox; /* Message ID to fetch */ + unsigned int authmechs; /* Accepted authentication mechanisms */ + 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 */ + bool ssldone; /* Is connect() over SSL done? Only relevant in + multi mode */ }; extern const struct Curl_handler Curl_handler_imap; |