mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
smtp: Added support for NTLM authentication
Modified smtp_endofresp() to detect NTLM from the server specified list of supported authentication mechanisms. Modified smtp_authenticate() to start the sending of the NTLM data. Added smtp_auth_ntlm_type1_message() which creates a NTLM type-1 message. This function is used by authenticate() to start the sending of data and by smtp_state_auth_ntlm_resp() when the AUTH command doesn't contain the type-1 message as part of the initial response. This lack of initial response can happen if an OOM error occurs or the type-1 message is longer than 504 characters. As the main AUTH command is limited to 512 character the data has to be transmitted in two parts; one containing the AUTH NTLM and the second containing the type-1 message. Added smtp_state_auth_ntlm_type2msg_resp() which handles the incoming type-2 message and sends an outgoing type-3 message. This type-2 message is sent by the server in response to our type-1 message. Modified smtp_state_auth_resp() to handle the response to: the AUTH NTLM without the initial response and the type-2 response. Modified smtp_disconnect() to cleanup the NTLM SSPI stack.
This commit is contained in:
parent
185ed3409a
commit
4d327d20c6
121
lib/smtp.c
121
lib/smtp.c
@ -85,6 +85,7 @@
|
|||||||
#include "curl_md5.h"
|
#include "curl_md5.h"
|
||||||
#include "curl_hmac.h"
|
#include "curl_hmac.h"
|
||||||
#include "curl_gethostname.h"
|
#include "curl_gethostname.h"
|
||||||
|
#include "curl_ntlm_msgs.h"
|
||||||
#include "warnless.h"
|
#include "warnless.h"
|
||||||
#include "http_proxy.h"
|
#include "http_proxy.h"
|
||||||
|
|
||||||
@ -263,6 +264,8 @@ static int smtp_endofresp(struct pingpong *pp, int *resp)
|
|||||||
smtpc->authmechs |= SMTP_AUTH_GSSAPI;
|
smtpc->authmechs |= SMTP_AUTH_GSSAPI;
|
||||||
else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
|
else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
|
||||||
smtpc->authmechs |= SMTP_AUTH_EXTERNAL;
|
smtpc->authmechs |= SMTP_AUTH_EXTERNAL;
|
||||||
|
else if(wordlen == 4 && !memcmp(line, "NTLM", 4))
|
||||||
|
smtpc->authmechs |= SMTP_AUTH_NTLM;
|
||||||
|
|
||||||
line += wordlen;
|
line += wordlen;
|
||||||
len -= wordlen;
|
len -= wordlen;
|
||||||
@ -290,6 +293,8 @@ static void state(struct connectdata *conn,
|
|||||||
"AUTHLOGIN",
|
"AUTHLOGIN",
|
||||||
"AUTHPASSWD",
|
"AUTHPASSWD",
|
||||||
"AUTHCRAM",
|
"AUTHCRAM",
|
||||||
|
"AUTHNTLM",
|
||||||
|
"AUTHNTLM_TYPE2MSG",
|
||||||
"AUTH",
|
"AUTH",
|
||||||
"MAIL",
|
"MAIL",
|
||||||
"RCPT",
|
"RCPT",
|
||||||
@ -311,6 +316,8 @@ static CURLcode smtp_state_ehlo(struct connectdata *conn)
|
|||||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
|
||||||
smtpc->authmechs = 0; /* No known authentication mechanisms yet. */
|
smtpc->authmechs = 0; /* No known authentication mechanisms yet. */
|
||||||
|
smtpc->authused = 0; /* Clear the authentication mechanism used
|
||||||
|
for esmtp connections */
|
||||||
|
|
||||||
/* send EHLO */
|
/* send EHLO */
|
||||||
result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
|
result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
|
||||||
@ -327,6 +334,9 @@ static CURLcode smtp_state_helo(struct connectdata *conn)
|
|||||||
CURLcode result;
|
CURLcode result;
|
||||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
|
||||||
|
smtpc->authused = 0; /* No authentication mechanism used in smtp
|
||||||
|
connections */
|
||||||
|
|
||||||
/* send HELO */
|
/* send HELO */
|
||||||
result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
|
result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
|
||||||
|
|
||||||
@ -380,6 +390,15 @@ static CURLcode smtp_auth_login_user(struct connectdata *conn,
|
|||||||
return Curl_base64_encode(conn->data, conn->user, ulen, outptr, outlen);
|
return Curl_base64_encode(conn->data, conn->user, ulen, outptr, outlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_NTLM
|
||||||
|
static CURLcode smtp_auth_ntlm_type1_message(struct connectdata *conn,
|
||||||
|
char **outptr, size_t *outlen)
|
||||||
|
{
|
||||||
|
return Curl_ntlm_create_type1_message(conn->user, conn->passwd,
|
||||||
|
&conn->ntlm, outptr, outlen);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static CURLcode smtp_authenticate(struct connectdata *conn)
|
static CURLcode smtp_authenticate(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
@ -404,6 +423,17 @@ static CURLcode smtp_authenticate(struct connectdata *conn)
|
|||||||
if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) {
|
if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) {
|
||||||
mech = "CRAM-MD5";
|
mech = "CRAM-MD5";
|
||||||
state1 = SMTP_AUTHCRAM;
|
state1 = SMTP_AUTHCRAM;
|
||||||
|
smtpc->authused = SMTP_AUTH_CRAM_MD5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
#ifdef USE_NTLM
|
||||||
|
if(smtpc->authmechs & SMTP_AUTH_NTLM) {
|
||||||
|
mech = "NTLM";
|
||||||
|
state1 = SMTP_AUTHNTLM;
|
||||||
|
state2 = SMTP_AUTHNTLM_TYPE2MSG;
|
||||||
|
smtpc->authused = SMTP_AUTH_NTLM;
|
||||||
|
result = smtp_auth_ntlm_type1_message(conn, &initresp, &len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
@ -411,12 +441,14 @@ static CURLcode smtp_authenticate(struct connectdata *conn)
|
|||||||
mech = "LOGIN";
|
mech = "LOGIN";
|
||||||
state1 = SMTP_AUTHLOGIN;
|
state1 = SMTP_AUTHLOGIN;
|
||||||
state2 = SMTP_AUTHPASSWD;
|
state2 = SMTP_AUTHPASSWD;
|
||||||
|
smtpc->authused = SMTP_AUTH_LOGIN;
|
||||||
result = smtp_auth_login_user(conn, &initresp, &len);
|
result = smtp_auth_login_user(conn, &initresp, &len);
|
||||||
}
|
}
|
||||||
else if(smtpc->authmechs & SMTP_AUTH_PLAIN) {
|
else if(smtpc->authmechs & SMTP_AUTH_PLAIN) {
|
||||||
mech = "PLAIN";
|
mech = "PLAIN";
|
||||||
state1 = SMTP_AUTHPLAIN;
|
state1 = SMTP_AUTHPLAIN;
|
||||||
state2 = SMTP_AUTH;
|
state2 = SMTP_AUTH;
|
||||||
|
smtpc->authused = SMTP_AUTH_PLAIN;
|
||||||
result = smtp_auth_plain_data(conn, &initresp, &len);
|
result = smtp_auth_plain_data(conn, &initresp, &len);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -759,6 +791,78 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NTLM
|
||||||
|
/* for the AUTH NTLM (without initial response) response. */
|
||||||
|
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 {
|
||||||
|
result = smtp_auth_ntlm_type1_message(conn, &type1msg, &len);
|
||||||
|
|
||||||
|
if(!result) {
|
||||||
|
if(type1msg) {
|
||||||
|
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg);
|
||||||
|
|
||||||
|
if(!result)
|
||||||
|
state(conn, SMTP_AUTHNTLM_TYPE2MSG);
|
||||||
|
}
|
||||||
|
Curl_safefree(type1msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for the NTLM type-2 response (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 *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 {
|
||||||
|
result = Curl_ntlm_decode_type2_message(data, data->state.buffer + 4, &conn->ntlm);
|
||||||
|
|
||||||
|
if(!result) {
|
||||||
|
result = Curl_ntlm_create_type3_message(conn->data, conn->user, conn->passwd, &conn->ntlm, &type3msg, &len);
|
||||||
|
|
||||||
|
if(!result) {
|
||||||
|
if(type3msg) {
|
||||||
|
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg);
|
||||||
|
|
||||||
|
if(!result)
|
||||||
|
state(conn, SMTP_AUTH);
|
||||||
|
}
|
||||||
|
Curl_safefree(type3msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* for final responses to AUTH sequences. */
|
/* for final responses to AUTH sequences. */
|
||||||
static CURLcode smtp_state_auth_resp(struct connectdata *conn,
|
static CURLcode smtp_state_auth_resp(struct connectdata *conn,
|
||||||
int smtpcode,
|
int smtpcode,
|
||||||
@ -1016,6 +1120,16 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NTLM
|
||||||
|
case SMTP_AUTHNTLM:
|
||||||
|
result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SMTP_AUTHNTLM_TYPE2MSG:
|
||||||
|
result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode, smtpc->state);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case SMTP_AUTH:
|
case SMTP_AUTH:
|
||||||
result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
|
result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
|
||||||
break;
|
break;
|
||||||
@ -1402,6 +1516,13 @@ static CURLcode smtp_disconnect(struct connectdata *conn,
|
|||||||
|
|
||||||
Curl_pp_disconnect(&smtpc->pp);
|
Curl_pp_disconnect(&smtpc->pp);
|
||||||
|
|
||||||
|
#ifdef USE_NTLM
|
||||||
|
/* Cleanup the ntlm structure */
|
||||||
|
if(smtpc->authused == SMTP_AUTH_NTLM) {
|
||||||
|
Curl_ntlm_sspi_cleanup(&conn->ntlm);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This won't already be freed in some error cases */
|
/* This won't already be freed in some error cases */
|
||||||
Curl_safefree(smtpc->domain);
|
Curl_safefree(smtpc->domain);
|
||||||
smtpc->domain = NULL;
|
smtpc->domain = NULL;
|
||||||
|
@ -40,6 +40,8 @@ typedef enum {
|
|||||||
SMTP_AUTHLOGIN,
|
SMTP_AUTHLOGIN,
|
||||||
SMTP_AUTHPASSWD,
|
SMTP_AUTHPASSWD,
|
||||||
SMTP_AUTHCRAM,
|
SMTP_AUTHCRAM,
|
||||||
|
SMTP_AUTHNTLM,
|
||||||
|
SMTP_AUTHNTLM_TYPE2MSG,
|
||||||
SMTP_AUTH,
|
SMTP_AUTH,
|
||||||
SMTP_MAIL, /* MAIL FROM */
|
SMTP_MAIL, /* MAIL FROM */
|
||||||
SMTP_RCPT, /* RCPT TO */
|
SMTP_RCPT, /* RCPT TO */
|
||||||
@ -57,6 +59,7 @@ struct smtp_conn {
|
|||||||
size_t eob; /* number of bytes of the EOB (End Of Body) that has been
|
size_t eob; /* number of bytes of the EOB (End Of Body) that has been
|
||||||
received thus far */
|
received thus far */
|
||||||
unsigned int authmechs; /* Accepted authentication methods. */
|
unsigned int authmechs; /* Accepted authentication methods. */
|
||||||
|
unsigned int authused; /* Authentication method used for the connection */
|
||||||
smtpstate state; /* always use smtp.c:state() to change state! */
|
smtpstate state; /* always use smtp.c:state() to change state! */
|
||||||
struct curl_slist *rcpt;
|
struct curl_slist *rcpt;
|
||||||
bool ssldone; /* is connect() over SSL done? only relevant in multi mode */
|
bool ssldone; /* is connect() over SSL done? only relevant in multi mode */
|
||||||
@ -69,6 +72,7 @@ struct smtp_conn {
|
|||||||
#define SMTP_AUTH_DIGEST_MD5 0x0008
|
#define SMTP_AUTH_DIGEST_MD5 0x0008
|
||||||
#define SMTP_AUTH_GSSAPI 0x0010
|
#define SMTP_AUTH_GSSAPI 0x0010
|
||||||
#define SMTP_AUTH_EXTERNAL 0x0020
|
#define SMTP_AUTH_EXTERNAL 0x0020
|
||||||
|
#define SMTP_AUTH_NTLM 0x0040
|
||||||
|
|
||||||
extern const struct Curl_handler Curl_handler_smtp;
|
extern const struct Curl_handler Curl_handler_smtp;
|
||||||
extern const struct Curl_handler Curl_handler_smtps;
|
extern const struct Curl_handler Curl_handler_smtps;
|
||||||
|
Loading…
Reference in New Issue
Block a user