Download | Plain Text | Line Numbers
diff -Naur a/ext/standard/mail.c b/ext/standard/mail.c
--- a/ext/standard/mail.c 2024-05-10 12:03:18.958513792 +0200
+++ b/ext/standard/mail.c 2024-05-10 11:58:33.626659753 +0200
@@ -54,6 +54,13 @@
} \
continue; \
} \
+ else if (str[pos] == '\n' && (str[pos + 1] == ' ' || str[pos + 1] == '\t')) { \
+ pos += 1; \
+ while (str[pos + 1] == ' ' || str[pos + 1] == '\t') { \
+ pos++; \
+ } \
+ continue; \
+ } \
extern zend_long php_getuid(void);
@@ -237,6 +244,47 @@
}
+static long
+count_recipients(const char *str, int len, int skip_field)
+{
+ long recipients = 0;
+ int got_field, i;
+
+ if (str == NULL || len <= 0)
+ return 0;
+
+ got_field = skip_field;
+ for (i = 0; str[i]; i++) {
+ /* search for mime-fields
+ * either at beginning or after '\n' of the string
+ */
+ if (!got_field &&
+ (!strncasecmp(&str[i], "To: ", strlen("To: ")) ||
+ !strncasecmp(&str[i], "Cc: ", strlen("Cc: ")) ||
+ !strncasecmp(&str[i], "Bcc: ", strlen("Bcc: "))
+ )) {
+ if (i == 0 || (i > 0 && str[i - 1] == '\n'))
+ got_field = 1;
+ }
+
+ /* search for every '@', don't stop at long headers */
+ if (got_field) {
+ if (str[i] == '@')
+ recipients++;
+ else if (str[i] == '\n')
+ if (i == len - 1 || (str[i + 1] != ' ' && str[i + 1] != '\t'))
+ got_field = 0;
+ }
+
+ /* message body starts here */
+ if (i > 0 && str[i - 1] == '\n' && str[i] == '\n')
+ break;
+ }
+
+ return recipients;
+}
+
+
/* {{{ Send an email message */
PHP_FUNCTION(mail)
{
@@ -249,6 +297,8 @@
size_t subject_len, i;
char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
char *to_r, *subject_r;
+ long recipients = 0;
+ long max_recipients = INI_INT("sendmail_max_recipients");
ZEND_PARSE_PARAMETERS_START(3, 5)
Z_PARAM_PATH(to, to_len)
@@ -287,7 +337,9 @@
* To prevent these separators from being replaced with a space, we use the
* SKIP_LONG_HEADER_SEP to skip over them. */
SKIP_LONG_HEADER_SEP(to_r, i);
- to_r[i] = ' ';
+ php_error_docref(NULL, E_WARNING, "Disallowed characters in mail parameters, mail not sent.");
+ RETVAL_FALSE;
+ goto end;
}
}
} else {
@@ -305,7 +357,9 @@
for (i = 0; subject_r[i]; i++) {
if (iscntrl((unsigned char) subject_r[i])) {
SKIP_LONG_HEADER_SEP(subject_r, i);
- subject_r[i] = ' ';
+ php_error_docref(NULL, E_WARNING, "Disallowed characters in mail parameters, mail not sent.");
+ RETVAL_FALSE;
+ goto end;
}
}
} else {
@@ -318,12 +372,32 @@
extra_cmd = php_escape_shell_cmd(ZSTR_VAL(extra_cmd));
}
+ /* count recipients */
+ if (max_recipients > 0) {
+ recipients += count_recipients(to, to_len, 1);
+ if (headers_str) {
+ recipients += count_recipients(ZSTR_VAL(headers_str), ZSTR_LEN(headers_str), 0);
+ }
+ if (extra_cmd) {
+ recipients += count_recipients(ZSTR_VAL(extra_cmd), ZSTR_LEN(extra_cmd), 1);
+ if (zend_string_starts_with_literal(extra_cmd, "-f")) {
+ recipients--;
+ }
+ }
+ if (recipients > max_recipients) {
+ php_error_docref(NULL, E_WARNING, "Max recipients reached, mail not sent.");
+ RETVAL_FALSE;
+ goto end;
+ }
+ }
+
if (php_mail(to_r, subject_r, message, headers_str && ZSTR_LEN(headers_str) ? ZSTR_VAL(headers_str) : NULL, extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)) {
RETVAL_TRUE;
} else {
RETVAL_FALSE;
}
+end:
if (headers_str) {
zend_string_release_ex(headers_str, 0);
}
@@ -432,10 +506,23 @@
} \
return val; \
+ zval *zhttphost;
+ char *httphost = NULL;
+ if ((mail_log && *mail_log) || PG(mail_x_header)) {
+ if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
+ (zhttphost = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), ZEND_STRL("HTTP_HOST"))) != NULL &&
+ Z_TYPE_P(zhttphost) == IS_STRING &&
+ Z_STRLEN_P(zhttphost) > 0) {
+ httphost = Z_STRVAL_P(zhttphost);
+ } else {
+ httphost = "";
+ }
+ }
+
if (mail_log && *mail_log) {
char *logline;
- 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 -- HTTP-Host: %s -- Headers: %s -- Subject: %s", zend_get_executed_filename(), zend_get_executed_lineno(), to, httphost, hdr ? hdr : "", subject);
if (hdr) {
php_mail_log_crlf_to_spaces(logline);
@@ -477,9 +564,9 @@
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);
+ spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s%sX-PHP-HTTP-Host: %s%s%s", php_getuid(), tmp, line_sep, httphost, line_sep, headers);
} else {
- spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f));
+ spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\r\nX-PHP-HTTP-Host: %s", php_getuid(), tmp, httphost);
}
hdr = ahdr;
zend_string_release_ex(f, 0);
diff -Naur a/main/main.c b/main/main.c
--- a/main/main.c 2022-09-26 13:36:38.293834496 +0200
+++ b/main/main.c 2022-09-26 13:43:12.767867280 +0200
@@ -743,6 +743,7 @@
PHP_INI_ENTRY("precision", "14", PHP_INI_ALL, OnSetPrecision)
PHP_INI_ENTRY("sendmail_from", NULL, PHP_INI_ALL, NULL)
PHP_INI_ENTRY("sendmail_path", DEFAULT_SENDMAIL_PATH, PHP_INI_SYSTEM, NULL)
+ PHP_INI_ENTRY("sendmail_max_recipients", "5", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("mail.force_extra_parameters",NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnChangeMailForceExtra)
PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL)
PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL)