Download | Plain Text | Line Numbers


diff -Naur php-7.0.17.orig/ext/standard/mail.c php-7.0.17/ext/standard/mail.c
--- php-7.0.17.orig/ext/standard/mail.c	2017-03-14 12:26:10.000000000 +0100
+++ php-7.0.17/ext/standard/mail.c	2017-04-11 00:04:56.203579871 +0200
@@ -64,6 +64,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;																						\
+	}																									\
 
 #define MAIL_ASCIIZ_CHECK(str, len)				\
 	p = str;									\
@@ -96,6 +103,46 @@
 }
 /* }}} */
 
+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;
+}
+
 /* {{{ proto int mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]])
    Send an email message */
 PHP_FUNCTION(mail)
@@ -106,8 +153,10 @@
 	size_t to_len, message_len;
 	size_t subject_len, i;
 	char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
-	char *to_r, *subject_r;
+	char *to_r=NULL, *subject_r=NULL;
 	char *p, *e;
+	long recipients = 0;
+	long max_recipients = INI_INT("sendmail_max_recipients");
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|SS",	&to, &to_len, &subject, &subject_len, &message, &message_len, &headers, &extra_cmd) == FAILURE) {
 		return;
@@ -125,6 +174,19 @@
 		MAIL_ASCIIZ_CHECK(ZSTR_VAL(extra_cmd), ZSTR_LEN(extra_cmd));
 	}
 
+	/* count recipients */
+	if (max_recipients > 0) {
+		recipients += count_recipients(to, to_len, 1);
+		if (headers) {
+			recipients += count_recipients(ZSTR_VAL(headers), ZSTR_LEN(headers), 0);
+		}
+		if (recipients > max_recipients) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Max recipients reached, mail not sent.");
+			RETVAL_FALSE;
+			goto end;
+		}
+	}
+
 	if (to_len > 0) {
 		to_r = estrndup(to, to_len);
 		for (; to_len; to_len--) {
@@ -140,7 +202,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 TSRMLS_CC, E_WARNING, "Disallowed characters in mail parameters, mail not sent.");
+				RETVAL_FALSE;
+				goto end;
 			}
 		}
 	} else {
@@ -158,7 +222,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 TSRMLS_CC, E_WARNING, "Disallowed characters in mail parameters, mail not sent.");
+				RETVAL_FALSE;
+				goto end;
 			}
 		}
 	} else {
@@ -177,6 +243,7 @@
 		RETVAL_FALSE;
 	}
 
+end:
 	if (headers_trimmed) {
 		zend_string_release(headers_trimmed);
 	}
@@ -285,6 +352,19 @@
 	}	\
 	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 *tmp;
 		time_t curtime;
@@ -294,7 +374,7 @@
 		time(&curtime);
 		date_str = php_format_date("d-M-Y H:i:s e", 13, curtime, 1);
 
-		l = spprintf(&tmp, 0, "[%s] mail() on [%s:%d]: To: %s -- Headers: %s\n", ZSTR_VAL(date_str), zend_get_executed_filename(), zend_get_executed_lineno(), to, hdr ? hdr : "");
+		l = spprintf(&tmp, 0, "[%s] mail() on [%s:%d]: To: %s -- HTTP-Host: %s -- Headers: %s\n", ZSTR_VAL(date_str), zend_get_executed_filename(), zend_get_executed_lineno(), to, httphost, hdr ? hdr : "");
 
 		zend_string_free(date_str);
 
@@ -318,16 +398,12 @@
 
 	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(&hdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\n%s", php_getuid(), ZSTR_VAL(f), headers);
+			spprintf(&hdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\nX-PHP-HTTP-Host: %s\n%s", php_getuid(), tmp, httphost, headers);
 		} else {
-			spprintf(&hdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f));
+			spprintf(&hdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\nX-PHP-HTTP-Host: %s", php_getuid(), tmp, httphost);
 		}
-		zend_string_release(f);
 	}
 
 	if (hdr && php_mail_detect_multiple_crlf(hdr)) {
diff -Naur php-7.0.17.orig/main/main.c php-7.0.17/main/main.c
--- php-7.0.17.orig/main/main.c	2017-03-14 12:26:16.000000000 +0100
+++ php-7.0.17/main/main.c	2017-04-11 00:04:29.047890385 +0200
@@ -558,6 +558,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)