From ea5d3fc2fcc4fe8c797e5732ae26d2c50b5c37b3 Mon Sep 17 00:00:00 2001 From: Giam Teck Choon Date: Wed, 18 Oct 2017 08:35:23 +0000 Subject: [PATCH] PHP mail() header patch for v7.1.x This is a patch to add an informational header to messages sent from PHP via the mail() function. This can help to track which script on a server was used to send a message, and which client caused it to be sent. The header added has the form: X-PHP-Script: for For example: X-PHP-Script: www.example.com/~user/testapp/send-mail.php for 10.0.0.1 If the connection appears to have come via a proxy cache (i.e. has an "X-Forwarded-For" header), is a list of addresses (the addresses in X-Forwarded-For, then the 'real' remote address). This patch is a modified version of Steve Bennett's patch which can be read at http://www.lancs.ac.uk/~steveb/patches/php-mail-header-patch/ since his patch only available for version 4.3.4 during the time I checked and also won't be working for mail function example 1 as listed at http://www.php.net/manual/en/function.mail.php Special thanks to: (1) Steve Bennett for his patch (2) Stefan Esser from hardened-php.net to report a security issue regarding PHP_SELF in headers (http://www.hardened-php.net/advisory_142006.139.html) (3) Alexey Koscheev from koscheev.ru regarding using zend_is_auto_global to properly access $_SERVER (24 Jan 2015) Reference: http://grokbase.com/t/php/php-internals/033hwqce0z/server-registration-issue (4) Alexey Koscheev from koscheev.ru regarding protecting variables from changing by user (14 Mar 2016) (5) Use Alexey Koscheev's patch from koscheev.ru and test success with nginx/php-fpm (18 Oct 2017) Signed-off-by: Giam Teck Choon --- ext/standard/mail.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 26272cd..8e4e29a 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -336,6 +336,52 @@ PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char MAIL_RET(0); } + char *headers2 = NULL; + while(1) { + zend_string *server = zend_string_init("_SERVER", sizeof("_SERVER") - 1, 0); + zend_is_auto_global(server); + + zval *remote_addr, *forwarded_for, *php_self, *server_name; + + if (Z_ISUNDEF(PG(http_globals)[TRACK_VARS_SERVER])) + break; + + if (!((remote_addr = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1)) && + Z_TYPE_P(remote_addr) == IS_STRING)) + break; + + if (!((php_self = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "PHP_SELF", sizeof("PHP_SELF") - 1)) && + Z_TYPE_P(php_self) == IS_STRING)) + break; + + if (!((server_name = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "SERVER_NAME", sizeof("SERVER_NAME") - 1)) && + Z_TYPE_P(server_name) == IS_STRING)) + break; + + forwarded_for = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_X_FORWARDED_FOR", sizeof("HTTP_X_FORWARDED_FOR") - 1); + if (forwarded_for && Z_TYPE_P(forwarded_for) != IS_STRING) + forwarded_for = NULL; + + headers2 = emalloc(32 + Z_STRLEN_P(server_name) + Z_STRLEN_P(php_self) + + (forwarded_for ? Z_STRLEN_P(forwarded_for) + 2 : 0) + + Z_STRLEN_P(remote_addr)); + strcpy(headers2, "X-PHP-Script: "); + strcat(headers2, Z_STRVAL_P(server_name)); + if (strchr(Z_STRVAL_P(php_self), '\n') != NULL || strchr(Z_STRVAL_P(php_self), '\r') != NULL) { + php_error_docref(NULL, E_WARNING, "Newline found in PHP_SELF variable which might cause possible injection '%s'", Z_STRVAL_P(php_self)); + } + else { + strcat(headers2, Z_STRVAL_P(php_self)); + } + strcat(headers2, " for "); + if (forwarded_for) { + strcat(headers2, Z_STRVAL_P(forwarded_for)); + strcat(headers2, ", "); + } + strcat(headers2, Z_STRVAL_P(remote_addr)); + break; + } + if (!sendmail_path) { #if (defined PHP_WIN32 || defined NETWARE) /* handle old style win smtp sending */ @@ -399,6 +445,10 @@ PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char #endif fprintf(sendmail, "To: %s\n", to); fprintf(sendmail, "Subject: %s\n", subject); + if (headers2 != NULL) { + fprintf(sendmail, "%s\n", headers2); + efree(headers2); + } if (hdr != NULL) { fprintf(sendmail, "%s\n", hdr); } -- 1.8.3.1