pop3: Added support for apop authentication

This commit is contained in:
Steve Holme 2012-06-09 13:49:37 +01:00
parent 4e430a8a16
commit c09c621af7
3 changed files with 98 additions and 4 deletions

View File

@ -16,6 +16,7 @@ This release includes the following changes:
o pop3: Added support for sasl ntlm authentication
o pop3: Added support for sasl cram-md5 authentication
o pop3: Added support for sasl digest-md5 authentication
o pop3: Added support for apop authentication
This release includes the following bugfixes:

View File

@ -84,6 +84,8 @@
#include "url.h"
#include "rawstr.h"
#include "curl_sasl.h"
#include "curl_md5.h"
#include "warnless.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@ -213,8 +215,9 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = {
#endif
/* Function that checks for an ending pop3 status code at the start of the
given string, but also detects the supported authentication types as well
as the allowed SASL authentication mechanisms within the CAPA response. */
given string, but also detects the APOP timestamp from the server greeting
as well as the supported authentication types and allowed SASL mechanisms
from the CAPA response. */
static int pop3_endofresp(struct pingpong *pp, int *resp)
{
char *line = pp->linestart_resp;
@ -222,6 +225,7 @@ static int pop3_endofresp(struct pingpong *pp, int *resp)
struct connectdata *conn = pp->conn;
struct pop3_conn *pop3c = &conn->proto.pop3c;
size_t wordlen;
size_t i;
/* Do we have an error response? */
if(len >= 4 && !memcmp("-ERR", line, 4)) {
@ -230,8 +234,31 @@ static int pop3_endofresp(struct pingpong *pp, int *resp)
return FALSE;
}
/* Are we processing reponses to our CAPA command? */
if(pop3c->state == POP3_CAPA) {
/* Are we processing servergreet responses */
if(pop3c->state == POP3_SERVERGREET) {
/* Look for the APOP timestamp */
if(len >= 3 && line[len - 3] == '>') {
for(i = 0; i < len - 3; ++i) {
if(line[i] == '<') {
/* Calculate the length of the timestamp */
size_t timestamplen = len - 2 - i;
/* Allocate some memory for the timestamp */
pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
if(!pop3c->apoptimestamp)
break;
/* Copy the timestamp */
memcpy(pop3c->apoptimestamp, line + i, timestamplen);
pop3c->apoptimestamp[timestamplen] = '\0';
break;
}
}
}
}
/* Are we processing CAPA command responses? */
else if(pop3c->state == POP3_CAPA) {
/* Do we have the terminating character? */
if(len >= 1 && !memcmp(line, ".", 1)) {
@ -334,6 +361,7 @@ static void state(struct connectdata *conn, pop3state newstate)
"AUTH_NTLM",
"AUTH_NTLM_TYPE2MSG",
"AUTH",
"APOP",
"USER",
"PASS",
"COMMAND",
@ -393,6 +421,40 @@ static CURLcode pop3_state_user(struct connectdata *conn)
return CURLE_OK;
}
static CURLcode pop3_state_apop(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct pop3_conn *pop3c = &conn->proto.pop3c;
size_t i;
MD5_context *ctxt;
unsigned char digest[MD5_DIGEST_LEN];
char secret[2 * MD5_DIGEST_LEN + 1];
ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
if(!ctxt)
return CURLE_OUT_OF_MEMORY;
Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
curlx_uztoui(strlen(pop3c->apoptimestamp)));
Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
curlx_uztoui(strlen(conn->passwd)));
/* Finalise the digest */
Curl_MD5_final(ctxt, digest);
/* Convert the calculated 16 octet digest into a 32 byte hex string */
for(i = 0; i < MD5_DIGEST_LEN; i++)
snprintf(&secret[2 * i], 3, "%02x", digest[i]);
result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
if(!result)
state(conn, POP3_APOP);
return result;
}
static CURLcode pop3_authenticate(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
@ -542,6 +604,8 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn,
/* Check supported authentication types by decreasing order of security */
if(conn->proto.pop3c.authtypes & POP3_TYPE_SASL)
result = pop3_authenticate(conn);
else if(conn->proto.pop3c.authtypes & POP3_TYPE_APOP)
result = pop3_state_apop(conn);
else if(conn->proto.pop3c.authtypes & POP3_TYPE_CLEARTEXT)
result = pop3_state_user(conn);
else {
@ -883,6 +947,26 @@ static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
return result;
}
static CURLcode pop3_state_apop_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
(void)instate; /* no use for this yet */
if(pop3code != '+') {
failf(data, "Authentication failed: %d", pop3code);
result = CURLE_LOGIN_DENIED;
}
/* End of connect phase */
state(conn, POP3_STOP);
return result;
}
/* For USER responses */
static CURLcode pop3_state_user_resp(struct connectdata *conn,
int pop3code,
@ -1100,6 +1184,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)
result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
break;
case POP3_APOP:
result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
break;
case POP3_USER:
result = pop3_state_user_resp(conn, pop3code, pop3c->state);
break;
@ -1408,6 +1496,9 @@ static CURLcode pop3_disconnect(struct connectdata *conn,
Curl_pp_disconnect(&pop3c->pp);
/* Clear our variables */
Curl_safefree(pop3c->apoptimestamp);
/* Cleanup the SASL module */
Curl_sasl_cleanup(conn, pop3c->authused);

View File

@ -40,6 +40,7 @@ typedef enum {
POP3_AUTH_NTLM,
POP3_AUTH_NTLM_TYPE2MSG,
POP3_AUTH,
POP3_APOP,
POP3_USER,
POP3_PASS,
POP3_COMMAND,
@ -60,6 +61,7 @@ struct pop3_conn {
unsigned int authtypes; /* Supported authentication types */
unsigned int authmechs; /* Accepted SASL authentication mechanisms */
unsigned int authused; /* SASL auth mechanism used for the connection */
char *apoptimestamp; /* APOP timestamp from the server greeting */
pop3state state; /* Always use pop3.c:state() to change state! */
};