summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/smtp.c
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2015-08-12 19:43:52 (GMT)
committerBrad King <brad.king@kitware.com>2015-08-12 19:43:52 (GMT)
commit91e8d35ab8ec2d62478a42eff10af88713497fad (patch)
treeff8cd1bd1ce3c42ef56c76b5ab471831a80c4665 /Utilities/cmcurl/lib/smtp.c
parent602cdc06a01b7c5c0eb444111382b09040f677ee (diff)
parent706542615828488a5ad197d0ef3dd5e42eb739c4 (diff)
downloadCMake-91e8d35ab8ec2d62478a42eff10af88713497fad.zip
CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.tar.gz
CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.tar.bz2
Merge branch 'curl-upstream' into update-curl
Resolve conflicts by taking upstream side when possible and otherwise integrating the changes from both sides. Be carful in CMakeLists.txt where the OPENSSL code block that we modified previously has moved, and preserve our previous modifications in the new location.
Diffstat (limited to 'Utilities/cmcurl/lib/smtp.c')
-rw-r--r--Utilities/cmcurl/lib/smtp.c1019
1 files changed, 156 insertions, 863 deletions
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index 9aa8b15..dada087 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, 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
@@ -62,7 +62,6 @@
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
-#include "if2ip.h"
#include "hostip.h"
#include "progress.h"
#include "transfer.h"
@@ -83,10 +82,7 @@
#include "curl_gethostname.h"
#include "curl_sasl.h"
#include "warnless.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
+#include "curl_printf.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
@@ -106,10 +102,10 @@ static CURLcode smtp_setup_connection(struct connectdata *conn);
static CURLcode smtp_parse_url_options(struct connectdata *conn);
static CURLcode smtp_parse_url_path(struct connectdata *conn);
static CURLcode smtp_parse_custom_request(struct connectdata *conn);
-static CURLcode smtp_calc_sasl_details(struct connectdata *conn,
- const char **mech,
- char **initresp, size_t *len,
- smtpstate *state1, smtpstate *state2);
+static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
+ const char *initresp);
+static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
+static void smtp_get_message(char *buffer, char** outptr);
/*
* SMTP protocol handler.
@@ -214,6 +210,17 @@ static const struct Curl_handler Curl_handler_smtps_proxy = {
#endif
#endif
+/* SASL parameters for the smtp protocol */
+static const struct SASLproto saslsmtp = {
+ "smtp", /* The service name */
+ 334, /* Code received when continuation is expected */
+ 235, /* Code to receive upon authentication success */
+ 512 - 8, /* Maximum initial response length (no max) */
+ smtp_perform_auth, /* Send authentication command */
+ smtp_continue_auth, /* Send authentication continuation */
+ smtp_get_message /* Get SASL response message */
+};
+
#ifdef USE_SSL
static void smtp_to_smtps(struct connectdata *conn)
{
@@ -310,20 +317,7 @@ static void state(struct connectdata *conn, smtpstate newstate)
"HELO",
"STARTTLS",
"UPGRADETLS",
- "AUTH_PLAIN",
- "AUTH_LOGIN",
- "AUTH_LOGIN_PASSWD",
- "AUTH_CRAMMD5",
- "AUTH_DIGESTMD5",
- "AUTH_DIGESTMD5_RESP",
- "AUTH_NTLM",
- "AUTH_NTLM_TYPE2MSG",
- "AUTH_GSSAPI",
- "AUTH_GSSAPI_TOKEN",
- "AUTH_GSSAPI_NO_DATA",
- "AUTH_XOAUTH2",
- "AUTH_CANCEL",
- "AUTH_FINAL",
+ "AUTH",
"COMMAND",
"MAIL",
"RCPT",
@@ -353,11 +347,11 @@ static CURLcode smtp_perform_ehlo(struct connectdata *conn)
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- smtpc->authmechs = 0; /* No known authentication mechanisms yet */
- smtpc->authused = 0; /* Clear the authentication mechanism used
- for esmtp connections */
- smtpc->tls_supported = FALSE; /* Clear the TLS capability */
- smtpc->auth_supported = FALSE; /* Clear the AUTH capability */
+ smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */
+ smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism
+ used for esmtp connections */
+ smtpc->tls_supported = FALSE; /* Clear the TLS capability */
+ smtpc->auth_supported = FALSE; /* Clear the AUTH capability */
/* Send the EHLO command */
result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
@@ -379,8 +373,8 @@ static CURLcode smtp_perform_helo(struct connectdata *conn)
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- smtpc->authused = 0; /* No authentication mechanism used in smtp
- connections */
+ smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used
+ in smtp connections */
/* Send the HELO command */
result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
@@ -446,25 +440,18 @@ static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
*/
static CURLcode smtp_perform_auth(struct connectdata *conn,
const char *mech,
- const char *initresp, size_t len,
- smtpstate state1, smtpstate state2)
+ const char *initresp)
{
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- if(initresp && 8 + strlen(mech) + len <= 512) { /* AUTH <mech> ...<crlf> */
+ if(initresp) { /* AUTH <mech> ...<crlf> */
/* Send the AUTH command with the initial response */
result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
-
- if(!result)
- state(conn, state2);
}
else {
/* Send the AUTH command */
result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
-
- if(!result)
- state(conn, state1);
}
return result;
@@ -472,6 +459,19 @@ static CURLcode smtp_perform_auth(struct connectdata *conn,
/***********************************************************************
*
+ * smtp_continue_auth()
+ *
+ * Sends SASL continuation data or cancellation.
+ */
+static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
+{
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ return Curl_pp_sendf(&smtpc->pp, "%s", resp);
+}
+
+/***********************************************************************
+ *
* smtp_perform_authentication()
*
* Initiates the authentication sequence, with the appropriate SASL
@@ -481,31 +481,22 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- const char *mech = NULL;
- char *initresp = NULL;
- size_t len = 0;
- smtpstate state1 = SMTP_STOP;
- smtpstate state2 = SMTP_STOP;
+ saslprogress progress;
- /* Check we have a username and password to authenticate with, and the
+ /* Check we have enough data to authenticate with, and the
server supports authentiation, and end the connect phase if not */
- if(!conn->bits.user_passwd || !smtpc->auth_supported) {
+ if(!smtpc->auth_supported ||
+ !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
state(conn, SMTP_STOP);
-
return result;
}
/* Calculate the SASL login details */
- result = smtp_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
- &state2);
+ result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);
if(!result) {
- if(mech) {
- /* Perform SASL based authentication */
- result = smtp_perform_auth(conn, mech, initresp, len, state1, state2);
-
- Curl_safefree(initresp);
- }
+ if(progress == SASL_INPROGRESS)
+ state(conn, SMTP_AUTH);
else {
/* Other mechanisms not supported */
infof(conn->data, "No known authentication mechanisms supported!\n");
@@ -572,7 +563,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
return CURLE_OUT_OF_MEMORY;
/* Calculate the optional AUTH parameter */
- if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.authused) {
+ if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
else
@@ -580,7 +571,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
auth = strdup("<>");
if(!auth) {
- Curl_safefree(from);
+ free(from);
return CURLE_OUT_OF_MEMORY;
}
@@ -591,8 +582,8 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
if(!size) {
- Curl_safefree(from);
- Curl_safefree(auth);
+ free(from);
+ free(auth);
return CURLE_OUT_OF_MEMORY;
}
@@ -612,9 +603,9 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
result = Curl_pp_sendf(&conn->proto.smtpc.pp,
"MAIL FROM:%s SIZE=%s", from, size);
- Curl_safefree(from);
- Curl_safefree(auth);
- Curl_safefree(size);
+ free(from);
+ free(auth);
+ free(size);
if(!result)
state(conn, SMTP_MAIL);
@@ -754,6 +745,9 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
/* Loop through the data line */
for(;;) {
+ size_t llen;
+ unsigned int mechbit;
+
while(len &&
(*line == ' ' || *line == '\t' ||
*line == '\r' || *line == '\n')) {
@@ -772,22 +766,9 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
wordlen++;
/* Test the word for a matching authentication mechanism */
- if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
- smtpc->authmechs |= SASL_MECH_LOGIN;
- else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
- smtpc->authmechs |= SASL_MECH_PLAIN;
- else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
- smtpc->authmechs |= SASL_MECH_CRAM_MD5;
- else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
- smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
- else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
- smtpc->authmechs |= SASL_MECH_GSSAPI;
- else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
- smtpc->authmechs |= SASL_MECH_EXTERNAL;
- else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
- smtpc->authmechs |= SASL_MECH_NTLM;
- else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
- smtpc->authmechs |= SASL_MECH_XOAUTH2;
+ if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) &&
+ llen == wordlen)
+ smtpc->sasl.authmechs |= mechbit;
line += wordlen;
len -= wordlen;
@@ -836,565 +817,31 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
return result;
}
-/* For AUTH PLAIN (without initial response) responses */
-static CURLcode smtp_state_auth_plain_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate 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(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Create the authorisation message */
- result = Curl_sasl_create_plain_message(conn->data, conn->user,
- conn->passwd, &plainauth, &len);
- if(!result && plainauth) {
- /* Send the message */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
-
- if(!result)
- state(conn, SMTP_AUTH_FINAL);
- }
- }
-
- Curl_safefree(plainauth);
-
- return result;
-}
-
-/* For AUTH LOGIN (without initial response) responses */
-static CURLcode smtp_state_auth_login_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate 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(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Create the user message */
- result = Curl_sasl_create_login_message(conn->data, conn->user,
- &authuser, &len);
- if(!result && authuser) {
- /* Send the user */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
-
- if(!result)
- state(conn, SMTP_AUTH_LOGIN_PASSWD);
- }
- }
-
- Curl_safefree(authuser);
-
- return result;
-}
-
-/* For AUTH LOGIN user entry responses */
-static CURLcode smtp_state_auth_login_password_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate 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(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Create the password message */
- result = Curl_sasl_create_login_message(conn->data, conn->passwd,
- &authpasswd, &len);
- if(!result && authpasswd) {
- /* Send the password */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
-
- if(!result)
- state(conn, SMTP_AUTH_FINAL);
- }
- }
-
- Curl_safefree(authpasswd);
-
- return result;
-}
-
-#ifndef CURL_DISABLE_CRYPTO_AUTH
-/* For AUTH CRAM-MD5 responses */
-static CURLcode smtp_state_auth_cram_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- char *chlg = NULL;
- char *chlg64 = NULL;
- char *rplyb64 = NULL;
- size_t len = 0;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- return CURLE_LOGIN_DENIED;
- }
-
- /* Get the challenge message */
- smtp_get_message(data->state.buffer, &chlg64);
-
- /* Decode the challenge message */
- result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len);
- if(result) {
- /* Send the cancellation */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
-
- if(!result)
- state(conn, SMTP_AUTH_CANCEL);
- }
- else {
- /* Create the response message */
- result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user,
- conn->passwd, &rplyb64, &len);
- if(!result && rplyb64) {
- /* Send the response */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
-
- if(!result)
- state(conn, SMTP_AUTH_FINAL);
- }
- }
-
- Curl_safefree(chlg);
- Curl_safefree(rplyb64);
-
- return result;
-}
-
-/* For AUTH DIGEST-MD5 challenge responses */
-static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- char *chlg64 = NULL;
- char *rplyb64 = NULL;
- size_t len = 0;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- return CURLE_LOGIN_DENIED;
- }
-
- /* Get the challenge message */
- smtp_get_message(data->state.buffer, &chlg64);
-
- /* Create the response message */
- result = Curl_sasl_create_digest_md5_message(data, chlg64,
- conn->user, conn->passwd,
- "smtp", &rplyb64, &len);
- if(result) {
- if(result == CURLE_BAD_CONTENT_ENCODING) {
- /* Send the cancellation */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
-
- if(!result)
- state(conn, SMTP_AUTH_CANCEL);
- }
- }
- else {
- /* Send the response */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
-
- if(!result)
- state(conn, SMTP_AUTH_DIGESTMD5_RESP);
- }
-
- Curl_safefree(rplyb64);
-
- return result;
-}
-
-/* For AUTH DIGEST-MD5 challenge-response responses */
-static CURLcode smtp_state_auth_digest_resp_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Authentication failed: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Send an empty response */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "");
-
- if(!result)
- state(conn, SMTP_AUTH_FINAL);
- }
-
- return result;
-}
-
-#endif
-
-#ifdef USE_NTLM
-/* For AUTH NTLM (without initial response) responses */
-static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- char *type1msg = NULL;
- size_t len = 0;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Create the type-1 message */
- result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
- &conn->ntlm,
- &type1msg, &len);
- if(!result && type1msg) {
- /* Send the message */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg);
-
- if(!result)
- state(conn, SMTP_AUTH_NTLM_TYPE2MSG);
- }
- }
-
- Curl_safefree(type1msg);
-
- return result;
-}
-
-/* For NTLM type-2 responses (sent in reponse to our type-1 message) */
-static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- char *type2msg = NULL;
- char *type3msg = NULL;
- size_t len = 0;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Get the type-2 message */
- smtp_get_message(data->state.buffer, &type2msg);
-
- /* Decode the type-2 message */
- result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm);
- if(result) {
- /* Send the cancellation */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
-
- if(!result)
- state(conn, SMTP_AUTH_CANCEL);
- }
- else {
- /* Create the type-3 message */
- result = Curl_sasl_create_ntlm_type3_message(data, conn->user,
- conn->passwd, &conn->ntlm,
- &type3msg, &len);
- if(!result && type3msg) {
- /* Send the message */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg);
-
- if(!result)
- state(conn, SMTP_AUTH_FINAL);
- }
- }
- }
-
- Curl_safefree(type3msg);
-
- return result;
-}
-#endif
-
-#if defined(USE_WINDOWS_SSPI)
-/* For AUTH GSSAPI (without initial response) responses */
-static CURLcode smtp_state_auth_gssapi_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct smtp_conn *smtpc = &conn->proto.smtpc;
- char *respmsg = NULL;
- size_t len = 0;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Create the initial response message */
- result = Curl_sasl_create_gssapi_user_message(data, conn->user,
- conn->passwd, "smtp",
- smtpc->mutual_auth, NULL,
- &conn->krb5,
- &respmsg, &len);
- if(!result && respmsg) {
- /* Send the message */
- result = Curl_pp_sendf(&smtpc->pp, "%s", respmsg);
-
- if(!result)
- state(conn, SMTP_AUTH_GSSAPI_TOKEN);
- }
- }
-
- Curl_safefree(respmsg);
-
- return result;
-}
-
-/* For AUTH GSSAPI user token responses */
-static CURLcode smtp_state_auth_gssapi_token_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct smtp_conn *smtpc = &conn->proto.smtpc;
- char *chlgmsg = NULL;
- char *respmsg = NULL;
- size_t len = 0;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Get the challenge message */
- smtp_get_message(data->state.buffer, &chlgmsg);
-
- if(smtpc->mutual_auth)
- /* Decode the user token challenge and create the optional response
- message */
- result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL,
- smtpc->mutual_auth,
- chlgmsg, &conn->krb5,
- &respmsg, &len);
- else
- /* Decode the security challenge and create the response message */
- result = Curl_sasl_create_gssapi_security_message(data, chlgmsg,
- &conn->krb5,
- &respmsg, &len);
-
- if(result) {
- if(result == CURLE_BAD_CONTENT_ENCODING) {
- /* Send the cancellation */
- result = Curl_pp_sendf(&smtpc->pp, "%s", "*");
-
- if(!result)
- state(conn, SMTP_AUTH_CANCEL);
- }
- }
- else {
- /* Send the response */
- if(respmsg)
- result = Curl_pp_sendf(&smtpc->pp, "%s", respmsg);
- else
- result = Curl_pp_sendf(&smtpc->pp, "%s", "");
-
- if(!result)
- state(conn, (smtpc->mutual_auth ? SMTP_AUTH_GSSAPI_NO_DATA :
- SMTP_AUTH_FINAL));
- }
- }
-
- Curl_safefree(respmsg);
-
- return result;
-}
-
-/* For AUTH GSSAPI no data responses */
-static CURLcode smtp_state_auth_gssapi_no_data_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- char *chlgmsg = NULL;
- char *respmsg = NULL;
- size_t len = 0;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Get the challenge message */
- smtp_get_message(data->state.buffer, &chlgmsg);
-
- /* Decode the security challenge and create the response message */
- result = Curl_sasl_create_gssapi_security_message(data, chlgmsg,
- &conn->krb5,
- &respmsg, &len);
- if(result) {
- if(result == CURLE_BAD_CONTENT_ENCODING) {
- /* Send the cancellation */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*");
-
- if(!result)
- state(conn, SMTP_AUTH_CANCEL);
- }
- }
- else {
- /* Send the response */
- if(respmsg) {
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", respmsg);
-
- if(!result)
- state(conn, SMTP_AUTH_FINAL);
- }
- }
- }
-
- Curl_safefree(respmsg);
-
- return result;
-}
-#endif
-
-/* For AUTH XOAUTH2 (without initial response) responses */
-static CURLcode smtp_state_auth_xoauth2_resp(struct connectdata *conn,
- int smtpcode, smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- size_t len = 0;
- char *xoauth = NULL;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 334) {
- failf(data, "Access denied: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else {
- /* Create the authorisation message */
- result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
- conn->xoauth2_bearer,
- &xoauth, &len);
- if(!result && xoauth) {
- /* Send the message */
- result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", xoauth);
-
- if(!result)
- state(conn, SMTP_AUTH_FINAL);
- }
- }
-
- Curl_safefree(xoauth);
-
- return result;
-}
-
-/* For AUTH cancellation responses */
-static CURLcode smtp_state_auth_cancel_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
+/* For SASL authentication responses */
+static CURLcode smtp_state_auth_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- const char *mech = NULL;
- char *initresp = NULL;
- size_t len = 0;
- smtpstate state1 = SMTP_STOP;
- smtpstate state2 = SMTP_STOP;
+ saslprogress progress;
- (void)smtpcode;
(void)instate; /* no use for this yet */
- /* Remove the offending mechanism from the supported list */
- smtpc->authmechs ^= smtpc->authused;
-
- /* Calculate alternative SASL login details */
- result = smtp_calc_sasl_details(conn, &mech, &initresp, &len, &state1,
- &state2);
-
- if(!result) {
- /* Do we have any mechanisms left? */
- if(mech) {
- /* Retry SASL based authentication */
- result = smtp_perform_auth(conn, mech, initresp, len, state1, state2);
-
- Curl_safefree(initresp);
- }
- else {
+ result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
+ if(!result)
+ switch(progress) {
+ case SASL_DONE:
+ state(conn, SMTP_STOP); /* Authenticated */
+ break;
+ case SASL_IDLE: /* No mechanism left after cancellation */
failf(data, "Authentication cancelled");
-
result = CURLE_LOGIN_DENIED;
+ break;
+ default:
+ break;
}
- }
-
- return result;
-}
-
-/* For final responses in the AUTH sequence */
-static CURLcode smtp_state_auth_final_resp(struct connectdata *conn,
- int smtpcode,
- smtpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
-
- (void)instate; /* no use for this yet */
-
- if(smtpcode != 235) {
- failf(data, "Authentication failed: %d", smtpcode);
- result = CURLE_LOGIN_DENIED;
- }
- else
- /* End of connect phase */
- state(conn, SMTP_STOP);
return result;
}
@@ -1592,69 +1039,8 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
break;
- case SMTP_AUTH_PLAIN:
- result = smtp_state_auth_plain_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_LOGIN:
- result = smtp_state_auth_login_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_LOGIN_PASSWD:
- result = smtp_state_auth_login_password_resp(conn, smtpcode,
- smtpc->state);
- break;
-
-#ifndef CURL_DISABLE_CRYPTO_AUTH
- case SMTP_AUTH_CRAMMD5:
- result = smtp_state_auth_cram_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_DIGESTMD5:
- result = smtp_state_auth_digest_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_DIGESTMD5_RESP:
- result = smtp_state_auth_digest_resp_resp(conn, smtpcode, smtpc->state);
- break;
-#endif
-
-#ifdef USE_NTLM
- case SMTP_AUTH_NTLM:
- result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_NTLM_TYPE2MSG:
- result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode,
- smtpc->state);
- break;
-#endif
-
-#if defined(USE_WINDOWS_SSPI)
- case SMTP_AUTH_GSSAPI:
- result = smtp_state_auth_gssapi_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_GSSAPI_TOKEN:
- result = smtp_state_auth_gssapi_token_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_GSSAPI_NO_DATA:
- result = smtp_state_auth_gssapi_no_data_resp(conn, smtpcode,
- smtpc->state);
- break;
-#endif
-
- case SMTP_AUTH_XOAUTH2:
- result = smtp_state_auth_xoauth2_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_CANCEL:
- result = smtp_state_auth_cancel_resp(conn, smtpcode, smtpc->state);
- break;
-
- case SMTP_AUTH_FINAL:
- result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state);
+ case SMTP_AUTH:
+ result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
break;
case SMTP_COMMAND:
@@ -1767,8 +1153,8 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
pp->endofresp = smtp_endofresp;
pp->conn = conn;
- /* Set the default preferred authentication mechanism */
- smtpc->prefmech = SASL_AUTH_ANY;
+ /* Initialize the SASL storage */
+ Curl_sasl_init(&smtpc->sasl, &saslsmtp);
/* Initialise the pingpong layer */
Curl_pp_init(pp);
@@ -1807,7 +1193,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
struct SessionHandle *data = conn->data;
struct SMTP *smtp = data->req.protop;
struct pingpong *pp = &conn->proto.smtpc.pp;
- const char *eob;
+ char *eob;
ssize_t len;
ssize_t bytes_written;
@@ -1827,30 +1213,45 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
/* Calculate the EOB taking into account any terminating CRLF from the
previous line of the email or the CRLF of the DATA command when there
- is "no mail data". RFC-5321, sect. 4.1.1.4. */
- eob = SMTP_EOB;
- len = SMTP_EOB_LEN;
+ is "no mail data". RFC-5321, sect. 4.1.1.4.
+
+ Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
+ fail when using a different pointer following a previous write, that
+ returned CURLE_AGAIN, we duplicate the EOB now rather than when the
+ bytes written doesn't equal len. */
if(smtp->trailing_crlf || !conn->data->state.infilesize) {
- eob += 2;
- len -= 2;
+ eob = strdup(SMTP_EOB + 2);
+ len = SMTP_EOB_LEN - 2;
+ }
+ else {
+ eob = strdup(SMTP_EOB);
+ len = SMTP_EOB_LEN;
}
+ if(!eob)
+ return CURLE_OUT_OF_MEMORY;
+
/* Send the end of block data */
result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
- if(result)
+ if(result) {
+ free(eob);
return result;
+ }
if(bytes_written != len) {
/* The whole chunk was not sent so keep it around and adjust the
pingpong structure accordingly */
- pp->sendthis = strdup(eob);
+ pp->sendthis = eob;
pp->sendsize = len;
pp->sendleft = len - bytes_written;
}
- else
+ else {
/* Successfully sent so adjust the response timeout relative to now */
pp->response = Curl_tvnow();
+ free(eob);
+ }
+
state(conn, SMTP_POSTDATA);
/* Run the state-machine
@@ -1971,7 +1372,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
Curl_pp_disconnect(&smtpc->pp);
/* Cleanup the SASL module */
- Curl_sasl_cleanup(conn, smtpc->authused);
+ Curl_sasl_cleanup(conn, smtpc->sasl.authused);
/* Cleanup our connection based variables */
Curl_safefree(smtpc->domain);
@@ -2092,52 +1493,30 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- const char *options = conn->options;
- const char *ptr = options;
- bool reset = TRUE;
+ const char *ptr = conn->options;
- while(ptr && *ptr) {
+ smtpc->sasl.resetprefs = TRUE;
+
+ while(!result && ptr && *ptr) {
const char *key = ptr;
+ const char *value;
while(*ptr && *ptr != '=')
ptr++;
- if(strnequal(key, "AUTH", 4)) {
- size_t len = 0;
- const char *value = ++ptr;
-
- if(reset) {
- reset = FALSE;
- smtpc->prefmech = SASL_AUTH_NONE;
- }
+ value = ptr + 1;
- while(*ptr && *ptr != ';') {
- ptr++;
- len++;
- }
+ while(*ptr && *ptr != ';')
+ ptr++;
- if(strnequal(value, "*", len))
- smtpc->prefmech = SASL_AUTH_ANY;
- else if(strnequal(value, SASL_MECH_STRING_LOGIN, len))
- smtpc->prefmech |= SASL_MECH_LOGIN;
- else if(strnequal(value, SASL_MECH_STRING_PLAIN, len))
- smtpc->prefmech |= SASL_MECH_PLAIN;
- else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len))
- smtpc->prefmech |= SASL_MECH_CRAM_MD5;
- else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len))
- smtpc->prefmech |= SASL_MECH_DIGEST_MD5;
- else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len))
- smtpc->prefmech |= SASL_MECH_GSSAPI;
- else if(strnequal(value, SASL_MECH_STRING_NTLM, len))
- smtpc->prefmech |= SASL_MECH_NTLM;
- else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len))
- smtpc->prefmech |= SASL_MECH_XOAUTH2;
-
- if(*ptr == ';')
- ptr++;
- }
+ if(strnequal(key, "AUTH=", 5))
+ result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
+ value, ptr - value);
else
result = CURLE_URL_MALFORMAT;
+
+ if(*ptr == ';')
+ ptr++;
}
return result;
@@ -2189,111 +1568,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn)
return result;
}
-/***********************************************************************
- *
- * smtp_calc_sasl_details()
- *
- * Calculate the required login details for SASL authentication.
- */
-static CURLcode smtp_calc_sasl_details(struct connectdata *conn,
- const char **mech,
- char **initresp, size_t *len,
- smtpstate *state1, smtpstate *state2)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct smtp_conn *smtpc = &conn->proto.smtpc;
-
- /* Calculate the supported authentication mechanism, by decreasing order of
- security, as well as the initial response where appropriate */
-#if defined(USE_WINDOWS_SSPI)
- if((smtpc->authmechs & SASL_MECH_GSSAPI) &&
- (smtpc->prefmech & SASL_MECH_GSSAPI)) {
- smtpc->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */
-
- *mech = SASL_MECH_STRING_GSSAPI;
- *state1 = SMTP_AUTH_GSSAPI;
- *state2 = SMTP_AUTH_GSSAPI_TOKEN;
- smtpc->authused = SASL_MECH_GSSAPI;
-
- if(data->set.sasl_ir)
- result = Curl_sasl_create_gssapi_user_message(data, conn->user,
- conn->passwd, "smtp",
- smtpc->mutual_auth,
- NULL, &conn->krb5,
- initresp, len);
- }
- else
-#endif
-#ifndef CURL_DISABLE_CRYPTO_AUTH
- if((smtpc->authmechs & SASL_MECH_DIGEST_MD5) &&
- (smtpc->prefmech & SASL_MECH_DIGEST_MD5)) {
- *mech = SASL_MECH_STRING_DIGEST_MD5;
- *state1 = SMTP_AUTH_DIGESTMD5;
- smtpc->authused = SASL_MECH_DIGEST_MD5;
- }
- else if((smtpc->authmechs & SASL_MECH_CRAM_MD5) &&
- (smtpc->prefmech & SASL_MECH_CRAM_MD5)) {
- *mech = SASL_MECH_STRING_CRAM_MD5;
- *state1 = SMTP_AUTH_CRAMMD5;
- smtpc->authused = SASL_MECH_CRAM_MD5;
- }
- else
-#endif
-#ifdef USE_NTLM
- if((smtpc->authmechs & SASL_MECH_NTLM) &&
- (smtpc->prefmech & SASL_MECH_NTLM)) {
- *mech = SASL_MECH_STRING_NTLM;
- *state1 = SMTP_AUTH_NTLM;
- *state2 = SMTP_AUTH_NTLM_TYPE2MSG;
- smtpc->authused = SASL_MECH_NTLM;
-
- if(data->set.sasl_ir)
- result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
- &conn->ntlm,
- initresp, len);
- }
- else
-#endif
- if(((smtpc->authmechs & SASL_MECH_XOAUTH2) &&
- (smtpc->prefmech & SASL_MECH_XOAUTH2) &&
- (smtpc->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
- *mech = SASL_MECH_STRING_XOAUTH2;
- *state1 = SMTP_AUTH_XOAUTH2;
- *state2 = SMTP_AUTH_FINAL;
- smtpc->authused = SASL_MECH_XOAUTH2;
-
- if(data->set.sasl_ir)
- result = Curl_sasl_create_xoauth2_message(data, conn->user,
- conn->xoauth2_bearer,
- initresp, len);
- }
- else if((smtpc->authmechs & SASL_MECH_LOGIN) &&
- (smtpc->prefmech & SASL_MECH_LOGIN)) {
- *mech = SASL_MECH_STRING_LOGIN;
- *state1 = SMTP_AUTH_LOGIN;
- *state2 = SMTP_AUTH_LOGIN_PASSWD;
- smtpc->authused = SASL_MECH_LOGIN;
-
- if(data->set.sasl_ir)
- result = Curl_sasl_create_login_message(data, conn->user, initresp, len);
- }
- else if((smtpc->authmechs & SASL_MECH_PLAIN) &&
- (smtpc->prefmech & SASL_MECH_PLAIN)) {
- *mech = SASL_MECH_STRING_PLAIN;
- *state1 = SMTP_AUTH_PLAIN;
- *state2 = SMTP_AUTH_FINAL;
- smtpc->authused = SASL_MECH_PLAIN;
-
- if(data->set.sasl_ir)
- result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
- initresp, len);
- }
-
- return result;
-}
-
-CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
+CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
{
/* When sending a SMTP payload we must detect CRLF. sequences making sure
they are sent as CRLF.. instead, as a . on the beginning of a line will
@@ -2305,17 +1580,26 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
ssize_t si;
struct SessionHandle *data = conn->data;
struct SMTP *smtp = data->req.protop;
+ char *scratch = data->state.scratch;
+ char *newscratch = NULL;
+ char *oldscratch = NULL;
+ size_t eob_sent;
+
+ /* Do we need to allocate a scratch buffer? */
+ if(!scratch || data->set.crlf) {
+ oldscratch = scratch;
- /* Do we need to allocate the scatch buffer? */
- if(!data->state.scratch) {
- data->state.scratch = malloc(2 * BUFSIZE);
+ scratch = newscratch = malloc(2 * BUFSIZE);
+ if(!newscratch) {
+ failf(data, "Failed to alloc scratch buffer!");
- if(!data->state.scratch) {
- failf (data, "Failed to alloc scratch buffer!");
return CURLE_OUT_OF_MEMORY;
}
}
+ /* Have we already sent part of the EOB? */
+ eob_sent = smtp->eob;
+
/* This loop can be improved by some kind of Boyer-Moore style of
approach but that is saved for later... */
for(i = 0, si = 0; i < nread; i++) {
@@ -2330,8 +1614,8 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
}
else if(smtp->eob) {
/* A previous substring matched so output that first */
- memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
- si += smtp->eob;
+ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
+ si += smtp->eob - eob_sent;
/* Then compare the first byte */
if(SMTP_EOB[0] == data->req.upload_fromhere[i])
@@ -2339,6 +1623,8 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
else
smtp->eob = 0;
+ eob_sent = 0;
+
/* Reset the trailing CRLF flag as there was more data */
smtp->trailing_crlf = FALSE;
}
@@ -2346,31 +1632,38 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
/* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
if(SMTP_EOB_FIND_LEN == smtp->eob) {
/* Copy the replacement data to the target buffer */
- memcpy(&data->state.scratch[si], SMTP_EOB_REPL, SMTP_EOB_REPL_LEN);
- si += SMTP_EOB_REPL_LEN;
+ memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
+ SMTP_EOB_REPL_LEN - eob_sent);
+ si += SMTP_EOB_REPL_LEN - eob_sent;
smtp->eob = 0;
+ eob_sent = 0;
}
else if(!smtp->eob)
- data->state.scratch[si++] = data->req.upload_fromhere[i];
+ scratch[si++] = data->req.upload_fromhere[i];
}
- if(smtp->eob) {
+ if(smtp->eob - eob_sent) {
/* A substring matched before processing ended so output that now */
- memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
- si += smtp->eob;
- smtp->eob = 0;
+ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
+ si += smtp->eob - eob_sent;
}
+ /* Only use the new buffer if we replaced something */
if(si != nread) {
- /* Only use the new buffer if we replaced something */
- nread = si;
-
/* Upload from the new (replaced) buffer instead */
- data->req.upload_fromhere = data->state.scratch;
+ data->req.upload_fromhere = scratch;
+
+ /* Save the buffer so it can be freed later */
+ data->state.scratch = scratch;
+
+ /* Free the old scratch buffer */
+ free(oldscratch);
/* Set the new amount too */
- data->req.upload_present = nread;
+ data->req.upload_present = si;
}
+ else
+ free(newscratch);
return CURLE_OK;
}