diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index c5331ef017af..805c4084352d 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -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" @@ -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); @@ -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); diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index c108900103cc..4d9e1dc82bc7 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -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; diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 395c7bb81d4f..c185afa2937a 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -21,7 +21,6 @@ #include "php.h" #include "ext/standard/info.h" #include "ext/standard/php_string.h" -#include "ext/standard/basic_functions.h" #include "ext/date/php_date.h" #include "zend_smart_str.h" @@ -154,10 +153,6 @@ static void php_mail_build_headers_elem(smart_str *s, const zend_string *key, zv case CONTAINS_NULL: zend_value_error("Header \"%s\" contains NULL character that is not allowed in the header", ZSTR_VAL(key)); return; - default: - // fallback - zend_value_error("Header \"%s\" has invalid format, or contains invalid characters", ZSTR_VAL(key)); - return; } smart_str_append(s, key); smart_str_appendl(s, ": ", 2); @@ -265,19 +260,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) @@ -343,7 +339,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; @@ -396,31 +392,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) { 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; } @@ -429,35 +427,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); } @@ -485,7 +483,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; @@ -510,22 +508,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); } @@ -536,7 +537,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); @@ -579,122 +581,121 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c efree (sendmail_cmd); } - if (sendmail) { - int ret; -#ifndef PHP_WIN32 - if (EACCES == errno) { - php_error_docref(NULL, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path); - pclose(sendmail); + if (UNEXPECTED(!sendmail)) { + php_error_docref(NULL, E_WARNING, "Could not execute mail delivery program '%s'", sendmail_path); #if PHP_SIGCHILD - /* Restore handler in case of error on Windows - Not sure if this applicable on Win but just in case. */ - if (sig_handler) { - signal(SIGCHLD, sig_handler); - } -#endif - MAIL_RET(false); + if (sig_handler) { + signal(SIGCHLD, sig_handler); } #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); + MAIL_RET(false); + } + +#ifndef PHP_WIN32 + if (EACCES == errno) { + php_error_docref(NULL, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path); + pclose(sendmail); +#if PHP_SIGCHILD + /* Restore handler in case of error on Windows + Not sure if this applicable on Win but just in case. */ + if (sig_handler) { + signal(SIGCHLD, sig_handler); } +#endif + MAIL_RET(false); + } +#endif + fprintf(sendmail, "To: %s%s", to, line_sep); + fprintf(sendmail, "Subject: %s%s", subject, 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 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') { - ++new_len; - } + 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 = ZSTR_LEN(message); + size_t new_len = 0; + + if (msg_len > 0) { + for (size_t i = 0; i < msg_len - 1; ++i) { + if (ZSTR_VAL(message)[i] == '\r' && ZSTR_VAL(message)[i + 1] == '\n') { + ++new_len; } + } - if (new_len == 0) { - fprintf(sendmail, "%s", 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') { - converted_message[j++] = '\n'; - ++i; /* skip LF part */ - } else { - converted_message[j++] = message[i]; - } + if (new_len == 0) { + 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 && ZSTR_VAL(message)[i] == '\r' && ZSTR_VAL(message)[i + 1] == '\n') { + converted_message[j++] = '\n'; + ++i; /* skip LF part */ + } else { + converted_message[j++] = ZSTR_VAL(message)[i]; } - - converted_message[j] = '\0'; - fprintf(sendmail, "%s", converted_message); - efree(converted_message); } + + converted_message[j] = '\0'; + fprintf(sendmail, "%s", converted_message); + efree(converted_message); } - } else { - fprintf(sendmail, "%s", message); } + } else { + fprintf(sendmail, "%s", ZSTR_VAL(message)); + } - fprintf(sendmail, "%s", line_sep); + fprintf(sendmail, "%s", line_sep); + + int ret; #ifdef PHP_WIN32 - ret = pclose(sendmail); + ret = pclose(sendmail); #if PHP_SIGCHILD - if (sig_handler) { - signal(SIGCHLD, sig_handler); - } + if (sig_handler) { + signal(SIGCHLD, sig_handler); + } #endif #else - int wstatus = pclose(sendmail); + int wstatus = pclose(sendmail); #if PHP_SIGCHILD - if (sig_handler) { - signal(SIGCHLD, sig_handler); - } + if (sig_handler) { + signal(SIGCHLD, sig_handler); + } #endif - /* Determine the wait(2) exit status */ - if (wstatus == -1) { - php_error_docref(NULL, E_WARNING, "Sendmail pclose failed %d (%s)", errno, strerror(errno)); - MAIL_RET(false); - } else if (WIFSIGNALED(wstatus)) { - php_error_docref(NULL, E_WARNING, "Sendmail killed by signal %d (%s)", WTERMSIG(wstatus), strsignal(WTERMSIG(wstatus))); - MAIL_RET(false); + /* Determine the wait(2) exit status */ + if (wstatus == -1) { + php_error_docref(NULL, E_WARNING, "Sendmail pclose failed %d (%s)", errno, strerror(errno)); + MAIL_RET(false); + } else if (WIFSIGNALED(wstatus)) { + php_error_docref(NULL, E_WARNING, "Sendmail killed by signal %d (%s)", WTERMSIG(wstatus), strsignal(WTERMSIG(wstatus))); + MAIL_RET(false); + } else { + if (WIFEXITED(wstatus)) { + ret = WEXITSTATUS(wstatus); } else { - if (WIFEXITED(wstatus)) { - ret = WEXITSTATUS(wstatus); - } else { - php_error_docref(NULL, E_WARNING, "Sendmail did not exit"); - MAIL_RET(false); - } + php_error_docref(NULL, E_WARNING, "Sendmail did not exit"); + MAIL_RET(false); } + } #endif #if defined(EX_TEMPFAIL) - if ((ret != EX_OK)&&(ret != EX_TEMPFAIL)) + if ((ret != EX_OK)&&(ret != EX_TEMPFAIL)) #elif defined(EX_OK) - if (ret != EX_OK) + if (ret != EX_OK) #else - if (ret != 0) -#endif - { - php_error_docref(NULL, E_WARNING, "Sendmail exited with non-zero exit code %d", ret); - MAIL_RET(false); - } else { - MAIL_RET(true); - } - } else { - php_error_docref(NULL, E_WARNING, "Could not execute mail delivery program '%s'", sendmail_path); -#if PHP_SIGCHILD - if (sig_handler) { - signal(SIGCHLD, sig_handler); - } + if (ret != 0) #endif + { + php_error_docref(NULL, E_WARNING, "Sendmail exited with non-zero exit code %d", ret); MAIL_RET(false); + } else { + MAIL_RET(true); } - - MAIL_RET(true); /* never reached */ } /* }}} */ diff --git a/ext/standard/php_mail.h b/ext/standard/php_mail.h index bebb526699d0..ade6a4124401 100644 --- a/ext/standard/php_mail.h +++ b/ext/standard/php_mail.h @@ -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 */