diff options
Diffstat (limited to 'lib/smtp.c')
-rw-r--r-- | lib/smtp.c | 515 |
1 files changed, 335 insertions, 180 deletions
diff --git a/lib/smtp.c b/lib/smtp.c index 1626ae7da..8835b07a5 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -29,11 +29,6 @@ #include "setup.h" #ifndef CURL_DISABLE_SMTP -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -90,6 +85,7 @@ #include "curl_md5.h" #include "curl_hmac.h" #include "curl_gethostname.h" +#include "curl_ntlm_msgs.h" #include "warnless.h" #include "http_proxy.h" @@ -116,7 +112,6 @@ static CURLcode smtp_doing(struct connectdata *conn, static CURLcode smtp_setup_connection(struct connectdata * conn); static CURLcode smtp_state_upgrade_tls(struct connectdata *conn); - /* * SMTP protocol handler. */ @@ -132,6 +127,7 @@ const struct Curl_handler Curl_handler_smtp = { smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -140,7 +136,6 @@ const struct Curl_handler Curl_handler_smtp = { PROTOPT_CLOSEACTION /* flags */ }; - #ifdef USE_SSL /* * SMTPS protocol handler. @@ -157,6 +152,7 @@ const struct Curl_handler Curl_handler_smtps = { smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -182,6 +178,7 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { 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 */ @@ -190,7 +187,6 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { PROTOPT_NONE /* flags */ }; - #ifdef USE_SSL /* * HTTP-proxyed SMTPS protocol handler. @@ -207,6 +203,7 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { 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 */ @@ -217,7 +214,6 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { #endif #endif - /* Function that checks for an ending smtp status code at the start of the given string. As a side effect, it also flags allowed authentication mechanisms according @@ -272,6 +268,8 @@ static int smtp_endofresp(struct pingpong *pp, int *resp) smtpc->authmechs |= SMTP_AUTH_GSSAPI; else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) smtpc->authmechs |= SMTP_AUTH_EXTERNAL; + else if(wordlen == 4 && !memcmp(line, "NTLM", 4)) + smtpc->authmechs |= SMTP_AUTH_NTLM; line += wordlen; len -= wordlen; @@ -288,7 +286,7 @@ static void state(struct connectdata *conn, struct smtp_conn *smtpc = &conn->proto.smtpc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ - static const char * const names[]={ + static const char * const names[] = { "STOP", "SERVERGREET", "EHLO", @@ -299,6 +297,8 @@ static void state(struct connectdata *conn, "AUTHLOGIN", "AUTHPASSWD", "AUTHCRAM", + "AUTHNTLM", + "AUTHNTLM_TYPE2MSG", "AUTH", "MAIL", "RCPT", @@ -320,6 +320,8 @@ static CURLcode smtp_state_ehlo(struct connectdata *conn) 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 */ /* send EHLO */ result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); @@ -336,6 +338,9 @@ static CURLcode smtp_state_helo(struct connectdata *conn) CURLcode result; struct smtp_conn *smtpc = &conn->proto.smtpc; + smtpc->authused = 0; /* No authentication mechanism used in smtp + connections */ + /* send HELO */ result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); @@ -346,7 +351,8 @@ static CURLcode smtp_state_helo(struct connectdata *conn) return CURLE_OK; } -static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) +static CURLcode smtp_auth_plain_data(struct connectdata *conn, + char **outptr, size_t *outlen) { char plainauth[2 * MAX_CURL_USER_LENGTH + MAX_CURL_PASSWORD_LENGTH]; size_t ulen; @@ -355,8 +361,11 @@ static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) ulen = strlen(conn->user); plen = strlen(conn->passwd); - if(2 * ulen + plen + 2 > sizeof plainauth) - return 0; + if(2 * ulen + plen + 2 > sizeof plainauth) { + *outlen = 0; + *outptr = NULL; + return CURLE_OUT_OF_MEMORY; /* plainauth too small */ + } memcpy(plainauth, conn->user, ulen); plainauth[ulen] = '\0'; @@ -364,89 +373,108 @@ static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) plainauth[2 * ulen + 1] = '\0'; memcpy(plainauth + 2 * ulen + 2, conn->passwd, plen); return Curl_base64_encode(conn->data, plainauth, 2 * ulen + plen + 2, - outptr); + outptr, outlen); } -static size_t smtp_auth_login_user(struct connectdata * conn, char * * outptr) +static CURLcode smtp_auth_login_user(struct connectdata *conn, + char **outptr, size_t *outlen) { - size_t ulen; - - ulen = strlen(conn->user); + size_t ulen = strlen(conn->user); if(!ulen) { *outptr = strdup("="); - return *outptr? 1: 0; + if(*outptr) { + *outlen = (size_t) 1; + return CURLE_OK; + } + *outlen = 0; + return CURLE_OUT_OF_MEMORY; } - return Curl_base64_encode(conn->data, conn->user, ulen, outptr); + 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) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - char * initresp; - const char * mech; - size_t l; - smtpstate state1; - smtpstate state2; - - if(!conn->bits.user_passwd) - state(conn, SMTP_STOP); /* End of connect phase. */ - else { - initresp = (char *) NULL; - l = 1; + char *initresp = NULL; + const char *mech = NULL; + size_t len = 0; + smtpstate state1 = SMTP_STOP; + smtpstate state2 = SMTP_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, SMTP_STOP); - /* Check supported authentication mechanisms by decreasing order of - preference. */ - mech = (const char *) NULL; /* Avoid compiler warnings. */ - state1 = SMTP_STOP; - state2 = SMTP_STOP; + return result; + } + /* Check supported authentication mechanisms by decreasing order of + security. */ #ifndef CURL_DISABLE_CRYPTO_AUTH - if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) { - mech = "CRAM-MD5"; - state1 = SMTP_AUTHCRAM; - } - else + if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) { + mech = "CRAM-MD5"; + state1 = SMTP_AUTHCRAM; + smtpc->authused = SMTP_AUTH_CRAM_MD5; + } + else #endif - if(smtpc->authmechs & SMTP_AUTH_PLAIN) { - mech = "PLAIN"; - state1 = SMTP_AUTHPLAIN; - state2 = SMTP_AUTH; - l = smtp_auth_plain_data(conn, &initresp); - } - else if(smtpc->authmechs & SMTP_AUTH_LOGIN) { - mech = "LOGIN"; - state1 = SMTP_AUTHLOGIN; - state2 = SMTP_AUTHPASSWD; - l = smtp_auth_login_user(conn, &initresp); - } - else { - infof(conn->data, "No known auth mechanisms supported!\n"); - result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported. */ - } +#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 +#endif + if(smtpc->authmechs & SMTP_AUTH_LOGIN) { + mech = "LOGIN"; + state1 = SMTP_AUTHLOGIN; + state2 = SMTP_AUTHPASSWD; + smtpc->authused = SMTP_AUTH_LOGIN; + result = smtp_auth_login_user(conn, &initresp, &len); + } + else if(smtpc->authmechs & SMTP_AUTH_PLAIN) { + mech = "PLAIN"; + state1 = SMTP_AUTHPLAIN; + state2 = SMTP_AUTH; + smtpc->authused = SMTP_AUTH_PLAIN; + result = smtp_auth_plain_data(conn, &initresp, &len); + } + else { + infof(conn->data, "No known auth mechanisms supported!\n"); + result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported. */ + } - if(!result) { - if(!l) - result = CURLE_OUT_OF_MEMORY; - else if(initresp && - l + strlen(mech) <= 512 - 8) { /* AUTH <mech> ...<crlf> */ - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - free(initresp); + if(!result) { + if(initresp && + strlen(mech) + len <= 512 - 8) { /* AUTH <mech> ...<crlf> */ + result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - if(!result) - state(conn, state2); - } - else { - Curl_safefree(initresp); - - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); + if(!result) + state(conn, state2); + } + else { + result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); - if(!result) - state(conn, state1); - } + if(!result) + state(conn, state1); } + Curl_safefree(initresp); } return result; @@ -466,7 +494,7 @@ static void smtp_to_smtps(struct connectdata *conn) conn->handler = &Curl_handler_smtps; } #else -#define smtp_to_smtps(x) +#define smtp_to_smtps(x) Curl_nop_stmt #endif /* for STARTTLS responses */ @@ -499,6 +527,7 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn, } } } + return result; } @@ -566,6 +595,7 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, /* end the connect phase */ state(conn, SMTP_STOP); } + return result; } @@ -576,8 +606,8 @@ static CURLcode smtp_state_authplain_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - size_t l; - char * plainauth; + size_t len = 0; + char *plainauth = NULL; (void)instate; /* no use for this yet */ @@ -586,16 +616,16 @@ static CURLcode smtp_state_authplain_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - l = smtp_auth_plain_data(conn, &plainauth); + result = smtp_auth_plain_data(conn, &plainauth, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - free(plainauth); + if(!result) { + if(plainauth) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - if(!result) - state(conn, SMTP_AUTH); + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(plainauth); } } @@ -609,8 +639,8 @@ static CURLcode smtp_state_authlogin_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - size_t l; - char * authuser; + size_t len = 0; + char *authuser = NULL; (void)instate; /* no use for this yet */ @@ -619,16 +649,16 @@ static CURLcode smtp_state_authlogin_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - l = smtp_auth_login_user(conn, &authuser); + result = smtp_auth_login_user(conn, &authuser, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - free(authuser); + if(!result) { + if(authuser) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - if(!result) - state(conn, SMTP_AUTHPASSWD); + if(!result) + state(conn, SMTP_AUTHPASSWD); + } + Curl_safefree(authuser); } } @@ -643,8 +673,8 @@ static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn, CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; size_t plen; - size_t l; - char *authpasswd; + size_t len = 0; + char *authpasswd = NULL; (void)instate; /* no use for this yet */ @@ -658,16 +688,16 @@ static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn, if(!plen) result = Curl_pp_sendf(&conn->proto.smtpc.pp, "="); else { - l = Curl_base64_encode(data, conn->passwd, plen, &authpasswd); + result = Curl_base64_encode(data, conn->passwd, plen, &authpasswd, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - free(authpasswd); + if(!result) { + if(authpasswd) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - if(!result) - state(conn, SMTP_AUTH); + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(authpasswd); } } } @@ -687,9 +717,9 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, char * chlg64 = data->state.buffer; unsigned char * chlg; size_t chlglen; - size_t l; - char * rplyb64; - HMAC_context * ctxt; + size_t len = 0; + char *rplyb64 = NULL; + HMAC_context *ctxt; unsigned char digest[16]; char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1]; @@ -708,17 +738,17 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, chlglen = 0; if(*chlg64 != '=') { - for(l = strlen(chlg64); l--;) - if(chlg64[l] != '\r' && chlg64[l] != '\n' && chlg64[l] != ' ' && - chlg64[l] != '\t') + for(len = strlen(chlg64); len--;) + if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' && + chlg64[len] != '\t') break; - if(++l) { - chlg64[l] = '\0'; + if(++len) { + chlg64[len] = '\0'; - chlglen = Curl_base64_decode(chlg64, &chlg); - if(!chlglen) - return CURLE_OUT_OF_MEMORY; + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; } } @@ -728,17 +758,14 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, (unsigned int)(strlen(conn->passwd))); if(!ctxt) { - if(chlg) - free(chlg); - + Curl_safefree(chlg); return CURLE_OUT_OF_MEMORY; } if(chlglen > 0) Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen)); - if(chlg) - free(chlg); + Curl_safefree(chlg); Curl_HMAC_final(ctxt, digest); @@ -751,21 +778,94 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, digest[12], digest[13], digest[14], digest[15]); /* Encode it to base64 and send it. */ - l = Curl_base64_encode(data, reply, 0, &rplyb64); + result = Curl_base64_encode(data, reply, 0, &rplyb64, &len); + + if(!result) { + if(rplyb64) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); + + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(rplyb64); + } + + return result; +} + +#endif - if(!l) - result = CURLE_OUT_OF_MEMORY; +#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 = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - free(rplyb64); + result = smtp_auth_ntlm_type1_message(conn, &type1msg, &len); - if(!result) - state(conn, SMTP_AUTH); + 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. */ @@ -791,20 +891,49 @@ static CURLcode smtp_state_auth_resp(struct connectdata *conn, /* start the DO phase */ static CURLcode smtp_mail(struct connectdata *conn) { + char *from = NULL; + char *size = NULL; CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + /* calculate the FROM parameter */ + if(!data->set.str[STRING_MAIL_FROM]) + /* null reverse-path, RFC-2821, sect. 3.7 */ + from = strdup("<>"); + else if(data->set.str[STRING_MAIL_FROM][0] == '<') + from = aprintf("%s", data->set.str[STRING_MAIL_FROM]); + else + from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]); + + if(!from) + return CURLE_OUT_OF_MEMORY; + + /* calculate the optional SIZE parameter */ + if(conn->data->set.infilesize > 0) { + size = aprintf("%" FORMAT_OFF_T, data->set.infilesize); + + if(!size) { + Curl_safefree(from); + + return CURLE_OUT_OF_MEMORY; + } + } + /* send MAIL FROM */ - if(data->set.str[STRING_MAIL_FROM][0] == '<') - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s", - data->set.str[STRING_MAIL_FROM]); + if(!size) + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s", from); else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:<%s>", - data->set.str[STRING_MAIL_FROM]); + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s SIZE=%s", + from, size); + + Curl_safefree(size); + Curl_safefree(from); + if(result) return result; state(conn, SMTP_MAIL); + return result; } @@ -824,6 +953,7 @@ static CURLcode smtp_rcpt_to(struct connectdata *conn) if(!result) state(conn, SMTP_RCPT); } + return result; } @@ -884,6 +1014,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, state(conn, SMTP_DATA); } + return result; } @@ -924,6 +1055,7 @@ static CURLcode smtp_state_postdata_resp(struct connectdata *conn, result = CURLE_RECV_ERROR; state(conn, SMTP_STOP); + return result; } @@ -931,7 +1063,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) { CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; int smtpcode; struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; @@ -993,6 +1125,17 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) break; #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: result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); break; @@ -1021,6 +1164,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) break; } } + return result; } @@ -1036,7 +1180,7 @@ static CURLcode smtp_multi_statemach(struct connectdata *conn, else result = Curl_pp_multi_statemach(&smtpc->pp); - *done = (bool)(smtpc->state == SMTP_STOP); + *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; return result; } @@ -1087,20 +1231,20 @@ static CURLcode smtp_init(struct connectdata *conn) * smtp_connect() should do everything that is to be considered a part of * the connection phase. * - * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE is not. When called as - * a part of the easy interface, it will always be TRUE. + * The variable pointed to by 'done' will be TRUE if the protocol-layer + * connect phase is done when this function returns, or FALSE if not. When + * called as a part of the easy interface, it will always be TRUE. */ static CURLcode smtp_connect(struct connectdata *conn, bool *done) /* see description above */ { CURLcode result; struct smtp_conn *smtpc = &conn->proto.smtpc; - struct SessionHandle *data=conn->data; - struct pingpong *pp=&smtpc->pp; + struct SessionHandle *data = conn->data; + struct pingpong *pp = &smtpc->pp; const char *path = conn->data->state.path; int len; - char localhost[1024 + 1]; + char localhost[HOSTNAME_MAX + 1]; *done = FALSE; /* default to not done yet */ @@ -1204,7 +1348,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, { struct SessionHandle *data = conn->data; struct FTP *smtp = data->state.proto.smtp; - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; ssize_t bytes_written; (void)premature; @@ -1234,7 +1378,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, if(status == CURLE_OK) { struct smtp_conn *smtpc = &conn->proto.smtpc; - struct pingpong *pp= &smtpc->pp; + struct pingpong *pp = &smtpc->pp; pp->response = Curl_tvnow(); /* timeout relative now */ state(conn, SMTP_POSTDATA); @@ -1268,7 +1412,7 @@ CURLcode smtp_perform(struct connectdata *conn, bool *dophase_done) { /* this is SMTP and no proxy */ - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -1292,7 +1436,7 @@ CURLcode smtp_perform(struct connectdata *conn, result = smtp_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -1361,9 +1505,10 @@ static CURLcode smtp_quit(struct connectdata *conn) * Disconnect from an SMTP server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ -static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) +static CURLcode smtp_disconnect(struct connectdata *conn, + bool dead_connection) { - struct smtp_conn *smtpc= &conn->proto.smtpc; + struct smtp_conn *smtpc = &conn->proto.smtpc; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the @@ -1377,6 +1522,13 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) 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 */ Curl_safefree(smtpc->domain); smtpc->domain = NULL; @@ -1389,7 +1541,7 @@ static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected) { struct FTP *smtp = conn->data->state.proto.smtp; - struct smtp_conn *smtpc= &conn->proto.smtpc; + struct smtp_conn *smtpc = &conn->proto.smtpc; (void)connected; if(smtp->transfer != FTPTRANSFER_BODY) @@ -1404,7 +1556,7 @@ static CURLcode smtp_dophase_done(struct connectdata *conn, /* called from multi.c while DOing */ static CURLcode smtp_doing(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { CURLcode result; result = smtp_multi_statemach(conn, dophase_done); @@ -1414,6 +1566,7 @@ static CURLcode smtp_doing(struct connectdata *conn, DEBUGF(infof(conn->data, "DO phase is complete\n")); } + return result; } @@ -1428,10 +1581,10 @@ static CURLcode smtp_doing(struct connectdata *conn, */ static CURLcode smtp_regular_transfer(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { - CURLcode result=CURLE_OK; - bool connected=FALSE; + CURLcode result = CURLE_OK; + bool connected = FALSE; struct SessionHandle *data = conn->data; data->req.size = -1; /* make sure this is unknown at this point */ @@ -1458,7 +1611,7 @@ CURLcode smtp_regular_transfer(struct connectdata *conn, return result; } -static CURLcode smtp_setup_connection(struct connectdata * conn) +static CURLcode smtp_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; @@ -1505,42 +1658,43 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) struct SessionHandle *data = conn->data; if(data->state.scratch == NULL) - data->state.scratch = malloc(2*BUFSIZE); + data->state.scratch = malloc(2 * BUFSIZE); if(data->state.scratch == NULL) { failf (data, "Failed to alloc scratch buffer!"); return CURLE_OUT_OF_MEMORY; } /* 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++, si++) { - ssize_t left = nread - i; - - if(left>= (ssize_t)(SMTP_EOB_LEN-smtpc->eob)) { - if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], - SMTP_EOB_LEN-smtpc->eob)) { - /* It matched, copy the replacement data to the target buffer - instead. Note that the replacement does not contain the - trailing CRLF but we instead continue to match on that one - to deal with repeated sequences. Like CRLF.CRLF.CRLF etc - */ - memcpy(&data->state.scratch[si], SMTP_EOB_REPL, - SMTP_EOB_REPL_LEN); - si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments - it */ - i+=SMTP_EOB_LEN-smtpc->eob-1-2; - smtpc->eob = 0; /* start over */ - continue; - } + for(i = 0, si = 0; i < nread; i++) { + + if(SMTP_EOB[smtpc->eob] == data->req.upload_fromhere[i]) + smtpc->eob++; + else if(smtpc->eob) { + /* previously a substring matched, output that first */ + memcpy(&data->state.scratch[si], SMTP_EOB, smtpc->eob); + si += smtpc->eob; + + /* then compare the first byte */ + if(SMTP_EOB[0] == data->req.upload_fromhere[i]) + smtpc->eob = 1; + else + smtpc->eob = 0; } - else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], - left)) { - /* the last piece of the data matches the EOB so we can't send that - until we know the rest of it */ - smtpc->eob += left; - break; + + if(SMTP_EOB_LEN == smtpc->eob) { + /* It matched, copy the replacement data to the target buffer + instead. Note that the replacement does not contain the + trailing CRLF but we instead continue to match on that one + to deal with repeated sequences. Like CRLF.CRLF.CRLF etc + */ + memcpy(&data->state.scratch[si], SMTP_EOB_REPL, + SMTP_EOB_REPL_LEN); + si += SMTP_EOB_REPL_LEN; + smtpc->eob = 2; /* start over at two bytes */ } + else if(!smtpc->eob) + data->state.scratch[si++] = data->req.upload_fromhere[i]; - data->state.scratch[si] = data->req.upload_fromhere[i]; } /* for() */ if(si != nread) { @@ -1553,6 +1707,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) /* set the new amount too */ data->req.upload_present = nread; } + return CURLE_OK; } |