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:
parent
4a5aa6682d
commit
db20517796
120
lib/imap.c
120
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
|
* 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;
|
||||||
|
16
lib/imap.h
16
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
|
* 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;
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user