mirror of
https://github.com/php/php-src.git
synced 2024-11-27 11:53:33 +08:00
Merge branch 'PHP-8.0'
* PHP-8.0: Fix #80751: Comma in recipient name breaks email delivery
This commit is contained in:
commit
87a5a0e2cb
93
ext/standard/tests/mail/bug80751.phpt
Normal file
93
ext/standard/tests/mail/bug80751.phpt
Normal file
@ -0,0 +1,93 @@
|
||||
--TEST--
|
||||
Bug #80751 (Comma in recipient name breaks email delivery)
|
||||
--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) {
|
||||
$header = imap_fetchheader($imap_stream, $i);
|
||||
echo "Return-Path header found: ";
|
||||
var_dump(strpos($header, 'Return-Path: joe@example.com') !== false);
|
||||
echo "To header found: ";
|
||||
var_dump(strpos($header, 'To: "<bob@example.com>" <info@mail.local>') !== false);
|
||||
echo "From header found: ";
|
||||
var_dump(strpos($header, 'From: "<bob@example.com>" <joe@example.com>') !== false);
|
||||
echo "Cc header found: ";
|
||||
var_dump(strpos($header, 'Cc: "Lastname, Firstname\\\\" <admin@mail.local>') !== false);
|
||||
imap_delete($imap_stream, $i);
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$repeat_count--;
|
||||
}
|
||||
|
||||
imap_close($imap_stream, CL_EXPUNGE);
|
||||
return $found;
|
||||
}
|
||||
|
||||
$to = "\"<bob@example.com>\" <{$users[1]}@$domain>";
|
||||
$subject = bin2hex(random_bytes(16));
|
||||
$message = 'hello';
|
||||
$headers = "From: \"<bob@example.com>\" <joe@example.com>\r\n"
|
||||
. "Cc: \"Lastname, Firstname\\\\\" <{$users[2]}@$domain>\r\n"
|
||||
. "Bcc: \"Firstname \\\"Ni,ck\\\" Lastname\" <{$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[1], $users[2], $users[3]] 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
|
||||
Return-Path header found: bool(true)
|
||||
To header found: bool(true)
|
||||
From header found: bool(true)
|
||||
Cc header found: bool(true)
|
||||
TEST PASSED: Message sent and deleted OK
|
||||
Return-Path header found: bool(true)
|
||||
To header found: bool(true)
|
||||
From header found: bool(true)
|
||||
Cc header found: bool(true)
|
||||
TEST PASSED: Message sent and deleted OK
|
||||
Return-Path header found: bool(true)
|
||||
To header found: bool(true)
|
||||
From header found: bool(true)
|
||||
Cc header found: bool(true)
|
||||
TEST PASSED: Message sent and deleted OK
|
102
win32/sendmail.c
102
win32/sendmail.c
@ -333,6 +333,37 @@ PHPAPI char *GetSMErrorText(int index)
|
||||
}
|
||||
}
|
||||
|
||||
/* strtok_r like, but recognizes quoted-strings */
|
||||
static char *find_address(char *list, char **state)
|
||||
{
|
||||
zend_bool in_quotes = 0;
|
||||
char *p = list;
|
||||
|
||||
if (list == NULL) {
|
||||
if (*state == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
p = list = *state;
|
||||
}
|
||||
*state = NULL;
|
||||
while ((p = strpbrk(p, ",\"\\")) != NULL) {
|
||||
if (*p == '\\' && in_quotes) {
|
||||
if (p[1] == '\0') {
|
||||
/* invalid address; let SMTP server deal with it */
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
} else if (*p == '"') {
|
||||
in_quotes = !in_quotes;
|
||||
} else if (*p == ',' && !in_quotes) {
|
||||
*p = '\0';
|
||||
*state = p + 1;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
// Name: SendText
|
||||
@ -357,7 +388,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
{
|
||||
int res;
|
||||
char *p;
|
||||
char *tempMailTo, *token;
|
||||
char *tempMailTo, *token, *token_state;
|
||||
const char *pos1, *pos2;
|
||||
char *server_response = NULL;
|
||||
char *stripped_header = NULL;
|
||||
@ -411,7 +442,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
|
||||
tempMailTo = estrdup(mailTo);
|
||||
/* Send mail to all rcpt's */
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
@ -425,14 +456,14 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL, &token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
|
||||
if (mailCc && *mailCc) {
|
||||
tempMailTo = estrdup(mailCc);
|
||||
/* Send mail to all rcpt's */
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
@ -446,7 +477,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL, &token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
}
|
||||
@ -472,7 +503,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
tempMailTo = estrndup(pos1, pos2 - pos1);
|
||||
}
|
||||
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
@ -486,7 +517,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL,&token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
}
|
||||
@ -497,7 +528,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
if (mailBcc && *mailBcc) {
|
||||
tempMailTo = estrdup(mailBcc);
|
||||
/* Send mail to all rcpt's */
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
@ -511,7 +542,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL, &token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
}
|
||||
@ -545,7 +576,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
}
|
||||
}
|
||||
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
@ -559,7 +590,7 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char *
|
||||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL, &token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
|
||||
@ -979,6 +1010,46 @@ static unsigned long GetAddr(LPSTR szHost)
|
||||
return (lAddr);
|
||||
} /* end GetAddr() */
|
||||
|
||||
/* returns the contents of an angle-addr (caller needs to efree) or NULL */
|
||||
static char *get_angle_addr(char *address)
|
||||
{
|
||||
zend_bool in_quotes = 0;
|
||||
char *p1 = address, *p2;
|
||||
|
||||
while ((p1 = strpbrk(p1, "<\"\\")) != NULL) {
|
||||
if (*p1 == '\\' && in_quotes) {
|
||||
if (p1[1] == '\0') {
|
||||
/* invalid address; let SMTP server deal with it */
|
||||
return NULL;
|
||||
}
|
||||
p1++;
|
||||
} else if (*p1 == '"') {
|
||||
in_quotes = !in_quotes;
|
||||
} else if (*p1 == '<' && !in_quotes) {
|
||||
break;
|
||||
}
|
||||
p1++;
|
||||
}
|
||||
if (p1 == NULL) return NULL;
|
||||
p2 = ++p1;
|
||||
while ((p2 = strpbrk(p2, ">\"\\")) != NULL) {
|
||||
if (*p2 == '\\' && in_quotes) {
|
||||
if (p2[1] == '\0') {
|
||||
/* invalid address; let SMTP server deal with it */
|
||||
return NULL;
|
||||
}
|
||||
p2++;
|
||||
} else if (*p2 == '"') {
|
||||
in_quotes = !in_quotes;
|
||||
} else if (*p2 == '>' && !in_quotes) {
|
||||
break;
|
||||
}
|
||||
p2++;
|
||||
}
|
||||
if (p2 == NULL) return NULL;
|
||||
|
||||
return estrndup(p1, p2 - p1);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
// Name: int FormatEmailAddress
|
||||
@ -994,13 +1065,12 @@ static unsigned long GetAddr(LPSTR szHost)
|
||||
// History:
|
||||
//********************************************************************/
|
||||
static int FormatEmailAddress(char* Buf, char* EmailAddress, char* FormatString) {
|
||||
char *tmpAddress1, *tmpAddress2;
|
||||
char *tmpAddress;
|
||||
int result;
|
||||
|
||||
if( (tmpAddress1 = strchr(EmailAddress, '<')) && (tmpAddress2 = strchr(tmpAddress1, '>')) ) {
|
||||
*tmpAddress2 = 0; // terminate the string temporarily.
|
||||
result = snprintf(Buf, MAIL_BUFFER_SIZE, FormatString , tmpAddress1+1);
|
||||
*tmpAddress2 = '>'; // put it back the way it was.
|
||||
if ((tmpAddress = get_angle_addr(EmailAddress)) != NULL) {
|
||||
result = snprintf(Buf, MAIL_BUFFER_SIZE, FormatString, tmpAddress);
|
||||
efree(tmpAddress);
|
||||
return result;
|
||||
}
|
||||
return snprintf(Buf, MAIL_BUFFER_SIZE , FormatString , EmailAddress );
|
||||
|
Loading…
Reference in New Issue
Block a user