Newer
Older
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2013, 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
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* RFC1734 POP3 Authentication
* RFC1939 POP3 protocol
* RFC2195 CRAM-MD5 authentication
* RFC2384 POP URL Scheme
* RFC2449 POP3 Extension Mechanism
* RFC2595 Using TLS with IMAP, POP3 and ACAP
* RFC2831 DIGEST-MD5 authentication
* RFC4422 Simple Authentication and Security Layer (SASL)
* RFC4616 PLAIN authentication
* RFC5034 POP3 SASL Authentication Mechanism
*
***************************************************************************/
#include "curl_setup.h"
#ifndef CURL_DISABLE_POP3
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_UTSNAME_H
#include <sys/utsname.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include <in.h>
#include <inet.h>
#endif
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
#undef in_addr_t
#define in_addr_t unsigned long
#endif
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
#include "if2ip.h"
#include "hostip.h"
#include "progress.h"
#include "transfer.h"
#include "escape.h"
#include "http.h" /* for HTTP proxy tunnel stuff */
#include "socks.h"
#include "pop3.h"
#include "strtoofft.h"
#include "strequal.h"
#include "sslgen.h"
#include "connect.h"
#include "strerror.h"
#include "select.h"
#include "multiif.h"
#include "url.h"
#include "rawstr.h"
#include "curl_sasl.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
#include "curl_memory.h"
/* The last #include file should be: */
/* Local API functions */
static CURLcode pop3_parse_url_path(struct connectdata *conn);
static CURLcode pop3_parse_custom_request(struct connectdata *conn);
static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
static CURLcode pop3_do(struct connectdata *conn, bool *done);
static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
bool premature);
static CURLcode pop3_connect(struct connectdata *conn, bool *done);
static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
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);
/*
* POP3 protocol handler.
*/
const struct Curl_handler Curl_handler_pop3 = {
"POP3", /* scheme */
pop3_setup_connection, /* setup_connection */
pop3_do, /* do_it */
pop3_done, /* done */
ZERO_NULL, /* do_more */
pop3_connect, /* connect_it */
pop3_multi_statemach, /* connecting */
pop3_doing, /* doing */
pop3_getsock, /* proto_getsock */
pop3_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
PORT_POP3, /* defport */
PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
};
#ifdef USE_SSL
/*
* POP3S protocol handler.
*/
const struct Curl_handler Curl_handler_pop3s = {
"POP3S", /* scheme */
pop3_setup_connection, /* setup_connection */
pop3_do, /* do_it */
pop3_done, /* done */
ZERO_NULL, /* do_more */
pop3_connect, /* connect_it */
pop3_multi_statemach, /* connecting */
pop3_doing, /* doing */
pop3_getsock, /* proto_getsock */
pop3_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
PORT_POP3S, /* defport */
CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */
PROTOPT_CLOSEACTION | PROTOPT_SSL
| PROTOPT_NOURLQUERY /* flags */
};
#endif
#ifndef CURL_DISABLE_HTTP
/*
* HTTP-proxyed POP3 protocol handler.
*/
static const struct Curl_handler Curl_handler_pop3_proxy = {
"POP3", /* scheme */
ZERO_NULL, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
ZERO_NULL, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
PORT_POP3, /* defport */
};
#ifdef USE_SSL
/*
* HTTP-proxyed POP3S protocol handler.
*/
static const struct Curl_handler Curl_handler_pop3s_proxy = {
"POP3S", /* scheme */
ZERO_NULL, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
ZERO_NULL, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
PORT_POP3S, /* defport */
};
#endif
#endif
#ifdef USE_SSL
static void pop3_to_pop3s(struct connectdata *conn)
{
conn->handler = &Curl_handler_pop3s;
}
#else
#define pop3_to_pop3s(x) Curl_nop_stmt
#endif
/* Function that checks for an ending POP3 status code at the start of the
given string, but also detects the APOP timestamp from the server greeting
and various capabilities from the CAPA response including the supported
authentication types and allowed SASL mechanisms. */
static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
int *resp)
{
struct pop3_conn *pop3c = &conn->proto.pop3c;
size_t wordlen;
/* Do we have an error response? */
if(len >= 4 && !memcmp("-ERR", line, 4)) {
*resp = '-';
/* 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 line? */
if(len >= 1 && !memcmp(line, ".", 1)) {
*resp = '+';
return TRUE;
}
/* Does the server support the STLS capability? */
if(len >= 4 && !memcmp(line, "STLS", 4))
pop3c->tls_supported = TRUE;
/* Does the server support clear text authentication? */
else if(len >= 4 && !memcmp(line, "USER", 4))
pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
/* Does the server support APOP authentication? */
else if(len >= 4 && !memcmp(line, "APOP", 4))
pop3c->authtypes |= POP3_TYPE_APOP;
/* Does the server support SASL based authentication? */
else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
pop3c->authtypes |= POP3_TYPE_SASL;
/* Advance past the SASL keyword */
line += 5;
len -= 5;
/* Loop through the data line */
for(;;) {
while(len &&
(*line == ' ' || *line == '\t' ||
*line == '\r' || *line == '\n')) {
line++;
len--;
}
/* Extract the word */
for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
line[wordlen] != '\t' && line[wordlen] != '\r' &&
line[wordlen] != '\n';)
wordlen++;
/* Test the word for a matching authentication mechanism */
if(wordlen == 5 && !memcmp(line, "LOGIN", 5))
pop3c->authmechs |= SASL_MECH_LOGIN;
else if(wordlen == 5 && !memcmp(line, "PLAIN", 5))
pop3c->authmechs |= SASL_MECH_PLAIN;
else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8))
pop3c->authmechs |= SASL_MECH_CRAM_MD5;
else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10))
pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6))
pop3c->authmechs |= SASL_MECH_GSSAPI;
else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
pop3c->authmechs |= SASL_MECH_EXTERNAL;
else if(wordlen == 4 && !memcmp(line, "NTLM", 4))
pop3c->authmechs |= SASL_MECH_NTLM;
line += wordlen;
len -= wordlen;
}
}
/* Do we have a command or continuation response? */
if((len >= 3 && !memcmp("+OK", line, 3)) ||
(len >= 1 && !memcmp("+", line, 1))) {
*resp = '+';
return TRUE;
}
return FALSE; /* Nothing for us */
}
/* This is the ONLY way to change POP3 state! */
static void state(struct connectdata *conn, pop3state newstate)
{
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char * const names[] = {
"STOP",
"SERVERGREET",
"AUTH_LOGIN",
"AUTH_LOGIN_PASSWD",
"AUTH_DIGESTMD5",
"AUTH_DIGESTMD5_RESP",
"AUTH_NTLM",
"AUTH_NTLM_TYPE2MSG",
"USER",
"PASS",
"QUIT",
/* LAST */
};
if(pop3c->state != newstate)
infof(conn->data, "POP3 %p state change from %s to %s\n",
pop3c, names[pop3c->state], names[newstate]);
#endif
pop3c->state = newstate;
}
static CURLcode pop3_state_capa(struct connectdata *conn)
CURLcode result = CURLE_OK;
struct pop3_conn *pop3c = &conn->proto.pop3c;
pop3c->authmechs = 0; /* No known authentication mechanisms yet */
pop3c->authused = 0; /* Clear the authentication mechanism used */
pop3c->tls_supported = FALSE; /* Clear the TLS capability */
result = Curl_pp_sendf(&pop3c->pp, "CAPA");
if(!result)
state(conn, POP3_CAPA);
return result;
}
static CURLcode pop3_state_starttls(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
/* Send the STLS command */
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "STLS");
if(!result)
state(conn, POP3_STARTTLS);
return result;
}
static CURLcode pop3_state_upgrade_tls(struct connectdata *conn)
{
struct pop3_conn *pop3c = &conn->proto.pop3c;
result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
if(!result) {
if(pop3c->state != POP3_UPGRADETLS)
state(conn, POP3_UPGRADETLS);
if(pop3c->ssldone) {
pop3_to_pop3s(conn);
result = pop3_state_capa(conn);
}
}
return result;
}
static CURLcode pop3_state_user(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
/* Check we have a username and password to authenticate with and end the
connect phase if we don't */
if(!conn->bits.user_passwd) {
state(conn, POP3_STOP);
return result;
}
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
if(!result)
state(conn, POP3_USER);
return result;
}
#ifndef CURL_DISABLE_CRYPTO_AUTH
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];
/* Check we have a username and password to authenticate with and end the
connect phase if we don't */
if(!conn->bits.user_passwd) {
state(conn, POP3_STOP);
return result;
}
/* Create the digest */
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;
struct pop3_conn *pop3c = &conn->proto.pop3c;
const char *mech = NULL;
pop3state authstate = POP3_STOP;
/* Check we have a username and password to authenticate with and end the
connect phase if we don't */
if(!conn->bits.user_passwd) {
state(conn, POP3_STOP);
return result;
}
/* Calculate the supported authentication mechanism by decreasing order of
if(pop3c->authtypes & POP3_TYPE_SASL) {
#ifndef CURL_DISABLE_CRYPTO_AUTH
if(pop3c->authmechs & 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) {
mech = "CRAM-MD5";
authstate = POP3_AUTH_CRAMMD5;
pop3c->authused = SASL_MECH_CRAM_MD5;
}
else
if(pop3c->authmechs & SASL_MECH_NTLM) {
mech = "NTLM";
authstate = POP3_AUTH_NTLM;
pop3c->authused = SASL_MECH_NTLM;
}
else
if(pop3c->authmechs & SASL_MECH_LOGIN) {
mech = "LOGIN";
authstate = POP3_AUTH_LOGIN;
pop3c->authused = SASL_MECH_LOGIN;
}
else if(pop3c->authmechs & SASL_MECH_PLAIN) {
mech = "PLAIN";
authstate = POP3_AUTH_PLAIN;
pop3c->authused = SASL_MECH_PLAIN;
}
if(mech) {
/* Perform SASL based authentication */
result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
if(!result)
state(conn, authstate);
}
#ifndef CURL_DISABLE_CRYPTO_AUTH
else if(pop3c->authtypes & POP3_TYPE_APOP)
/* Perform APOP authentication */
result = pop3_state_apop(conn);
#endif
else if(pop3c->authtypes & POP3_TYPE_CLEARTEXT)
/* Perform clear text authentication */
result = pop3_state_user(conn);
else {
/* Other mechanisms not supported */
infof(conn->data, "No known authentication mechanisms supported!\n");
result = CURLE_LOGIN_DENIED;
return result;
}
/* For the initial server greeting */
static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
(void)instate; /* no use for this yet */
failf(data, "Got unexpected pop3-server response");
return CURLE_FTP_WEIRD_SERVER_REPLY;
}
result = pop3_state_capa(conn);
return result;
}
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
/* For CAPA responses */
static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
struct pop3_conn *pop3c = &conn->proto.pop3c;
(void)instate; /* no use for this yet */
if(pop3code != '+')
result = pop3_state_user(conn);
else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
/* We don't have a SSL/TLS connection yet, but SSL is requested */
if(pop3c->tls_supported)
/* Switch to TLS connection now */
result = pop3_state_starttls(conn);
else if(data->set.use_ssl == CURLUSESSL_TRY)
/* Fallback and carry on with authentication */
result = pop3_authenticate(conn);
else {
failf(data, "STLS not supported.");
result = CURLE_USE_SSL_FAILED;
}
}
else
result = pop3_authenticate(conn);
return result;
}
/* For STARTTLS responses */
static CURLcode pop3_state_starttls_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(data->set.use_ssl != CURLUSESSL_TRY) {
failf(data, "STARTTLS denied. %c", pop3code);
result = CURLE_USE_SSL_FAILED;
}
else
result = pop3_authenticate(conn);
}
result = pop3_state_upgrade_tls(conn);
return result;
}
/* For AUTH PLAIN responses */
static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
size_t len = 0;
char *plainauth = NULL;
(void)instate; /* no use for this yet */
if(pop3code != '+') {
failf(data, "Access denied. %c", pop3code);
result = CURLE_LOGIN_DENIED;
}
else {
/* Create the authorisation message */
result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
&plainauth, &len);
if(!result) {
if(plainauth) {
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
if(!result)
state(conn, POP3_AUTH_FINAL);
Curl_safefree(plainauth);
}
}
return result;
}
/* For AUTH LOGIN responses */
static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
size_t len = 0;
char *authuser = NULL;
(void)instate; /* no use for this yet */
if(pop3code != '+') {
failf(data, "Access denied: %d", pop3code);
result = CURLE_LOGIN_DENIED;
}
else {
result = Curl_sasl_create_login_message(data, conn->user,
if(!result) {
if(authuser) {
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser);
if(!result)
state(conn, POP3_AUTH_LOGIN_PASSWD);
}
Curl_safefree(authuser);
}
}
return result;
}
/* For AUTH LOGIN user entry responses */
static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
size_t len = 0;
char *authpasswd = NULL;
(void)instate; /* no use for this yet */
if(pop3code != '+') {
failf(data, "Access denied: %d", pop3code);
result = CURLE_LOGIN_DENIED;
}
else {
result = Curl_sasl_create_login_message(data, conn->passwd,
if(!result) {
if(authpasswd) {
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd);
if(!result)
state(conn, POP3_AUTH_FINAL);
Curl_safefree(authpasswd);
}
}
return result;
}
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
#ifndef CURL_DISABLE_CRYPTO_AUTH
/* For AUTH CRAM-MD5 responses */
static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
char *chlg64 = data->state.buffer;
size_t len = 0;
char *rplyb64 = NULL;
(void)instate; /* no use for this yet */
if(pop3code != '+') {
failf(data, "Access denied: %d", pop3code);
return CURLE_LOGIN_DENIED;
}
/* Get the challenge */
for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
;
/* Terminate the challenge */
if(*chlg64 != '=') {
for(len = strlen(chlg64); len--;)
if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' &&
chlg64[len] != '\t')
break;
if(++len) {
chlg64[len] = '\0';
}
}
result = Curl_sasl_create_cram_md5_message(data, chlg64, conn->user,
conn->passwd, &rplyb64, &len);
if(!result) {
if(rplyb64) {
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
if(!result)
state(conn, POP3_AUTH_FINAL);
Curl_safefree(rplyb64);
}
return result;
}
/* For AUTH DIGEST-MD5 challenge responses */
static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
char *chlg64 = data->state.buffer;
size_t len = 0;
char *rplyb64 = NULL;
(void)instate; /* no use for this yet */
if(pop3code != '+') {
failf(data, "Access denied: %d", pop3code);
return CURLE_LOGIN_DENIED;
}
/* Get the challenge */
for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
;
result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
conn->passwd, "pop",
&rplyb64, &len);
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
if(!result) {
if(rplyb64) {
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
if(!result)
state(conn, POP3_AUTH_DIGESTMD5_RESP);
}
Curl_safefree(rplyb64);
}
return result;
}
/* For AUTH DIGEST-MD5 challenge-response responses */
static CURLcode pop3_state_auth_digest_resp_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;
}
else {
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "");
if(!result)
state(conn, POP3_AUTH_FINAL);
}
return result;
}
#ifdef USE_NTLM
/* For AUTH NTLM responses */
static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
size_t len = 0;
char *type1msg = NULL;
(void)instate; /* no use for this yet */
if(pop3code != '+') {
failf(data, "Access denied: %d", pop3code);
result = CURLE_LOGIN_DENIED;
}
else {
result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
if(!result) {
if(type1msg) {
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg);
if(!result)
state(conn, POP3_AUTH_NTLM_TYPE2MSG);
}
Curl_safefree(type1msg);
}
}
return result;
}
/* For NTLM type-2 responses (sent in reponse to our type-1 message) */
static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
int pop3code,
pop3state instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
size_t len = 0;
char *type3msg = NULL;
(void)instate; /* no use for this yet */
if(pop3code != '+') {
failf(data, "Access denied: %d", pop3code);
result = CURLE_LOGIN_DENIED;
}
else {
result = Curl_sasl_create_ntlm_type3_message(data,
data->state.buffer + 2,
conn->user, conn->passwd,
&conn->ntlm,
&type3msg, &len);
if(!result) {
if(type3msg) {
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg);
if(!result)
state(conn, POP3_AUTH_FINAL);
}
Curl_safefree(type3msg);
}
}
return result;
}
#endif
/* For final responses to the AUTH sequence */
static CURLcode pop3_state_auth_final_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;
}
else
/* End of connect phase */
state(conn, POP3_STOP);
return result;
}
#ifndef CURL_DISABLE_CRYPTO_AUTH
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;
}
else
/* End of connect phase */
state(conn, POP3_STOP);