aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE-NOTES1
-rw-r--r--lib/pop3.c99
-rw-r--r--lib/pop3.h2
3 files changed, 98 insertions, 4 deletions
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index fa85b190b..80bed0457 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -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:
diff --git a/lib/pop3.c b/lib/pop3.c
index 1e399a03b..8ce7f259b 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -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);
diff --git a/lib/pop3.h b/lib/pop3.h
index 1ca8bb289..1b6859955 100644
--- a/lib/pop3.h
+++ b/lib/pop3.h
@@ -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! */
};