Download | Plain Text | No Line Numbers


  1. diff -Naur a/ext/standard/mail.c b/ext/standard/mail.c
  2. --- a/ext/standard/mail.c 2024-05-10 12:03:18.958513792 +0200
  3. +++ b/ext/standard/mail.c 2024-05-10 11:58:33.626659753 +0200
  4. @@ -54,6 +54,13 @@
  5. } \
  6. continue; \
  7. } \
  8. + else if (str[pos] == '\n' && (str[pos + 1] == ' ' || str[pos + 1] == '\t')) { \
  9. + pos += 1; \
  10. + while (str[pos + 1] == ' ' || str[pos + 1] == '\t') { \
  11. + pos++; \
  12. + } \
  13. + continue; \
  14. + } \
  15.  
  16. extern zend_long php_getuid(void);
  17.  
  18. @@ -237,6 +244,47 @@
  19. }
  20.  
  21.  
  22. +static long
  23. +count_recipients(const char *str, int len, int skip_field)
  24. +{
  25. + long recipients = 0;
  26. + int got_field, i;
  27. +
  28. + if (str == NULL || len <= 0)
  29. + return 0;
  30. +
  31. + got_field = skip_field;
  32. + for (i = 0; str[i]; i++) {
  33. + /* search for mime-fields
  34. + * either at beginning or after '\n' of the string
  35. + */
  36. + if (!got_field &&
  37. + (!strncasecmp(&str[i], "To: ", strlen("To: ")) ||
  38. + !strncasecmp(&str[i], "Cc: ", strlen("Cc: ")) ||
  39. + !strncasecmp(&str[i], "Bcc: ", strlen("Bcc: "))
  40. + )) {
  41. + if (i == 0 || (i > 0 && str[i - 1] == '\n'))
  42. + got_field = 1;
  43. + }
  44. +
  45. + /* search for every '@', don't stop at long headers */
  46. + if (got_field) {
  47. + if (str[i] == '@')
  48. + recipients++;
  49. + else if (str[i] == '\n')
  50. + if (i == len - 1 || (str[i + 1] != ' ' && str[i + 1] != '\t'))
  51. + got_field = 0;
  52. + }
  53. +
  54. + /* message body starts here */
  55. + if (i > 0 && str[i - 1] == '\n' && str[i] == '\n')
  56. + break;
  57. + }
  58. +
  59. + return recipients;
  60. +}
  61. +
  62. +
  63. /* {{{ Send an email message */
  64. PHP_FUNCTION(mail)
  65. {
  66. @@ -249,6 +297,8 @@
  67. size_t subject_len, i;
  68. char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
  69. char *to_r, *subject_r;
  70. + long recipients = 0;
  71. + long max_recipients = INI_INT("sendmail_max_recipients");
  72.  
  73. ZEND_PARSE_PARAMETERS_START(3, 5)
  74. Z_PARAM_PATH(to, to_len)
  75. @@ -287,7 +337,9 @@
  76. * To prevent these separators from being replaced with a space, we use the
  77. * SKIP_LONG_HEADER_SEP to skip over them. */
  78. SKIP_LONG_HEADER_SEP(to_r, i);
  79. - to_r[i] = ' ';
  80. + php_error_docref(NULL, E_WARNING, "Disallowed characters in mail parameters, mail not sent.");
  81. + RETVAL_FALSE;
  82. + goto end;
  83. }
  84. }
  85. } else {
  86. @@ -305,7 +357,9 @@
  87. for (i = 0; subject_r[i]; i++) {
  88. if (iscntrl((unsigned char) subject_r[i])) {
  89. SKIP_LONG_HEADER_SEP(subject_r, i);
  90. - subject_r[i] = ' ';
  91. + php_error_docref(NULL, E_WARNING, "Disallowed characters in mail parameters, mail not sent.");
  92. + RETVAL_FALSE;
  93. + goto end;
  94. }
  95. }
  96. } else {
  97. @@ -318,12 +372,32 @@
  98. extra_cmd = php_escape_shell_cmd(ZSTR_VAL(extra_cmd));
  99. }
  100.  
  101. + /* count recipients */
  102. + if (max_recipients > 0) {
  103. + recipients += count_recipients(to, to_len, 1);
  104. + if (headers_str) {
  105. + recipients += count_recipients(ZSTR_VAL(headers_str), ZSTR_LEN(headers_str), 0);
  106. + }
  107. + if (extra_cmd) {
  108. + recipients += count_recipients(ZSTR_VAL(extra_cmd), ZSTR_LEN(extra_cmd), 1);
  109. + if (zend_string_starts_with_literal(extra_cmd, "-f")) {
  110. + recipients--;
  111. + }
  112. + }
  113. + if (recipients > max_recipients) {
  114. + php_error_docref(NULL, E_WARNING, "Max recipients reached, mail not sent.");
  115. + RETVAL_FALSE;
  116. + goto end;
  117. + }
  118. + }
  119. +
  120. 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)) {
  121. RETVAL_TRUE;
  122. } else {
  123. RETVAL_FALSE;
  124. }
  125.  
  126. +end:
  127. if (headers_str) {
  128. zend_string_release_ex(headers_str, 0);
  129. }
  130. @@ -432,10 +506,23 @@
  131. } \
  132. return val; \
  133.  
  134. + zval *zhttphost;
  135. + char *httphost = NULL;
  136. + if ((mail_log && *mail_log) || PG(mail_x_header)) {
  137. + if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
  138. + (zhttphost = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), ZEND_STRL("HTTP_HOST"))) != NULL &&
  139. + Z_TYPE_P(zhttphost) == IS_STRING &&
  140. + Z_STRLEN_P(zhttphost) > 0) {
  141. + httphost = Z_STRVAL_P(zhttphost);
  142. + } else {
  143. + httphost = "";
  144. + }
  145. + }
  146. +
  147. if (mail_log && *mail_log) {
  148. char *logline;
  149.  
  150. - 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);
  151. + 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);
  152.  
  153. if (hdr) {
  154. php_mail_log_crlf_to_spaces(logline);
  155. @@ -477,9 +564,9 @@
  156. f = php_basename(tmp, strlen(tmp), NULL, 0);
  157.  
  158. if (headers != NULL && *headers) {
  159. - spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s%s%s", php_getuid(), ZSTR_VAL(f), line_sep, headers);
  160. + 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);
  161. } else {
  162. - spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f));
  163. + spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\r\nX-PHP-HTTP-Host: %s", php_getuid(), tmp, httphost);
  164. }
  165. hdr = ahdr;
  166. zend_string_release_ex(f, 0);
  167. diff -Naur a/main/main.c b/main/main.c
  168. --- a/main/main.c 2022-09-26 13:36:38.293834496 +0200
  169. +++ b/main/main.c 2022-09-26 13:43:12.767867280 +0200
  170. @@ -743,6 +743,7 @@
  171. PHP_INI_ENTRY("precision", "14", PHP_INI_ALL, OnSetPrecision)
  172. PHP_INI_ENTRY("sendmail_from", NULL, PHP_INI_ALL, NULL)
  173. PHP_INI_ENTRY("sendmail_path", DEFAULT_SENDMAIL_PATH, PHP_INI_SYSTEM, NULL)
  174. + PHP_INI_ENTRY("sendmail_max_recipients", "5", PHP_INI_ALL, NULL)
  175. PHP_INI_ENTRY("mail.force_extra_parameters",NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnChangeMailForceExtra)
  176. PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL)
  177. PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL)
  178.