File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard / mail.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:57 2014 UTC (10 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Author: Rasmus Lerdorf <rasmus@php.net>                              |
   16:    +----------------------------------------------------------------------+
   17:  */
   18: 
   19: /* $Id: mail.c,v 1.1.1.5 2014/06/15 20:03:57 misho Exp $ */
   20: 
   21: #include <stdlib.h>
   22: #include <ctype.h>
   23: #include <stdio.h>
   24: #include "php.h"
   25: #include "ext/standard/info.h"
   26: #include "ext/standard/php_string.h"
   27: #include "ext/standard/basic_functions.h"
   28: 
   29: #if HAVE_SYSEXITS_H
   30: #include <sysexits.h>
   31: #endif
   32: #if HAVE_SYS_SYSEXITS_H
   33: #include <sys/sysexits.h>
   34: #endif
   35: 
   36: #if PHP_SIGCHILD
   37: #if HAVE_SIGNAL_H
   38: #include <signal.h>
   39: #endif
   40: #endif
   41: 
   42: #include "php_syslog.h"
   43: #include "php_mail.h"
   44: #include "php_ini.h"
   45: #include "php_string.h"
   46: #include "exec.h"
   47: 
   48: #ifdef PHP_WIN32
   49: #include "win32/sendmail.h"
   50: #endif
   51: 
   52: #ifdef NETWARE
   53: #define EX_OK           0       /* successful termination */
   54: #define EX_TEMPFAIL     75      /* temp failure; user is invited to retry */
   55: #endif
   56: 
   57: #define SKIP_LONG_HEADER_SEP(str, pos)																	\
   58: 	if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) {	\
   59: 		pos += 2;																						\
   60: 		while (str[pos + 1] == ' ' || str[pos + 1] == '\t') {											\
   61: 			pos++;																						\
   62: 		}																								\
   63: 		continue;																						\
   64: 	}																									\
   65: 
   66: #define MAIL_ASCIIZ_CHECK(str, len)				\
   67: 	p = str;									\
   68: 	e = p + len;								\
   69: 	while ((p = memchr(p, '\0', (e - p)))) {	\
   70: 		*p = ' ';								\
   71: 	}											\
   72: 
   73: extern long php_getuid(TSRMLS_D);
   74: 
   75: /* {{{ proto int ezmlm_hash(string addr)
   76:    Calculate EZMLM list hash value. */
   77: PHP_FUNCTION(ezmlm_hash)
   78: {
   79: 	char *str = NULL;
   80: 	unsigned int h = 5381;
   81: 	int j, str_len;
   82: 
   83: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
   84: 		return;
   85: 	}
   86: 
   87: 	for (j = 0; j < str_len; j++) {
   88: 		h = (h + (h << 5)) ^ (unsigned long) (unsigned char) tolower(str[j]);
   89: 	}
   90: 
   91: 	h = (h % 53);
   92: 
   93: 	RETURN_LONG((int) h);
   94: }
   95: /* }}} */
   96: 
   97: /* {{{ proto int mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]])
   98:    Send an email message */
   99: PHP_FUNCTION(mail)
  100: {
  101: 	char *to=NULL, *message=NULL, *headers=NULL, *headers_trimmed=NULL;
  102: 	char *subject=NULL, *extra_cmd=NULL;
  103: 	int to_len, message_len, headers_len = 0;
  104: 	int subject_len, extra_cmd_len = 0, i;
  105: 	char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
  106: 	char *to_r, *subject_r;
  107: 	char *p, *e;
  108: 
  109: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ss",	&to, &to_len, &subject, &subject_len, &message, &message_len, &headers, &headers_len, &extra_cmd, &extra_cmd_len) == FAILURE) {
  110: 		return;
  111: 	}
  112: 
  113: 	/* ASCIIZ check */
  114: 	MAIL_ASCIIZ_CHECK(to, to_len);
  115: 	MAIL_ASCIIZ_CHECK(subject, subject_len);
  116: 	MAIL_ASCIIZ_CHECK(message, message_len);
  117: 	if (headers) {
  118: 		MAIL_ASCIIZ_CHECK(headers, headers_len);
  119: 		headers_trimmed = php_trim(headers, headers_len, NULL, 0, NULL, 2 TSRMLS_CC);
  120: 	}
  121: 	if (extra_cmd) {
  122: 		MAIL_ASCIIZ_CHECK(extra_cmd, extra_cmd_len);
  123: 	}
  124: 
  125: 	if (to_len > 0) {
  126: 		to_r = estrndup(to, to_len);
  127: 		for (; to_len; to_len--) {
  128: 			if (!isspace((unsigned char) to_r[to_len - 1])) {
  129: 				break;
  130: 			}
  131: 			to_r[to_len - 1] = '\0';
  132: 		}
  133: 		for (i = 0; to_r[i]; i++) {
  134: 			if (iscntrl((unsigned char) to_r[i])) {
  135: 				/* According to RFC 822, section 3.1.1 long headers may be separated into
  136: 				 * parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
  137: 				 * To prevent these separators from being replaced with a space, we use the
  138: 				 * SKIP_LONG_HEADER_SEP to skip over them. */
  139: 				SKIP_LONG_HEADER_SEP(to_r, i);
  140: 				to_r[i] = ' ';
  141: 			}
  142: 		}
  143: 	} else {
  144: 		to_r = to;
  145: 	}
  146: 
  147: 	if (subject_len > 0) {
  148: 		subject_r = estrndup(subject, subject_len);
  149: 		for (; subject_len; subject_len--) {
  150: 			if (!isspace((unsigned char) subject_r[subject_len - 1])) {
  151: 				break;
  152: 			}
  153: 			subject_r[subject_len - 1] = '\0';
  154: 		}
  155: 		for (i = 0; subject_r[i]; i++) {
  156: 			if (iscntrl((unsigned char) subject_r[i])) {
  157: 				SKIP_LONG_HEADER_SEP(subject_r, i);
  158: 				subject_r[i] = ' ';
  159: 			}
  160: 		}
  161: 	} else {
  162: 		subject_r = subject;
  163: 	}
  164: 
  165: 	if (force_extra_parameters) {
  166: 		extra_cmd = php_escape_shell_cmd(force_extra_parameters);
  167: 	} else if (extra_cmd) {
  168: 		extra_cmd = php_escape_shell_cmd(extra_cmd);
  169: 	}
  170: 
  171: 	if (php_mail(to_r, subject_r, message, headers_trimmed, extra_cmd TSRMLS_CC)) {
  172: 		RETVAL_TRUE;
  173: 	} else {
  174: 		RETVAL_FALSE;
  175: 	}
  176: 
  177: 	if (headers_trimmed) {
  178: 		efree(headers_trimmed);
  179: 	}
  180: 
  181: 	if (extra_cmd) {
  182: 		efree (extra_cmd);
  183: 	}
  184: 	if (to_r != to) {
  185: 		efree(to_r);
  186: 	}
  187: 	if (subject_r != subject) {
  188: 		efree(subject_r);
  189: 	}
  190: }
  191: /* }}} */
  192: 
  193: 
  194: void php_mail_log_crlf_to_spaces(char *message) {
  195: 	/* Find all instances of carriage returns or line feeds and
  196: 	 * replace them with spaces. Thus, a log line is always one line
  197: 	 * long
  198: 	 */
  199: 	char *p = message;
  200: 	while ((p = strpbrk(p, "\r\n"))) {
  201: 		*p = ' ';
  202: 	}
  203: }
  204: 
  205: void php_mail_log_to_syslog(char *message) {
  206: 	/* Write 'message' to syslog. */
  207: #ifdef HAVE_SYSLOG_H
  208: 	php_syslog(LOG_NOTICE, "%s", message);
  209: #endif
  210: }
  211: 
  212: 
  213: void php_mail_log_to_file(char *filename, char *message, size_t message_size TSRMLS_DC) {
  214: 	/* Write 'message' to the given file. */
  215: 	uint flags = IGNORE_URL_WIN | REPORT_ERRORS | STREAM_DISABLE_OPEN_BASEDIR;
  216: 	php_stream *stream = php_stream_open_wrapper(filename, "a", flags, NULL);
  217: 	if (stream) {
  218: 		php_stream_write(stream, message, message_size);
  219: 		php_stream_close(stream);
  220: 	}
  221: }
  222: 
  223: 
  224: /* {{{ php_mail
  225:  */
  226: PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd TSRMLS_DC)
  227: {
  228: #if (defined PHP_WIN32 || defined NETWARE)
  229: 	int tsm_err;
  230: 	char *tsm_errmsg = NULL;
  231: #endif
  232: 	FILE *sendmail;
  233: 	int ret;
  234: 	char *sendmail_path = INI_STR("sendmail_path");
  235: 	char *sendmail_cmd = NULL;
  236: 	char *mail_log = INI_STR("mail.log");
  237: 	char *hdr = headers;
  238: #if PHP_SIGCHILD
  239: 	void (*sig_handler)() = NULL;
  240: #endif
  241: 
  242: #define MAIL_RET(val) \
  243: 	if (hdr != headers) {	\
  244: 		efree(hdr);	\
  245: 	}	\
  246: 	return val;	\
  247: 
  248: 	if (mail_log && *mail_log) {
  249: 		char *tmp;
  250: 		int l = spprintf(&tmp, 0, "mail() on [%s:%d]: To: %s -- Headers: %s\n", zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C), to, hdr ? hdr : "");
  251: 
  252: 		if (hdr) {
  253: 			php_mail_log_crlf_to_spaces(tmp);
  254: 		}
  255: 
  256: 		if (!strcmp(mail_log, "syslog")) {
  257: 			/* Drop the final space when logging to syslog. */
  258: 			tmp[l - 1] = 0;
  259: 			php_mail_log_to_syslog(tmp);
  260: 		}
  261: 		else {
  262: 			/* Convert the final space to a newline when logging to file. */
  263: 			tmp[l - 1] = '\n';
  264: 			php_mail_log_to_file(mail_log, tmp, l TSRMLS_CC);
  265: 		}
  266: 
  267: 		efree(tmp);
  268: 	}
  269: 	if (PG(mail_x_header)) {
  270: 		const char *tmp = zend_get_executed_filename(TSRMLS_C);
  271: 		char *f;
  272: 		size_t f_len;
  273: 
  274: 		php_basename(tmp, strlen(tmp), NULL, 0,&f, &f_len TSRMLS_CC);
  275: 
  276: 		if (headers != NULL) {
  277: 			spprintf(&hdr, 0, "X-PHP-Originating-Script: %ld:%s\n%s", php_getuid(TSRMLS_C), f, headers);
  278: 		} else {
  279: 			spprintf(&hdr, 0, "X-PHP-Originating-Script: %ld:%s", php_getuid(TSRMLS_C), f);
  280: 		}
  281: 		efree(f);
  282: 	}
  283: 
  284: 	if (!sendmail_path) {
  285: #if (defined PHP_WIN32 || defined NETWARE)
  286: 		/* handle old style win smtp sending */
  287: 		if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message, NULL, NULL, NULL TSRMLS_CC) == FAILURE) {
  288: 			if (tsm_errmsg) {
  289: 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tsm_errmsg);
  290: 				efree(tsm_errmsg);
  291: 			} else {
  292: 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", GetSMErrorText(tsm_err));
  293: 			}
  294: 			MAIL_RET(0);
  295: 		}
  296: 		MAIL_RET(1);
  297: #else
  298: 		MAIL_RET(0);
  299: #endif
  300: 	}
  301: 	if (extra_cmd != NULL) {
  302: 		spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, extra_cmd);
  303: 	} else {
  304: 		sendmail_cmd = sendmail_path;
  305: 	}
  306: 
  307: #if PHP_SIGCHILD
  308: 	/* Set signal handler of SIGCHLD to default to prevent other signal handlers
  309: 	 * from being called and reaping the return code when our child exits.
  310: 	 * The original handler needs to be restored after pclose() */
  311: 	sig_handler = (void *)signal(SIGCHLD, SIG_DFL);
  312: 	if (sig_handler == SIG_ERR) {
  313: 		sig_handler = NULL;
  314: 	}
  315: #endif
  316: 
  317: #ifdef PHP_WIN32
  318: 	sendmail = popen_ex(sendmail_cmd, "wb", NULL, NULL TSRMLS_CC);
  319: #else
  320: 	/* Since popen() doesn't indicate if the internal fork() doesn't work
  321: 	 * (e.g. the shell can't be executed) we explicitly set it to 0 to be
  322: 	 * sure we don't catch any older errno value. */
  323: 	errno = 0;
  324: 	sendmail = popen(sendmail_cmd, "w");
  325: #endif
  326: 	if (extra_cmd != NULL) {
  327: 		efree (sendmail_cmd);
  328: 	}
  329: 
  330: 	if (sendmail) {
  331: #ifndef PHP_WIN32
  332: 		if (EACCES == errno) {
  333: 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path);
  334: 			pclose(sendmail);
  335: #if PHP_SIGCHILD
  336: 			/* Restore handler in case of error on Windows
  337: 			   Not sure if this applicable on Win but just in case. */
  338: 			if (sig_handler) {
  339: 				signal(SIGCHLD, sig_handler);
  340: 			}
  341: #endif
  342: 			MAIL_RET(0);
  343: 		}
  344: #endif
  345: 		fprintf(sendmail, "To: %s\n", to);
  346: 		fprintf(sendmail, "Subject: %s\n", subject);
  347: 		if (hdr != NULL) {
  348: 			fprintf(sendmail, "%s\n", hdr);
  349: 		}
  350: 		fprintf(sendmail, "\n%s\n", message);
  351: 		ret = pclose(sendmail);
  352: 
  353: #if PHP_SIGCHILD
  354: 		if (sig_handler) {
  355: 			signal(SIGCHLD, sig_handler);
  356: 		}
  357: #endif
  358: 
  359: #ifdef PHP_WIN32
  360: 		if (ret == -1)
  361: #else
  362: #if defined(EX_TEMPFAIL)
  363: 		if ((ret != EX_OK)&&(ret != EX_TEMPFAIL))
  364: #elif defined(EX_OK)
  365: 		if (ret != EX_OK)
  366: #else
  367: 		if (ret != 0)
  368: #endif
  369: #endif
  370: 		{
  371: 			MAIL_RET(0);
  372: 		} else {
  373: 			MAIL_RET(1);
  374: 		}
  375: 	} else {
  376: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute mail delivery program '%s'", sendmail_path);
  377: #if PHP_SIGCHILD
  378: 		if (sig_handler) {
  379: 			signal(SIGCHLD, sig_handler);						
  380: 		}
  381: #endif
  382: 		MAIL_RET(0);
  383: 	}
  384: 
  385: 	MAIL_RET(1); /* never reached */
  386: }
  387: /* }}} */
  388: 
  389: /* {{{ PHP_MINFO_FUNCTION
  390:  */
  391: PHP_MINFO_FUNCTION(mail)
  392: {
  393: 	char *sendmail_path = INI_STR("sendmail_path");
  394: 
  395: #ifdef PHP_WIN32
  396: 	if (!sendmail_path) {
  397: 		php_info_print_table_row(2, "Internal Sendmail Support for Windows", "enabled");
  398: 	} else {
  399: 		php_info_print_table_row(2, "Path to sendmail", sendmail_path);
  400: 	}
  401: #else
  402: 	php_info_print_table_row(2, "Path to sendmail", sendmail_path);
  403: #endif
  404: }
  405: /* }}} */
  406: 
  407: /*
  408:  * Local variables:
  409:  * tab-width: 4
  410:  * c-basic-offset: 4
  411:  * End:
  412:  * vim600: sw=4 ts=4 fdm=marker
  413:  * vim<600: sw=4 ts=4
  414:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>