From b3a01be2f3fee2fc192175a77b0f347f84466cb3 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sat, 13 Apr 2013 16:09:28 +0100 Subject: [PATCH] pop3: Added support for ;auth= in the URL Added support for specifying the preferred authentication type and SASL mechanism in the URL as per RFC-2384. --- lib/pop3.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++----- lib/pop3.h | 6 ++++ 2 files changed, 97 insertions(+), 8 deletions(-) diff --git a/lib/pop3.c b/lib/pop3.c index 1dbe31816..ee4a713a8 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -101,6 +101,7 @@ static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done); static CURLcode pop3_setup_connection(struct connectdata *conn); +static CURLcode pop3_parse_url_options(struct connectdata *conn); static CURLcode pop3_parse_url_path(struct connectdata *conn); static CURLcode pop3_parse_custom_request(struct connectdata *conn); @@ -514,12 +515,14 @@ static CURLcode pop3_authenticate(struct connectdata *conn) security */ if(pop3c->authtypes & POP3_TYPE_SASL) { #ifndef CURL_DISABLE_CRYPTO_AUTH - if(pop3c->authmechs & SASL_MECH_DIGEST_MD5) { + if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) && + (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) { mech = "DIGEST-MD5"; authstate = POP3_AUTH_DIGESTMD5; pop3c->authused = SASL_MECH_DIGEST_MD5; } - else if(pop3c->authmechs & SASL_MECH_CRAM_MD5) { + else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) && + (pop3c->prefmech & SASL_MECH_CRAM_MD5)) { mech = "CRAM-MD5"; authstate = POP3_AUTH_CRAMMD5; pop3c->authused = SASL_MECH_CRAM_MD5; @@ -527,26 +530,29 @@ static CURLcode pop3_authenticate(struct connectdata *conn) else #endif #ifdef USE_NTLM - if(pop3c->authmechs & SASL_MECH_NTLM) { + if((pop3c->authmechs & SASL_MECH_NTLM) && + (pop3c->prefmech & SASL_MECH_NTLM)) { mech = "NTLM"; authstate = POP3_AUTH_NTLM; pop3c->authused = SASL_MECH_NTLM; } else #endif - if(pop3c->authmechs & SASL_MECH_LOGIN) { + if((pop3c->authmechs & SASL_MECH_LOGIN) && + (pop3c->prefmech & SASL_MECH_LOGIN)) { mech = "LOGIN"; authstate = POP3_AUTH_LOGIN; pop3c->authused = SASL_MECH_LOGIN; } - else if(pop3c->authmechs & SASL_MECH_PLAIN) { + else if((pop3c->authmechs & SASL_MECH_PLAIN) && + (pop3c->prefmech & SASL_MECH_PLAIN)) { mech = "PLAIN"; authstate = POP3_AUTH_PLAIN; pop3c->authused = SASL_MECH_PLAIN; } } - if(mech) { + if(mech && (pop3c->preftype & POP3_TYPE_SASL)) { /* Perform SASL based authentication */ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); @@ -554,11 +560,13 @@ static CURLcode pop3_authenticate(struct connectdata *conn) state(conn, authstate); } #ifndef CURL_DISABLE_CRYPTO_AUTH - else if(pop3c->authtypes & POP3_TYPE_APOP) + else if((pop3c->authtypes & POP3_TYPE_APOP) && + (pop3c->preftype & POP3_TYPE_APOP)) /* Perform APOP authentication */ result = pop3_state_apop(conn); #endif - else if(pop3c->authtypes & POP3_TYPE_CLEARTEXT) + else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && + (pop3c->preftype & POP3_TYPE_CLEARTEXT)) /* Perform clear text authentication */ result = pop3_state_user(conn); else { @@ -1332,9 +1340,18 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done) pp->endofresp = pop3_endofresp; pp->conn = conn; + /* Set the default preferred authentication type and mechanism */ + pop3c->preftype = POP3_TYPE_ANY; + pop3c->prefmech = SASL_AUTH_ANY; + /* Initialise the pingpong layer */ Curl_pp_init(pp); + /* Parse the URL options */ + result = pop3_parse_url_options(conn); + if(result) + return result; + /* Start off waiting for the server greeting response */ state(conn, POP3_SERVERGREET); @@ -1608,6 +1625,72 @@ static CURLcode pop3_setup_connection(struct connectdata *conn) return CURLE_OK; } +/*********************************************************************** + * + * pop3_parse_url_options() + * + * Parse the URL login options. + */ +static CURLcode pop3_parse_url_options(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *options = conn->options; + const char *ptr = options; + + if(options) { + const char *key = ptr; + + while(*ptr && *ptr != '=') + ptr++; + + if(strnequal(key, "AUTH", 4)) { + const char *value = ptr + 1; + + if(strequal(value, "*")) { + pop3c->preftype = POP3_TYPE_ANY; + pop3c->prefmech = SASL_AUTH_ANY; + } + else if(strequal(value, "+APOP")) { + pop3c->preftype = POP3_TYPE_APOP; + pop3c->prefmech = SASL_AUTH_NONE; + } + else if(strequal(value, "LOGIN")) { + pop3c->preftype = POP3_TYPE_SASL; + pop3c->prefmech = SASL_MECH_LOGIN; + } + else if(strequal(value, "PLAIN")) { + pop3c->preftype = POP3_TYPE_SASL; + pop3c->prefmech = SASL_MECH_PLAIN; + } + else if(strequal(value, "CRAM-MD5")) { + pop3c->preftype = POP3_TYPE_SASL; + pop3c->prefmech = SASL_MECH_CRAM_MD5; + } + else if(strequal(value, "DIGEST-MD5")) { + pop3c->preftype = POP3_TYPE_SASL; + pop3c->prefmech = SASL_MECH_DIGEST_MD5; + } + else if(strequal(value, "GSSAPI")) { + pop3c->preftype = POP3_TYPE_SASL; + pop3c->prefmech = SASL_MECH_GSSAPI; + } + else if(strequal(value, "NTLM")) { + pop3c->preftype = POP3_TYPE_SASL; + pop3c->prefmech = SASL_MECH_NTLM; + } + else { + pop3c->preftype = POP3_TYPE_NONE; + pop3c->prefmech = SASL_AUTH_NONE; + } + } + else + result = CURLE_URL_MALFORMAT; + } + + return result; +} + /*********************************************************************** * * pop3_parse_url_path() diff --git a/lib/pop3.h b/lib/pop3.h index 129dffc71..5fd4b244e 100644 --- a/lib/pop3.h +++ b/lib/pop3.h @@ -74,6 +74,8 @@ struct pop3_conn { non-body */ unsigned int authtypes; /* Supported authentication types */ unsigned int authmechs; /* Accepted SASL authentication mechanisms */ + unsigned int preftype; /* Preferred authentication type */ + unsigned int prefmech; /* Preferred SASL authentication mechanism */ unsigned int authused; /* SASL auth mechanism used for the connection */ char *apoptimestamp; /* APOP timestamp from the server greeting */ bool tls_supported; /* StartTLS capability supported by server */ @@ -87,6 +89,10 @@ extern const struct Curl_handler Curl_handler_pop3s; #define POP3_TYPE_APOP 0x0002 #define POP3_TYPE_SASL 0x0004 +/* Authentication type values */ +#define POP3_TYPE_NONE 0 +#define POP3_TYPE_ANY ~0 + /* This is the 5-bytes End-Of-Body marker for POP3 */ #define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" #define POP3_EOB_LEN 5