Skip to content

Commit

Permalink
SASL: common URL option and auth capabilities decoders for all protocols
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick Monnerat committed Jan 20, 2015
1 parent 5f09cbc commit e1ea18f
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 199 deletions.
103 changes: 101 additions & 2 deletions lib/curl_sasl.c
Expand Up @@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2012 - 2015, 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
Expand Down Expand Up @@ -41,6 +41,7 @@
#include "warnless.h"
#include "curl_memory.h"
#include "strtok.h"
#include "strequal.h"
#include "rawstr.h"
#include "non-ascii.h" /* included for Curl_convert_... prototypes */

Expand Down Expand Up @@ -73,6 +74,24 @@
return result; \
}


/* Supported mechanisms */
const struct {
const char * name; /* Name */
size_t len; /* Name length */
unsigned int bit; /* Flag bit */
} mechtable[] = {
{ "LOGIN", 5, SASL_MECH_LOGIN },
{ "PLAIN", 5, SASL_MECH_PLAIN },
{ "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 },
{ "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 },
{ "GSSAPI", 6, SASL_MECH_GSSAPI },
{ "EXTERNAL", 8, SASL_MECH_EXTERNAL },
{ "NTLM", 4, SASL_MECH_NTLM },
{ "XOAUTH2", 7, SASL_MECH_XOAUTH2 },
{ ZERO_NULL, 0, 0 }
};

/*
* Return 0 on success and then the buffers are filled in fine.
*
Expand Down Expand Up @@ -248,7 +267,7 @@ static CURLcode sasl_digest_get_qop_values(const char *options, int *value)
*
* Parameters:
*
* serivce [in] - The service type such as www, smtp, pop or imap.
* service [in] - The service type such as www, smtp, pop or imap.
* host [in] - The host name or realm.
*
* Returns a pointer to the newly allocated SPN.
Expand Down Expand Up @@ -1180,3 +1199,83 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
(void)authused;
#endif
}

/*
* Curl_sasl_decode_mech()
*
* Convert an SASL mechanism name to a token.
*
* Parameters:
*
* ptr [in] - The mechanism string.
* maxlen [in] - Maximum mechanism string length.
* len [out] - If not NULL, effective name length.
*
* Return the SASL mechanism token or 0 if no match.
*/
unsigned int
Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len)
{
unsigned int i;
char c;

for(i = 0; mechtable[i].name; i++) {
if(maxlen >= mechtable[i].len &&
!memcmp(ptr, mechtable[i].name, mechtable[i].len)) {
if(len)
*len = mechtable[i].len;
if(maxlen == mechtable[i].len)
return mechtable[i].bit;
c = ptr[mechtable[i].len];
if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_')
return mechtable[i].bit;
}
}

return 0;
}

/*
* Curl_sasl_parse_url_auth_option()
*
* Parse the URL login options.
*/
CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
const char *value, size_t len)
{
CURLcode result = CURLE_OK;
unsigned int mechbit;
size_t llen;

if(!len)
return CURLE_URL_MALFORMAT;

if(sasl->resetprefs) {
sasl->resetprefs = FALSE;
sasl->prefmech = SASL_AUTH_NONE;
}

if(strnequal(value, "*", len))
sasl->prefmech = SASL_AUTH_ANY;
else if((mechbit = Curl_sasl_decode_mech(value, len, &llen)) &&
llen == len)
sasl->prefmech |= mechbit;
else
result = CURLE_URL_MALFORMAT;

return result;
}

/*
* Curl_sasl_init()
*
* Initializes an SASL structure.
*/
void Curl_sasl_init(struct SASL *sasl)
{
sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
sasl->prefmech = SASL_AUTH_ANY; /* Prefer all mechanisms */
sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */
sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
}
12 changes: 12 additions & 0 deletions lib/curl_sasl.h
Expand Up @@ -73,6 +73,7 @@ struct SASL {
unsigned int authmechs; /* Accepted authentication mechanisms */
unsigned int prefmech; /* Preferred authentication mechanism */
unsigned int authused; /* Auth mechanism used for the connection */
bool resetprefs; /* For URL auth option parsing. */
bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */
};

Expand Down Expand Up @@ -201,4 +202,15 @@ CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data,
functions */
void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);

/* Convert a mechanism name to a token */
unsigned int Curl_sasl_decode_mech(const char *ptr,
size_t maxlen, size_t *len);

/* Parse the URL login options */
CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
const char *value, size_t len);

/* Initializes an SASL structure */
void Curl_sasl_init(struct SASL *sasl);

