Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 98 additions & 33 deletions src/wp-includes/PHPMailer/PHPMailer.php
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ class PHPMailer
*
* @var string
*/
const VERSION = '7.0.0';
const VERSION = '7.0.2';

/**
* Error severity: message only, continue processing.
Expand Down Expand Up @@ -876,6 +876,7 @@ public function __destruct()
private function mailPassthru($to, $subject, $body, $header, $params)
{
//Check overloading of mail function to avoid double-encoding
// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecatedRemoved
if ((int)ini_get('mbstring.func_overload') & 1) {
$subject = $this->secureHeader($subject);
} else {
Expand Down Expand Up @@ -987,6 +988,54 @@ public function isMail()
$this->Mailer = 'mail';
}

/**
* Extract sendmail path and parse to deal with known parameters.
*
* @param string $sendmailPath The sendmail path as set in php.ini
*
* @return string The sendmail path without the known parameters
*/
private function parseSendmailPath($sendmailPath)
{
$sendmailPath = trim((string)$sendmailPath);
if ($sendmailPath === '') {
return $sendmailPath;
}

$parts = preg_split('/\s+/', $sendmailPath);
if (empty($parts)) {
return $sendmailPath;
}

$command = array_shift($parts);
$remainder = [];

// Parse only -t, -i, -oi and -f parameters.
for ($i = 0; $i < count($parts); ++$i) {
$part = $parts[$i];
if (preg_match('/^-(i|oi|t)$/', $part, $matches)) {
continue;
}
if (preg_match('/^-f(.*)$/', $part, $matches)) {
$address = $matches[1];
if ($address === '' && isset($parts[$i + 1]) && strpos($parts[$i + 1], '-') !== 0) {
$address = $parts[++$i];
}
$this->Sender = $address;
continue;
}

$remainder[] = $part;
}

// The params that are not parsed are added back to the command.
if (!empty($remainder)) {
$command .= ' ' . implode(' ', $remainder);
}

return $command;
}

/**
* Send messages using $Sendmail.
*/
Expand All @@ -995,10 +1044,9 @@ public function isSendmail()
$ini_sendmail_path = ini_get('sendmail_path');

if (false === stripos($ini_sendmail_path, 'sendmail')) {
$this->Sendmail = '/usr/sbin/sendmail';
} else {
$this->Sendmail = $ini_sendmail_path;
$ini_sendmail_path = '/usr/sbin/sendmail';
}
$this->Sendmail = $this->parseSendmailPath($ini_sendmail_path);
$this->Mailer = 'sendmail';
}

Expand All @@ -1010,10 +1058,9 @@ public function isQmail()
$ini_sendmail_path = ini_get('sendmail_path');

if (false === stripos($ini_sendmail_path, 'qmail')) {
$this->Sendmail = '/var/qmail/bin/qmail-inject';
} else {
$this->Sendmail = $ini_sendmail_path;
$ini_sendmail_path = '/var/qmail/bin/qmail-inject';
}
$this->Sendmail = $this->parseSendmailPath($ini_sendmail_path);
$this->Mailer = 'qmail';
}

Expand Down Expand Up @@ -1242,21 +1289,25 @@ protected function addAnAddress($kind, $address, $name = '')
* @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
*
* @param string $addrstr The address list string
* @param null $useimap Deprecated argument since 6.11.0.
* @param null $useimap Unused. Argument has been deprecated in PHPMailer 6.11.0.
* Previously this argument determined whether to use
* the IMAP extension to parse the list and accepted a boolean value.
* @param string $charset The charset to use when decoding the address list string.
*
* @return array
*/
public static function parseAddresses($addrstr, $useimap = null, $charset = self::CHARSET_ISO88591)
{
if ($useimap !== null) {
trigger_error(self::lang('deprecated_argument'), E_USER_DEPRECATED);
trigger_error(self::lang('deprecated_argument') . '$useimap', E_USER_DEPRECATED);
}
$addresses = [];
if (function_exists('imap_rfc822_parse_adrlist')) {
//Use this built-in parser if it's available
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.imap_rfc822_parse_adrlistRemoved -- wrapped in function_exists()
$list = imap_rfc822_parse_adrlist($addrstr, '');
// Clear any potential IMAP errors to get rid of notices being thrown at end of script.
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.imap_errorsRemoved -- wrapped in function_exists()
imap_errors();
foreach ($list as $address) {
if (
Expand Down Expand Up @@ -1583,9 +1634,11 @@ public function punyencodeAddress($address)
);
} elseif (defined('INTL_IDNA_VARIANT_2003')) {
//Fall back to this old, deprecated/removed encoding
// phpcs:ignore PHPCompatibility.Constants.RemovedConstants.intl_idna_variant_2003DeprecatedRemoved
$punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_2003);
} else {
//Fall back to a default we don't know about
// phpcs:ignore PHPCompatibility.ParameterValues.NewIDNVariantDefault.NotSet
$punycode = idn_to_ascii($domain, $errorcode);
}
if (false !== $punycode) {
Expand Down Expand Up @@ -1853,25 +1906,27 @@ protected function sendmailSend($header, $body)
//PHP config has a sender address we can use
$this->Sender = ini_get('sendmail_from');
}
//CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.

$sendmailArgs = [];

// CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
// Also don't add the -f automatically unless it has been set either via Sender
// or sendmail_path. Otherwise it can introduce new problems.
// @see http://github.com/PHPMailer/PHPMailer/issues/2298
if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
if ($this->Mailer === 'qmail') {
$sendmailFmt = '%s -f%s';
} else {
$sendmailFmt = '%s -oi -f%s -t';
}
} elseif ($this->Mailer === 'qmail') {
$sendmailFmt = '%s';
} else {
//Allow sendmail to choose a default envelope sender. It may
//seem preferable to force it to use the From header as with
//SMTP, but that introduces new problems (see
//<https://github.com/PHPMailer/PHPMailer/issues/2298>), and
//it has historically worked this way.
$sendmailFmt = '%s -oi -t';
$sendmailArgs[] = '-f' . $this->Sender;
}

