summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2020-11-10 16:13:54 +0100
committerChristoph M. Becker <cmbecker69@gmx.de>2020-11-19 19:25:03 +0100
commit881e43a03c774bf8d31b5fe751bd493447174ad0 (patch)
treefe073f91c6319a176733cd711674dc8ed66452b5
parentc2b1182879bf2785245638945851c241b0859cbb (diff)
downloadphp-git-881e43a03c774bf8d31b5fe751bd493447174ad0.tar.gz
Fix #72964: White space not unfolded for CC/Bcc headers
`\r\n` does only terminate a header, if not followed by `\t` or ` `. We have to cater to that when determining the end position of the respective headers. Closes GH-6420.
-rw-r--r--NEWS1
-rw-r--r--ext/standard/tests/mail/bug72964.phpt73
-rw-r--r--win32/sendmail.c25
3 files changed, 99 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 1bb1c0a757..229c459bca 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ PHP NEWS
(cmb)
. Fixed bug #80345 (PHPIZE configuration has outdated PHP_RELEASE_VERSION).
(cmb)
+ . Fixed bug #72964 (White space not unfolded for CC/Bcc headers). (cmb)
26 Nov 2020, PHP 7.4.13
diff --git a/ext/standard/tests/mail/bug72964.phpt b/ext/standard/tests/mail/bug72964.phpt
new file mode 100644
index 0000000000..44048771d6
--- /dev/null
+++ b/ext/standard/tests/mail/bug72964.phpt
@@ -0,0 +1,73 @@
+--TEST--
+Bug #72964 (White space not unfolded for CC/Bcc headers)
+--SKIPIF--
+<?php
+if (PHP_OS_FAMILY !== 'Windows') die('skip Windows only test');
+if (getenv("SKIP_SLOW_TESTS")) die('skip slow test');
+require_once __DIR__ . '/mail_skipif.inc';
+?>
+--INI--
+SMTP=localhost
+smtp_port=25
+--FILE--
+<?php
+require_once __DIR__ . '/mail_include.inc';
+
+function find_and_delete_message($username, $subject) {
+ global $default_mailbox, $password;
+
+ $imap_stream = imap_open($default_mailbox, $username, $password);
+ if ($imap_stream === false) {
+ die("Cannot connect to IMAP server $server: " . imap_last_error() . "\n");
+ }
+
+ $found = false;
+ $repeat_count = 20; // we will repeat a max of 20 times
+ while (!$found && $repeat_count > 0) {
+ // sleep for a while to allow msg to be delivered
+ sleep(1);
+
+ $num_messages = imap_check($imap_stream)->Nmsgs;
+ for ($i = $num_messages; $i > 0; $i--) {
+ $info = imap_headerinfo($imap_stream, $i);
+ if ($info->subject === $subject) {
+ imap_delete($imap_stream, $i);
+ $found = true;
+ break;
+ }
+ }
+ $repeat_count--;
+ }
+
+ imap_close($imap_stream, CL_EXPUNGE);
+ return $found;
+}
+
+$to = "{$users[2]}@$domain";
+$subject = bin2hex(random_bytes(16));
+$message = 'hello';
+$headers = "From: webmaster@example.com\r\n"
+ . "Cc: {$users[0]}@$domain,\r\n\t{$users[1]}@$domain\r\n"
+ . "Bcc: {$users[2]}@$domain,\r\n {$users[3]}@$domain\r\n";
+
+$res = mail($to, $subject, $message, $headers);
+if ($res !== true) {
+ die("TEST FAILED : Unable to send test email\n");
+} else {
+ echo "Message sent OK\n";
+}
+
+foreach ($users as $user) {
+ if (!find_and_delete_message("$user@$domain", $subject)) {
+ echo "TEST FAILED: email not delivered\n";
+ } else {
+ echo "TEST PASSED: Message sent and deleted OK\n";
+ }
+}
+?>
+--EXPECT--
+Message sent OK
+TEST PASSED: Message sent and deleted OK
+TEST PASSED: Message sent and deleted OK
+TEST PASSED: Message sent and deleted OK
+TEST PASSED: Message sent and deleted OK
diff --git a/win32/sendmail.c b/win32/sendmail.c
index 9e31028d58..c82dc7b3c6 100644
--- a/win32/sendmail.c
+++ b/win32/sendmail.c
@@ -458,6 +458,16 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
if (NULL == (pos2 = strstr(pos1, "\r\n"))) {
tempMailTo = estrndup(pos1, strlen(pos1));
} else {
+ char *pos3;
+ while (pos2[2] == ' ' || pos2[2] == '\t') {
+ pos3 = strstr(pos2 + 2, "\r\n");
+ if (pos3 != NULL) {
+ pos2 = pos3;
+ } else {
+ pos2 += strlen(pos2);
+ break;
+ }
+ }
tempMailTo = estrndup(pos1, pos2 - pos1);
}
@@ -516,7 +526,22 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
header we know it was the last thing. */
pos2 = pos1;
} else {
+ char *pos3 = NULL;
+ while (pos2[2] == ' ' || pos2[2] == '\t') {
+ pos3 = strstr(pos2 + 2, "\r\n");
+ if (pos3 != NULL) {
+ pos2 = pos3;
+ } else {
+ pos2 += strlen(pos2);
+ break;
+ }
+ }
tempMailTo = estrndup(pos1, pos2 - pos1);
+ if (pos3 == NULL) {
+ /* Later, when we remove the Bcc: out of the
+ header we know it was the last thing. */
+ pos2 = pos1;
+ }
}
token = strtok(tempMailTo, ",");