1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-22 08:08:50 -05:00

(SMTP) support DATA better in the server and make sure to "escape" CRLF.CRLF

sequences in uploaded data. The test server doesn't "decode" escaped dot-lines
but instead test cases must be written to take them into account. Added test
case 803 to verify dot-escaping.
This commit is contained in:
Daniel Stenberg 2009-12-30 21:52:27 +00:00
parent d7cd761047
commit 5e6ffe353a
7 changed files with 206 additions and 5 deletions

View File

@ -639,6 +639,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
struct FTP *smtp = data->state.proto.smtp; struct FTP *smtp = data->state.proto.smtp;
CURLcode result=CURLE_OK; CURLcode result=CURLE_OK;
ssize_t bytes_written;
(void)premature; (void)premature;
if(!smtp) if(!smtp)
@ -653,6 +654,15 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
conn->bits.close = TRUE; /* marked for closure */ conn->bits.close = TRUE; /* marked for closure */
result = status; /* use the already set error code */ result = status; /* use the already set error code */
} }
else
/* TODO: make this work even when the socket is EWOULDBLOCK in this call! */
/* write to socket (send away data) */
result = Curl_write(conn,
conn->writesockfd, /* socket to send to */
SMTP_EOB, /* buffer pointer */
SMTP_EOB_LEN, /* buffer size */
&bytes_written); /* actually sent away */
/* clear these for next connection */ /* clear these for next connection */
smtp->transfer = FTPTRANSFER_BODY; smtp->transfer = FTPTRANSFER_BODY;

View File

@ -58,4 +58,8 @@ extern const struct Curl_handler Curl_handler_smtps;
#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a" #define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a"
#define SMTP_EOB_LEN 5 #define SMTP_EOB_LEN 5
/* if found in data, replace it with this string instead */
#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
#define SMTP_EOB_REPL_LEN 4
#endif /* __SMTP_H */ #endif /* __SMTP_H */

View File

@ -784,6 +784,68 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
/* store number of bytes available for upload */ /* store number of bytes available for upload */
data->req.upload_present = nread; data->req.upload_present = nread;
#ifndef CURL_DISABLE_SMTP
if(conn->protocol & PROT_SMTP) {
/* When sending SMTP payload, we must detect CRLF.CRLF sequences in
* the data and make sure it is sent as CRLF..CRLF instead, as
* otherwise it will wrongly be detected as end of data by the server.
*/
struct smtp_conn *smtpc = &conn->proto.smtpc;
if(data->state.scratch == NULL)
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++) {
int left = nread - i;
if(left>= (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;
}
}
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;
}
data->state.scratch[si] = data->req.upload_fromhere[i];
} /* for() */
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;
/* set the new amount too */
data->req.upload_present = nread;
}
}
else
#endif /* CURL_DISABLE_SMTP */
/* convert LF to CRLF if so asked */ /* convert LF to CRLF if so asked */
if((!sending_http_headers) && if((!sending_http_headers) &&
#ifdef CURL_DO_LINEEND_CONV #ifdef CURL_DO_LINEEND_CONV
@ -837,10 +899,10 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
/* write to socket (send away data) */ /* write to socket (send away data) */
result = Curl_write(conn, result = Curl_write(conn,
conn->writesockfd, /* socket to send to */ conn->writesockfd, /* socket to send to */
data->req.upload_fromhere, /* buffer pointer */ data->req.upload_fromhere, /* buffer pointer */
data->req.upload_present, /* buffer size */ data->req.upload_present, /* buffer size */
&bytes_written); /* actually send away */ &bytes_written); /* actually sent */
if(result) if(result)
return result; return result;

View File

@ -63,7 +63,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
test1089 test1090 test1091 test1092 test1093 test1094 test1095 test1096 \ test1089 test1090 test1091 test1092 test1093 test1094 test1095 test1096 \
test1097 test560 test561 test1098 test1099 test562 test563 test1100 \ test1097 test560 test561 test1098 test1099 test562 test563 test1100 \
test564 test1101 test1102 test1103 test1104 test299 test310 test311 \ test564 test1101 test1102 test1103 test1104 test299 test310 test311 \
test312 test1105 test565 test800 test1106 test801 test566 test802 test312 test1105 test565 test800 test1106 test801 test566 test802 test803
filecheck: filecheck:
@mkdir test-place; \ @mkdir test-place; \

View File

@ -38,11 +38,15 @@ EHLO user
MAIL FROM:802@from MAIL FROM:802@from
RCPT TO:802@foo RCPT TO:802@foo
DATA DATA
QUIT
</protocol>
<upload>
From: different From: different
To: another To: another
body body
QUIT
</protocol> .
</upload>
</verify> </verify>
</testcase> </testcase>

64
tests/data/test803 Normal file
View File

@ -0,0 +1,64 @@
<testcase>
<info>
<keywords>
SMTP
</keywords>
</info>
#
# Server-side
<reply>
</reply>
#
# Client-side
<client>
<server>
smtp
</server>
<name>
SMTP with CRLF-dot-CRLF in data
</name>
<stdin>
From: different
To: another
.
.
.
body
</stdin>
<command>
smtp://%HOSTIP:%SMTPPORT -u user:secret --mail-rcpt 803@foo --mail-from 803@from -T -
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<protocol>
EHLO user
MAIL FROM:803@from
RCPT TO:803@foo
DATA
QUIT
</protocol>
<upload>
From: different
To: another
..
..
..
body
.
</upload>
</verify>
</testcase>

View File

@ -473,12 +473,69 @@ sub DATA_smtp {
if($testno eq "verifiedserver") { if($testno eq "verifiedserver") {
sendcontrol "554 WE ROOLZ: $$\r\n"; sendcontrol "554 WE ROOLZ: $$\r\n";
return 0; # don't wait for data now
} }
else { else {
$testno =~ s/^([0-9]*).*/$1/;
sendcontrol "354 Show me the mail\r\n"; sendcontrol "354 Show me the mail\r\n";
} }
logmsg "===> rcpt $testno was $smtp_rcpt\n"; logmsg "===> rcpt $testno was $smtp_rcpt\n";
my $filename = "log/upload.$testno";
logmsg "Store test number $testno in $filename\n";
open(FILE, ">$filename") ||
return 0; # failed to open output
my $line;
my $ulsize=0;
my $disc=0;
my $raw;
while (5 == (sysread \*SFREAD, $line, 5)) {
if($line eq "DATA\n") {
my $i;
my $eob;
sysread \*SFREAD, $i, 5;
my $size = 0;
if($i =~ /^([0-9a-fA-F]{4})\n/) {
$size = hex($1);
}
sysread \*SFREAD, $line, $size;
$ulsize += $size;
print FILE $line if(!$nosave);
$raw .= $line;
if($raw =~ /\x0d\x0a\x2e\x0d\x0a\z/) {
# end of data marker!
$eob = 1;
}
logmsg "> Appending $size bytes to file\n";
if($eob) {
logmsg "Found SMTP EOB marker\n";
last;
}
}
elsif($line eq "DISC\n") {
# disconnect!
$disc=1;
last;
}
else {
logmsg "No support for: $line";
last;
}
}
if($nosave) {
print FILE "$ulsize bytes would've been stored here\n";
}
close(FILE);
logmsg "received $ulsize bytes upload\n";
} }
sub RCPT_smtp { sub RCPT_smtp {