// Qmail doesn't accept all the sendmail parameters
// @see https://github.com/PHPMailer/PHPMailer/issues/3189
if ($this->Mailer !== 'qmail') {
$sendmailArgs[] = '-i';
$sendmailArgs[] = '-t';
}

$sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
$resultArgs = (empty($sendmailArgs) ? '' : ' ' . implode(' ', $sendmailArgs));

$sendmail = trim(escapeshellcmd($this->Sendmail) . $resultArgs);
$this->edebug('Sendmail path: ' . $this->Sendmail);
$this->edebug('Sendmail command: ' . $sendmail);
$this->edebug('Envelope sender: ' . $this->Sender);
Expand Down Expand Up @@ -2055,7 +2110,8 @@ protected function mailSend($header, $body)
$this->Sender = ini_get('sendmail_from');
}
if (!empty($this->Sender) && static::validateAddress($this->Sender)) {
if (self::isShellSafe($this->Sender)) {
$phpmailer_path = ini_get('sendmail_path');
if (self::isShellSafe($this->Sender) && strpos($phpmailer_path, ' -f') === false) {
$params = sprintf('-f%s', $this->Sender);
}
$old_from = ini_get('sendmail_from');
Expand Down Expand Up @@ -2482,7 +2538,7 @@ public static function setLanguage($langcode = 'en', $lang_path = '')
'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses',
'imap_recommended' => 'Using simplified address parser is not recommended. ' .
'Install the PHP IMAP extension for full RFC822 parsing.',
'deprecated_argument' => 'Argument $useimap is deprecated',
'deprecated_argument' => 'Deprecated Argument: ',
];
if (empty($lang_path)) {
//Calculate an absolute path so it can work if CWD is not here
Expand Down Expand Up @@ -2956,6 +3012,7 @@ protected function generateId()
$bytes = '';
if (function_exists('random_bytes')) {
try {
// phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.random_bytesFound -- Wrapped in function_exists.
$bytes = random_bytes($len);
} catch (\Exception $e) {
//Do nothing
Expand Down Expand Up @@ -4590,10 +4647,10 @@ public function getCustomHeaders()
* Converts data-uri images into embedded attachments.
* If you don't want to apply these transformations to your HTML, just set Body and AltBody directly.
*
* @param string $message HTML message string
* @param string $basedir Absolute path to a base directory to prepend to relative paths to images
* @param bool|callable $advanced Whether to use the internal HTML to text converter
* or your own custom converter
* @param string $message HTML message string
* @param string $basedir Absolute path to a base directory to prepend to relative paths to images
* @param bool|callable $advanced Whether to use the internal HTML to text converter
* or your own custom converter
* @return string The transformed message body
*
* @throws Exception
Expand All @@ -4602,6 +4659,12 @@ public function getCustomHeaders()
*/
public function msgHTML($message, $basedir = '', $advanced = false)
{
$cid_domain = 'phpmailer.0';
if (filter_var($this->From, FILTER_VALIDATE_EMAIL)) {
//prepend with a character to create valid RFC822 string in order to validate
$cid_domain = substr($this->From, strrpos($this->From, '@') + 1);
}

preg_match_all('/(?<!-)(src|background)=["\'](.*)["\']/Ui', $message, $images);
if (array_key_exists(2, $images)) {
if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) {
Expand All @@ -4623,7 +4686,7 @@ public function msgHTML($message, $basedir = '', $advanced = false)
}
//Hash the decoded data, not the URL, so that the same data-URI image used in multiple places
//will only be embedded once, even if it used a different encoding
$cid = substr(hash('sha256', $data), 0, 32) . '@phpmailer.0'; //RFC2392 S 2
$cid = substr(hash('sha256', $data), 0, 32) . '@' . $cid_domain; //RFC2392 S 2

if (!$this->cidExists($cid)) {
$this->addStringEmbeddedImage(
Expand Down Expand Up @@ -4657,7 +4720,7 @@ public function msgHTML($message, $basedir = '', $advanced = false)
$directory = '';
}
//RFC2392 S 2
$cid = substr(hash('sha256', $url), 0, 32) . '@phpmailer.0';
$cid = substr(hash('sha256', $url), 0, 32) . '@' . $cid_domain;
if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) {
$basedir .= '/';
}
Expand Down Expand Up @@ -5105,12 +5168,14 @@ public function DKIM_Sign($signHeader)
}
if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
if (\PHP_MAJOR_VERSION < 8) {
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.openssl_pkey_freeDeprecated
openssl_pkey_free($privKey);
}

return base64_encode($signature);
}
if (\PHP_MAJOR_VERSION < 8) {
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.openssl_pkey_freeDeprecated
openssl_pkey_free($privKey);
}

Expand Down
3 changes: 2 additions & 1 deletion src/wp-includes/PHPMailer/POP3.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ class POP3
* The POP3 PHPMailer Version number.
*
* @var string
* @deprecated This constant will be removed in PHPMailer 8.0. Use `PHPMailer::VERSION` instead.
*/
const VERSION = '7.0.0';
const VERSION = '7.0.2';

/**
* Default POP3 port number.
Expand Down
39 changes: 34 additions & 5 deletions src/wp-includes/PHPMailer/SMTP.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ class SMTP
* The PHPMailer SMTP version number.
*
* @var string
* @deprecated This constant will be removed in PHPMailer 8.0. Use `PHPMailer::VERSION` instead.
*/
const VERSION = '7.0.0';
const VERSION = '7.0.2';

/**
* SMTP line break constant.
Expand Down Expand Up @@ -494,7 +495,9 @@ public function startTLS()
//PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
//so add them back in manually if we can
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
// phpcs:ignore PHPCompatibility.Constants.NewConstants.stream_crypto_method_tlsv1_2_clientFound
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
// phpcs:ignore PHPCompatibility.Constants.NewConstants.stream_crypto_method_tlsv1_1_clientFound
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
}

Expand Down Expand Up @@ -633,7 +636,13 @@ public function authenticate(
if (null === $OAuth) {
return false;
}
$oauth = $OAuth->getOauth64();
try {
$oauth = $OAuth->getOauth64();
} catch (\Exception $e) {
// We catch all exceptions and convert them to PHPMailer exceptions to be able to
// handle them correctly later
throw new Exception("SMTP authentication error", 0, $e);
}
/*
* An SMTP command line can have a maximum length of 512 bytes, including the command name,
* so the base64-encoded OAUTH token has a maximum length of:
Expand Down Expand Up @@ -761,6 +770,25 @@ public function close()
}
}

private function iterateLines($s)
{
$start = 0;
$length = strlen($s);

for ($i = 0; $i < $length; $i++) {
$c = $s[$i];
if ($c === "\n" || $c === "\r") {
yield substr($s, $start, $i - $start);
if ($c === "\r" && $i + 1 < $length && $s[$i + 1] === "\n") {
$i++;
}
$start = $i + 1;
}
}

yield substr($s, $start);
}

/**
* Send an SMTP DATA command.
* Issues a data command and sends the msg_data to the server,
Expand Down Expand Up @@ -789,15 +817,16 @@ public function data($msg_data)
* NOTE: this does not count towards line-length limit.
*/

//Normalize line breaks before exploding
$lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data));
//Iterate over lines with normalized line breaks
$lines = $this->iterateLines($msg_data);

/* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
* of the first line (':' separated) does not contain a space then it _should_ be a header, and we will
* process all lines before a blank line as headers.
*/

$field = substr($lines[0], 0, strpos($lines[0], ':'));
$first_line = $lines->current();
$field = substr($first_line, 0, strpos($first_line, ':'));
$in_headers = false;
if (!empty($field) && strpos($field, ' ') === false) {
$in_headers = true;
Expand Down
Loading