#endif /* HEADER_CURL_SASL_H */
103 changes: 33 additions & 70 deletions lib/imap.c
Expand Up @@ -914,26 +914,16 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,

/* Do we have a SASL based authentication mechanism? */
else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
size_t llen;
unsigned int mechbit;

line += 5;
wordlen -= 5;

/* Test the word for a matching authentication mechanism */
if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
imapc->sasl.authmechs |= SASL_MECH_LOGIN;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
imapc->sasl.authmechs |= SASL_MECH_PLAIN;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
imapc->sasl.authmechs |= SASL_MECH_CRAM_MD5;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
imapc->sasl.authmechs |= SASL_MECH_DIGEST_MD5;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
imapc->sasl.authmechs |= SASL_MECH_GSSAPI;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
imapc->sasl.authmechs |= SASL_MECH_EXTERNAL;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
imapc->sasl.authmechs |= SASL_MECH_NTLM;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
imapc->sasl.authmechs |= SASL_MECH_XOAUTH2;
if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) &&
llen == wordlen)
imapc->sasl.authmechs |= mechbit;
}

line += wordlen;
Expand Down Expand Up @@ -2061,7 +2051,7 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done)

/* Set the default preferred authentication type and mechanism */
imapc->preftype = IMAP_TYPE_ANY;
imapc->sasl.prefmech = SASL_AUTH_ANY;
Curl_sasl_init(&imapc->sasl);

/* Initialise the pingpong layer */
Curl_pp_init(pp);
Expand Down Expand Up @@ -2548,69 +2538,42 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc;
const char *options = conn->options;
const char *ptr = options;
bool reset = TRUE;
const char *ptr = conn->options;

imapc->sasl.resetprefs = TRUE;

while(ptr && *ptr) {
while(!result && ptr && *ptr) {
const char *key = ptr;
const char *value;

while(*ptr && *ptr != '=')
ptr++;

if(strnequal(key, "AUTH", 4)) {
size_t len = 0;
const char *value = ++ptr;

if(reset) {
reset = FALSE;
imapc->preftype = IMAP_TYPE_NONE;
imapc->sasl.prefmech = SASL_AUTH_NONE;
}
value = ptr + 1;

while(*ptr && *ptr != ';') {
ptr++;
len++;
}

if(strnequal(value, "*", len)) {
imapc->preftype = IMAP_TYPE_ANY;
imapc->sasl.prefmech = SASL_AUTH_ANY;
}
else if(strnequal(value, SASL_MECH_STRING_LOGIN, len)) {
imapc->preftype = IMAP_TYPE_SASL;
imapc->sasl.prefmech |= SASL_MECH_LOGIN;
}
else if(strnequal(value, SASL_MECH_STRING_PLAIN, len)) {
imapc->preftype = IMAP_TYPE_SASL;
imapc->sasl.prefmech |= SASL_MECH_PLAIN;
}
else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len)) {
imapc->preftype = IMAP_TYPE_SASL;
imapc->sasl.prefmech |= SASL_MECH_CRAM_MD5;
}
else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len)) {
imapc->preftype = IMAP_TYPE_SASL;
imapc->sasl.prefmech |= SASL_MECH_DIGEST_MD5;
}
else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len)) {
imapc->preftype = IMAP_TYPE_SASL;
imapc->sasl.prefmech |= SASL_MECH_GSSAPI;
}
else if(strnequal(value, SASL_MECH_STRING_NTLM, len)) {
imapc->preftype = IMAP_TYPE_SASL;
imapc->sasl.prefmech |= SASL_MECH_NTLM;
}
else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len)) {
imapc->preftype = IMAP_TYPE_SASL;
imapc->sasl.prefmech |= SASL_MECH_XOAUTH2;
}
while(*ptr && *ptr != ';')
ptr++;

if(*ptr == ';')
ptr++;
}
if(strnequal(key, "AUTH=", 5))
result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
value, ptr - value);
else
result = CURLE_URL_MALFORMAT;

if(*ptr == ';')
ptr++;
}

switch(imapc->sasl.prefmech) {
case SASL_AUTH_NONE:
imapc->preftype = IMAP_TYPE_NONE;
break;
case SASL_AUTH_ANY:
imapc->preftype = IMAP_TYPE_ANY;
break;
default:
imapc->preftype = IMAP_TYPE_SASL;
break;
}

return result;
Expand Down
2 changes: 1 addition & 1 deletion lib/imap.h
Expand Up @@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2009 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2009 - 2015, 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
Expand Down

0 comments on commit e1ea18f

Please sign in to comment.