Skip to content

Commit

Permalink
pop3: Added support for apop authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
captain-caveman2k committed Jun 9, 2012
1 parent 4e430a8 commit c09c621
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 4 deletions.
1 change: 1 addition & 0 deletions RELEASE-NOTES
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
99 changes: 95 additions & 4 deletions lib/pop3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -213,15 +215,17 @@ 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;
size_t len = strlen(pp->linestart_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)) {
Expand All @@ -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)) {
Expand Down Expand Up @@ -334,6 +361,7 @@ static void state(struct connectdata *conn, pop3state newstate)
"AUTH_NTLM",
"AUTH_NTLM_TYPE2MSG",
"AUTH",
"APOP",
"USER",
"PASS",
"COMMAND",
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions lib/pop3.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ typedef enum {
POP3_AUTH_NTLM,
POP3_AUTH_NTLM_TYPE2MSG,
POP3_AUTH,
POP3_APOP,
POP3_USER,
POP3_PASS,
POP3_COMMAND,
Expand All @@ -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! */
};

Expand Down

0 comments on commit c09c621

Please sign in to comment.