Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 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
7 changes: 3 additions & 4 deletions ext/mbstring/mbstring.c
Original file line number Diff line number Diff line change
Expand Up @@ -4633,9 +4633,8 @@ PHP_FUNCTION(mb_send_mail)

unsigned int num_errors = 0;
zend_string *tmpstr = mb_fast_convert((unsigned char*)message, message_len, msg_enc, tran_cs, '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR, &num_errors);
zend_string *conv = mb_fast_convert((unsigned char*)ZSTR_VAL(tmpstr), ZSTR_LEN(tmpstr), &mbfl_encoding_8bit, body_enc, '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR, &num_errors);
zend_string *converted_message = mb_fast_convert((unsigned char*)ZSTR_VAL(tmpstr), ZSTR_LEN(tmpstr), &mbfl_encoding_8bit, body_enc, '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR, &num_errors);
zend_string_free(tmpstr);
message = ZSTR_VAL(conv);

/* other headers */
#define PHP_MBSTR_MAIL_MIME_HEADER1 "MIME-Version: 1.0"
Expand Down Expand Up @@ -4703,7 +4702,7 @@ PHP_FUNCTION(mb_send_mail)
extra_cmd = php_escape_shell_cmd(extra_cmd);
}

RETVAL_BOOL(php_mail(to_r, ZSTR_VAL(subject), message, ZSTR_VAL(str_headers), extra_cmd));
RETVAL_BOOL(php_mail(to_r, ZSTR_VAL(subject), converted_message, str_headers, extra_cmd));

if (extra_cmd) {
zend_string_release_ex(extra_cmd, 0);
Expand All @@ -4712,7 +4711,7 @@ PHP_FUNCTION(mb_send_mail)
efree(to_r);
}
zend_string_release(subject);
zend_string_free(conv);
zend_string_free(converted_message);
zend_hash_destroy(&ht_headers);
if (str_headers) {
zend_string_release_ex(str_headers, 0);
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ PHPAPI zend_result _php_error_log(int opt_err, const zend_string *message, const
switch (opt_err)
{
case 1: /*send an email */
if (!php_mail(ZSTR_VAL(opt), "PHP error_log message", ZSTR_VAL(message), ZSTR_VAL(headers), NULL)) {
if (!php_mail(ZSTR_VAL(opt), "PHP error_log message", message, headers, NULL)) {
return FAILURE;
}
break;
Expand Down
79 changes: 43 additions & 36 deletions ext/standard/mail.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,19 +265,20 @@ PHPAPI zend_string *php_mail_build_headers(const HashTable *headers)
/* {{{ Send an email message */
PHP_FUNCTION(mail)
{
char *to=NULL, *message=NULL;
char *to=NULL;
char *subject=NULL;
zend_string *message;
zend_string *extra_cmd=NULL;
zend_string *headers_str = NULL;
HashTable *headers_ht = NULL;
size_t to_len, message_len;
size_t to_len;
size_t subject_len, i;
char *to_r, *subject_r;

ZEND_PARSE_PARAMETERS_START(3, 5)
Z_PARAM_PATH(to, to_len)
Z_PARAM_PATH(subject, subject_len)
Z_PARAM_PATH(message, message_len)
Z_PARAM_PATH_STR(message)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_STR(headers_ht, headers_str)
Z_PARAM_PATH_STR(extra_cmd)
Expand Down Expand Up @@ -343,7 +344,7 @@ PHP_FUNCTION(mail)
extra_cmd = php_escape_shell_cmd(extra_cmd);
}

if (php_mail(to_r, subject_r, message, headers_str && ZSTR_LEN(headers_str) ? ZSTR_VAL(headers_str) : NULL, extra_cmd)) {
if (php_mail(to_r, subject_r, message, headers_str, extra_cmd)) {
RETVAL_TRUE;
} else {
RETVAL_FALSE;
Expand Down Expand Up @@ -396,31 +397,33 @@ static void php_mail_log_to_file(const zend_string *filename, const char *messag
}


static int php_mail_detect_multiple_crlf(const char *hdr) {
static bool php_mail_detect_multiple_crlf(const zend_string *headers) {
/* This function detects multiple/malformed multiple newlines. */

if (!hdr || !strlen(hdr)) {
return 0;
if (!headers || !ZSTR_LEN(headers)) {
return false;
}

const char *end = ZSTR_VAL(headers) + ZSTR_LEN(headers);
const char *hdr = ZSTR_VAL(headers);
/* Should not have any newlines at the beginning. */
/* RFC 2822 2.2. Header Fields */
if (*hdr < 33 || *hdr > 126 || *hdr == ':') {
return 1;
return true;
}

while(*hdr) {
while (hdr < end) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the implications are of allowing NULs now. I suppose that won't work properly anyway?

if (*hdr == '\r') {
if (*(hdr+1) == '\0' || *(hdr+1) == '\r' || (*(hdr+1) == '\n' && (*(hdr+2) == '\0' || *(hdr+2) == '\n' || *(hdr+2) == '\r'))) {
/* Malformed or multiple newlines. */
return 1;
return true;
} else {
hdr += 2;
}
} else if (*hdr == '\n') {
if (*(hdr+1) == '\0' || *(hdr+1) == '\r' || *(hdr+1) == '\n') {
/* Malformed or multiple newlines. */
return 1;
return true;
} else {
hdr += 2;
}
Expand All @@ -429,35 +432,35 @@ static int php_mail_detect_multiple_crlf(const char *hdr) {
}
}

return 0;
return false;
}


/* {{{ php_mail */
PHPAPI bool php_mail(const char *to, const char *subject, const char *message, const char *headers, const zend_string *extra_cmd)
PHPAPI bool php_mail(const char *to, const char *subject, const zend_string *message, const zend_string *headers, const zend_string *extra_cmd)
{
FILE *sendmail;
char *sendmail_path = INI_STR("sendmail_path");
char *sendmail_cmd = NULL;
const zend_string *mail_log = zend_ini_str(ZEND_STRL("mail.log"), false);
const char *hdr = headers;
char *ahdr = NULL;
#if PHP_SIGCHILD
void (*sig_handler)(int) = NULL;
#endif

#define MAIL_RET(val) \
if (ahdr != NULL) { \
efree(ahdr); \
} \
return val; \
if (headers_with_x_php_header != NULL) { \
zend_string_release_ex(headers_with_x_php_header, false); \
} \
return val; \

if (mail_log && ZSTR_LEN(mail_log)) {
char *logline;
const char *hdr = headers ? ZSTR_VAL(headers) : "";

spprintf(&logline, 0, "mail() on [%s:%d]: To: %s -- Headers: %s -- Subject: %s", zend_get_executed_filename(), zend_get_executed_lineno(), to, hdr ? hdr : "", subject);
spprintf(&logline, 0, "mail() on [%s:%d]: To: %s -- Headers: %s -- Subject: %s",
zend_get_executed_filename(), zend_get_executed_lineno(), to, hdr, subject);

if (hdr) {
if (headers && ZSTR_LEN(headers)) {
php_mail_log_crlf_to_spaces(logline);
}

Expand Down Expand Up @@ -485,7 +488,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
}

if (EG(exception)) {
MAIL_RET(false);
return false;
}

const char *line_sep;
Expand All @@ -510,22 +513,25 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
line_sep = PG(mail_mixed_lf_and_crlf) ? "\n" : "\r\n";
}

zend_string *headers_with_x_php_header = NULL;
if (PG(mail_x_header)) {
const char *tmp = zend_get_executed_filename();
zend_string *f;

f = php_basename(tmp, strlen(tmp), NULL, 0);

if (headers != NULL && *headers) {
spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s%s%s", php_getuid(), ZSTR_VAL(f), line_sep, headers);
if (headers != NULL && ZSTR_LEN(headers)) {
headers_with_x_php_header = strpprintf(0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s%s%s",
php_getuid(), ZSTR_VAL(f), line_sep, ZSTR_VAL(headers));
} else {
spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f));
headers_with_x_php_header = strpprintf(0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s",
php_getuid(), ZSTR_VAL(f));
}
hdr = ahdr;
zend_string_release_ex(f, 0);
headers = headers_with_x_php_header;
}

if (hdr && php_mail_detect_multiple_crlf(hdr)) {
if (php_mail_detect_multiple_crlf(headers)) {
php_error_docref(NULL, E_WARNING, "Multiple or malformed newlines found in additional_header");
MAIL_RET(false);
}
Expand All @@ -536,7 +542,8 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
char *tsm_errmsg = NULL;

/* handle old style win smtp sending */
if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message) == FAILURE) {
int status = TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, headers ? ZSTR_VAL(headers) : NULL, subject, to, ZSTR_VAL(message));
if (status == FAILURE) {
if (tsm_errmsg) {
php_error_docref(NULL, E_WARNING, "%s", tsm_errmsg);
efree(tsm_errmsg);
Expand Down Expand Up @@ -597,35 +604,35 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
#endif
fprintf(sendmail, "To: %s%s", to, line_sep);
fprintf(sendmail, "Subject: %s%s", subject, line_sep);
if (hdr != NULL) {
fprintf(sendmail, "%s%s", hdr, line_sep);
if (headers && ZSTR_LEN(headers)) {
fprintf(sendmail, "%s%s", ZSTR_VAL(headers), line_sep);
}

fprintf(sendmail, "%s", line_sep);

if (cr_lf_mode && zend_string_equals_literal(cr_lf_mode, "lf")) {
char *converted_message = NULL;
size_t msg_len = strlen(message);
size_t msg_len = ZSTR_LEN(message);
size_t new_len = 0;

if (msg_len > 0) {
for (size_t i = 0; i < msg_len - 1; ++i) {
if (message[i] == '\r' && message[i + 1] == '\n') {
if (ZSTR_VAL(message)[i] == '\r' && ZSTR_VAL(message)[i + 1] == '\n') {
++new_len;
}
}

if (new_len == 0) {
fprintf(sendmail, "%s", message);
fprintf(sendmail, "%s", ZSTR_VAL(message));
} else {
converted_message = emalloc(msg_len - new_len + 1);
size_t j = 0;
for (size_t i = 0; i < msg_len; ++i) {
if (i < msg_len - 1 && message[i] == '\r' && message[i + 1] == '\n') {
if (i < msg_len - 1 && ZSTR_VAL(message)[i] == '\r' && ZSTR_VAL(message)[i + 1] == '\n') {
converted_message[j++] = '\n';
++i; /* skip LF part */
} else {
converted_message[j++] = message[i];
converted_message[j++] = ZSTR_VAL(message)[i];
}
}

Expand All @@ -635,7 +642,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c
}
}
} else {
fprintf(sendmail, "%s", message);
fprintf(sendmail, "%s", ZSTR_VAL(message));
}

fprintf(sendmail, "%s", line_sep);
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/php_mail.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
PHP_MINFO_FUNCTION(mail);

PHPAPI zend_string *php_mail_build_headers(const HashTable *headers);
PHPAPI extern bool php_mail(const char *to, const char *subject, const char *message, const char *headers, const zend_string *extra_cmd);
PHPAPI extern bool php_mail(const char *to, const char *subject, const zend_string *message, const zend_string *headers, const zend_string *extra_cmd);

#endif /* PHP_MAIL_H */