1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

imap: Added support for SASL based authentication mechanism detection

Added support for detecting the supported SASL authentication mechanisms
via the CAPABILITY command.
This commit is contained in:
Steve Holme 2013-01-06 19:13:58 +00:00
parent 4a5aa6682d
commit db20517796
4 changed files with 132 additions and 22 deletions

View File

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -70,6 +70,7 @@
#include "multiif.h" #include "multiif.h"
#include "url.h" #include "url.h"
#include "rawstr.h" #include "rawstr.h"
#include "curl_sasl.h"
#define _MPRINTF_REPLACE /* use our functions only */ #define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h> #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 /* 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) static int imap_endofresp(struct pingpong *pp, int *resp)
{ {
char *line = pp->linestart_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; struct imap_conn *imapc = &pp->conn->proto.imapc;
const char *id = imapc->idstr; const char *id = imapc->idstr;
size_t id_len = strlen(id); size_t id_len = strlen(id);
size_t wordlen;
/* Do we have a generic command response? */ /* Do we have a generic command response? */
if(len >= id_len + 3) { 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? */ /* Are we processing FETCH command responses? */
if(imapc->state == IMAP_FETCH) { if(imapc->state == IMAP_FETCH) {
/* Do we have a valid response? */ /* 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! */ /* This is the ONLY way to change IMAP state! */
@ -361,6 +422,7 @@ static void state(struct connectdata *conn,
"SERVERGREET", "SERVERGREET",
"STARTTLS", "STARTTLS",
"UPGRADETLS", "UPGRADETLS",
"CAPABILITY",
"LOGIN", "LOGIN",
"SELECT", "SELECT",
"FETCH", "FETCH",
@ -376,6 +438,35 @@ static void state(struct connectdata *conn,
imapc->state = newstate; 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) static CURLcode imap_state_login(struct connectdata *conn)
{ {
CURLcode result; CURLcode result;
@ -439,7 +530,7 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
state(conn, IMAP_STARTTLS); state(conn, IMAP_STARTTLS);
} }
else else
result = imap_state_login(conn); result = imap_state_capability(conn);
return result; return result;
} }
@ -460,7 +551,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
result = CURLE_USE_SSL_FAILED; result = CURLE_USE_SSL_FAILED;
} }
else else
result = imap_state_login(conn); result = imap_state_capability(conn);
} }
else { else {
if(data->state.used_interface == Curl_if_multi) { 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); result = Curl_ssl_connect(conn, FIRSTSOCKET);
if(CURLE_OK == result) { if(CURLE_OK == result) {
imap_to_imaps(conn); 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) { if(imapc->ssldone) {
imap_to_imaps(conn); imap_to_imaps(conn);
result = imap_state_login(conn); result = imap_state_capability(conn);
} }
return result; 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 */ /* For LOGIN responses */
static CURLcode imap_state_login_resp(struct connectdata *conn, static CURLcode imap_state_login_resp(struct connectdata *conn,
int imapcode, int imapcode,
@ -694,6 +796,10 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
result = imap_state_starttls_resp(conn, imapcode, imapc->state); result = imap_state_starttls_resp(conn, imapcode, imapc->state);
break; break;
case IMAP_CAPABILITY:
result = imap_state_capability_resp(conn, imapcode, imapc->state);
break;
case IMAP_LOGIN: case IMAP_LOGIN:
result = imap_state_login_resp(conn, imapcode, imapc->state); result = imap_state_login_resp(conn, imapcode, imapc->state);
break; break;

View File

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -34,6 +34,7 @@ typedef enum {
IMAP_STARTTLS, IMAP_STARTTLS,
IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS
(multi mode only) */ (multi mode only) */
IMAP_CAPABILITY,
IMAP_LOGIN, IMAP_LOGIN,
IMAP_SELECT, IMAP_SELECT,
IMAP_FETCH, IMAP_FETCH,
@ -45,12 +46,13 @@ typedef enum {
struct */ struct */
struct imap_conn { struct imap_conn {
struct pingpong pp; struct pingpong pp;
char *mailbox; /* Message ID to fetch */ char *mailbox; /* Message ID to fetch */
imapstate state; /* Always use imap.c:state() to change state! */ unsigned int authmechs; /* Accepted authentication mechanisms */
int cmdid; /* Next command ID */ imapstate state; /* Always use imap.c:state() to change state! */
const char *idstr; /* String based response ID to wait for */ int cmdid; /* Next command ID */
bool ssldone; /* Is connect() over SSL done? Only relevant in const char *idstr; /* String based response ID to wait for */
multi mode */ bool ssldone; /* Is connect() over SSL done? Only relevant in
multi mode */
}; };
extern const struct Curl_handler Curl_handler_imap; extern const struct Curl_handler Curl_handler_imap;

View File

@ -56,10 +56,11 @@ imap://%HOSTIP:%IMAPPORT/1321 -u user:secret -p -x %HOSTIP:%PROXYPORT
^User-Agent: curl/.* ^User-Agent: curl/.*
</strip> </strip>
<protocol> <protocol>
B LOGIN user secret B CAPABILITY
C SELECT 1321 C LOGIN user secret
D FETCH 1 BODY[TEXT] D SELECT 1321
A LOGOUT A FETCH 1 BODY[TEXT]
B LOGOUT
</protocol> </protocol>
<proxy> <proxy>
CONNECT %HOSTIP:%IMAPPORT HTTP/1.1 CONNECT %HOSTIP:%IMAPPORT HTTP/1.1

View File

@ -38,10 +38,11 @@ imap://%HOSTIP:%IMAPPORT/801 -u user:secret
# Verify data after the test has been "shot" # Verify data after the test has been "shot"
<verify> <verify>
<protocol> <protocol>
B LOGIN user secret B CAPABILITY
C SELECT 801 C LOGIN user secret
D FETCH 1 BODY[TEXT] D SELECT 801
A LOGOUT A FETCH 1 BODY[TEXT]
B LOGOUT
</protocol> </protocol>
</verify> </verify>
</testcase> </testcase>