xref: /PHP-7.3/ext/standard/mail.c (revision ae215069)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 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 #include <stdlib.h>
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <time.h>
23 #include "php.h"
24 #include "ext/standard/info.h"
25 #include "ext/standard/php_string.h"
26 #include "ext/standard/basic_functions.h"
27 #include "ext/date/php_date.h"
28 #include "zend_smart_str.h"
29 
30 #if HAVE_SYSEXITS_H
31 #include <sysexits.h>
32 #endif
33 #if HAVE_SYS_SYSEXITS_H
34 #include <sys/sysexits.h>
35 #endif
36 
37 #if PHP_SIGCHILD
38 #if HAVE_SIGNAL_H
39 #include <signal.h>
40 #endif
41 #endif
42 
43 #include "php_syslog.h"
44 #include "php_mail.h"
45 #include "php_ini.h"
46 #include "php_string.h"
47 #include "exec.h"
48 
49 #ifdef PHP_WIN32
50 #include "win32/sendmail.h"
51 #endif
52 
53 #define SKIP_LONG_HEADER_SEP(str, pos)																	\
54 	if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) {	\
55 		pos += 2;																						\
56 		while (str[pos + 1] == ' ' || str[pos + 1] == '\t') {											\
57 			pos++;																						\
58 		}																								\
59 		continue;																						\
60 	}																									\
61 
62 #define MAIL_ASCIIZ_CHECK(str, len)				\
63 	p = str;									\
64 	e = p + len;								\
65 	while ((p = memchr(p, '\0', (e - p)))) {	\
66 		*p = ' ';								\
67 	}											\
68 
69 extern zend_long php_getuid(void);
70 
71 /* {{{ proto int ezmlm_hash(string addr)
72    Calculate EZMLM list hash value. */
PHP_FUNCTION(ezmlm_hash)73 PHP_FUNCTION(ezmlm_hash)
74 {
75 	char *str = NULL;
76 	unsigned int h = 5381;
77 	size_t j, str_len;
78 
79 	ZEND_PARSE_PARAMETERS_START(1, 1)
80 		Z_PARAM_STRING(str, str_len)
81 	ZEND_PARSE_PARAMETERS_END();
82 
83 	for (j = 0; j < str_len; j++) {
84 		h = (h + (h << 5)) ^ (zend_ulong) (unsigned char) tolower(str[j]);
85 	}
86 
87 	h = (h % 53);
88 
89 	RETURN_LONG((zend_long) h);
90 }
91 /* }}} */
92 
93 
php_mail_build_headers_check_field_value(zval * val)94 static zend_bool php_mail_build_headers_check_field_value(zval *val)
95 {
96 	size_t len = 0;
97 	zend_string *value = Z_STR_P(val);
98 
99 	/* https://tools.ietf.org/html/rfc2822#section-2.2.1 */
100 	/* https://tools.ietf.org/html/rfc2822#section-2.2.3 */
101 	while (len < value->len) {
102 		if (*(value->val+len) == '\r') {
103 			if (value->len - len >= 3
104 				&&  *(value->val+len+1) == '\n'
105 				&& (*(value->val+len+2) == ' '  || *(value->val+len+2) == '\t')) {
106 				len += 3;
107 				continue;
108 			}
109 			return FAILURE;
110 		}
111 		if (*(value->val+len) == '\0') {
112 			return FAILURE;
113 		}
114 		len++;
115 	}
116 	return SUCCESS;
117 }
118 
119 
php_mail_build_headers_check_field_name(zend_string * key)120 static zend_bool php_mail_build_headers_check_field_name(zend_string *key)
121 {
122 	size_t len = 0;
123 
124 	/* https://tools.ietf.org/html/rfc2822#section-2.2 */
125 	while (len < key->len) {
126 		if (*(key->val+len) < 33 || *(key->val+len) > 126 || *(key->val+len) == ':') {
127 			return FAILURE;
128 		}
129 		len++;
130 	}
131 	return SUCCESS;
132 }
133 
134 
135 static void php_mail_build_headers_elems(smart_str *s, zend_string *key, zval *val);
136 
php_mail_build_headers_elem(smart_str * s,zend_string * key,zval * val)137 static void php_mail_build_headers_elem(smart_str *s, zend_string *key, zval *val)
138 {
139 	switch(Z_TYPE_P(val)) {
140 		case IS_STRING:
141 			if (php_mail_build_headers_check_field_name(key) != SUCCESS) {
142 				php_error_docref(NULL, E_WARNING, "Header field name (%s) contains invalid chars", ZSTR_VAL(key));
143 				return;
144 			}
145 			if (php_mail_build_headers_check_field_value(val) != SUCCESS) {
146 				php_error_docref(NULL, E_WARNING, "Header field value (%s => %s) contains invalid chars or format", ZSTR_VAL(key), Z_STRVAL_P(val));
147 				return;
148 			}
149 			smart_str_append(s, key);
150 			smart_str_appendl(s, ": ", 2);
151 			smart_str_appends(s, Z_STRVAL_P(val));
152 			smart_str_appendl(s, "\r\n", 2);
153 			break;
154 		case IS_ARRAY:
155 			php_mail_build_headers_elems(s, key, val);
156 			break;
157 		default:
158 			php_error_docref(NULL, E_WARNING, "headers array elements must be string or array (%s)", ZSTR_VAL(key));
159 	}
160 }
161 
162 
php_mail_build_headers_elems(smart_str * s,zend_string * key,zval * val)163 static void php_mail_build_headers_elems(smart_str *s, zend_string *key, zval *val)
164 {
165 	zend_ulong idx;
166 	zend_string *tmp_key;
167 	zval *tmp_val;
168 
169 	(void)(idx);
170 	ZEND_HASH_FOREACH_KEY_VAL(HASH_OF(val), idx, tmp_key, tmp_val) {
171 		if (tmp_key) {
172 			php_error_docref(NULL, E_WARNING, "Multiple header key must be numeric index (%s)", ZSTR_VAL(tmp_key));
173 			continue;
174 		}
175 		if (Z_TYPE_P(tmp_val) != IS_STRING) {
176 			php_error_docref(NULL, E_WARNING, "Multiple header values must be string (%s)", ZSTR_VAL(key));
177 			continue;
178 		}
179 		php_mail_build_headers_elem(s, key, tmp_val);
180 	} ZEND_HASH_FOREACH_END();
181 }
182 
183 
php_mail_build_headers(zval * headers)184 PHPAPI zend_string *php_mail_build_headers(zval *headers)
185 {
186 	zend_ulong idx;
187 	zend_string *key;
188 	zval *val;
189 	smart_str s = {0};
190 
191 	ZEND_ASSERT(Z_TYPE_P(headers) == IS_ARRAY);
192 
193 	ZEND_HASH_FOREACH_KEY_VAL(HASH_OF(headers), idx, key, val) {
194 		if (!key) {
195 			php_error_docref(NULL, E_WARNING, "Found numeric header (" ZEND_LONG_FMT ")", idx);
196 			continue;
197 		}
198 		/* https://tools.ietf.org/html/rfc2822#section-3.6 */
199 		switch(ZSTR_LEN(key)) {
200 			case sizeof("orig-date")-1:
201 				if (!strncasecmp("orig-date", ZSTR_VAL(key), ZSTR_LEN(key))) {
202 					PHP_MAIL_BUILD_HEADER_CHECK("orig-date", s, key, val);
203 				} else {
204 					PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
205 				}
206 				break;
207 			case sizeof("from")-1:
208 				if (!strncasecmp("from", ZSTR_VAL(key), ZSTR_LEN(key))) {
209 					PHP_MAIL_BUILD_HEADER_CHECK("from", s, key, val);
210 				} else {
211 					PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
212 				}
213 				break;
214 			case sizeof("sender")-1:
215 				if (!strncasecmp("sender", ZSTR_VAL(key), ZSTR_LEN(key))) {
216 					PHP_MAIL_BUILD_HEADER_CHECK("sender", s, key, val);
217 				} else {
218 					PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
219 				}
220 				break;
221 			case sizeof("reply-to")-1:
222 				if (!strncasecmp("reply-to", ZSTR_VAL(key), ZSTR_LEN(key))) {
223 					PHP_MAIL_BUILD_HEADER_CHECK("reply-to", s, key, val);
224 				} else {
225 					PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
226 				}
227 				break;
228 			case sizeof("to")-1: /* "to", "cc" */
229 				if (!strncasecmp("to", ZSTR_VAL(key), ZSTR_LEN(key))) {
230 					php_error_docref(NULL, E_WARNING, "Extra header cannot contain 'To' header");
231 					continue;
232 				}
233 				if (!strncasecmp("cc", ZSTR_VAL(key), ZSTR_LEN(key))) {
234 					PHP_MAIL_BUILD_HEADER_CHECK("cc", s, key, val);
235 				} else {
236 					PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
237 				}
238 				break;
239 			case sizeof("bcc")-1:
240 				if (!strncasecmp("bcc", ZSTR_VAL(key), ZSTR_LEN(key))) {
241 					PHP_MAIL_BUILD_HEADER_CHECK("bcc", s, key, val);
242 				} else {
243 					PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
244 				}
245 				break;
246 			case sizeof("message-id")-1: /* "references" */
247 				if (!strncasecmp("message-id", ZSTR_VAL(key), ZSTR_LEN(key))) {
248 					PHP_MAIL_BUILD_HEADER_CHECK("message-id", s, key, val);
249 				} else if (!strncasecmp("references", ZSTR_VAL(key), ZSTR_LEN(key))) {
250 					PHP_MAIL_BUILD_HEADER_CHECK("references", s, key, val);
251 				} else {
252 					PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
253 				}
254 				break;
255 			case sizeof("in-reply-to")-1:
256 				if (!strncasecmp("in-reply-to", ZSTR_VAL(key), ZSTR_LEN(key))) {
257 					PHP_MAIL_BUILD_HEADER_CHECK("in-reply-to", s, key, val);
258 				} else {
259 					PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
260 				}
261 				break;
262 			case sizeof("subject")-1:
263 				if (!strncasecmp("subject", ZSTR_VAL(key), ZSTR_LEN(key))) {
264 					php_error_docref(NULL, E_WARNING, "Extra header cannot contain 'Subject' header");
265 					continue;
266 				}
267 				PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
268 				break;
269 			default:
270 				PHP_MAIL_BUILD_HEADER_DEFAULT(s, key, val);
271 		}
272 	} ZEND_HASH_FOREACH_END();
273 
274 	/* Remove the last \r\n */
275 	if (s.s) s.s->len -= 2;
276 	smart_str_0(&s);
277 
278 	return s.s;
279 }
280 
281 
282 /* {{{ proto int mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]])
283    Send an email message */
PHP_FUNCTION(mail)284 PHP_FUNCTION(mail)
285 {
286 	char *to=NULL, *message=NULL;
287 	char *subject=NULL;
288 	zend_string *extra_cmd=NULL, *str_headers=NULL, *tmp_headers;
289 	zval *headers = NULL;
290 	size_t to_len, message_len;
291 	size_t subject_len, i;
292 	char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
293 	char *to_r, *subject_r;
294 	char *p, *e;
295 
296 	ZEND_PARSE_PARAMETERS_START(3, 5)
297 		Z_PARAM_STRING(to, to_len)
298 		Z_PARAM_STRING(subject, subject_len)
299 		Z_PARAM_STRING(message, message_len)
300 		Z_PARAM_OPTIONAL
301 		Z_PARAM_ZVAL(headers)
302 		Z_PARAM_STR(extra_cmd)
303 	ZEND_PARSE_PARAMETERS_END();
304 
305 	/* ASCIIZ check */
306 	MAIL_ASCIIZ_CHECK(to, to_len);
307 	MAIL_ASCIIZ_CHECK(subject, subject_len);
308 	MAIL_ASCIIZ_CHECK(message, message_len);
309 	if (headers) {
310 		switch(Z_TYPE_P(headers)) {
311 			case IS_STRING:
312 				tmp_headers = zend_string_init(Z_STRVAL_P(headers), Z_STRLEN_P(headers), 0);
313 				MAIL_ASCIIZ_CHECK(ZSTR_VAL(tmp_headers), ZSTR_LEN(tmp_headers));
314 				str_headers = php_trim(tmp_headers, NULL, 0, 2);
315 				zend_string_release_ex(tmp_headers, 0);
316 				break;
317 			case IS_ARRAY:
318 				str_headers = php_mail_build_headers(headers);
319 				break;
320 			default:
321 				php_error_docref(NULL, E_WARNING, "headers parameter must be string or array");
322 				RETURN_FALSE;
323 		}
324 	}
325 	if (extra_cmd) {
326 		MAIL_ASCIIZ_CHECK(ZSTR_VAL(extra_cmd), ZSTR_LEN(extra_cmd));
327 	}
328 
329 	if (to_len > 0) {
330 		to_r = estrndup(to, to_len);
331 		for (; to_len; to_len--) {
332 			if (!isspace((unsigned char) to_r[to_len - 1])) {
333 				break;
334 			}
335 			to_r[to_len - 1] = '\0';
336 		}
337 		for (i = 0; to_r[i]; i++) {
338 			if (iscntrl((unsigned char) to_r[i])) {
339 				/* According to RFC 822, section 3.1.1 long headers may be separated into
340 				 * parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
341 				 * To prevent these separators from being replaced with a space, we use the
342 				 * SKIP_LONG_HEADER_SEP to skip over them. */
343 				SKIP_LONG_HEADER_SEP(to_r, i);
344 				to_r[i] = ' ';
345 			}
346 		}
347 	} else {
348 		to_r = to;
349 	}
350 
351 	if (subject_len > 0) {
352 		subject_r = estrndup(subject, subject_len);
353 		for (; subject_len; subject_len--) {
354 			if (!isspace((unsigned char) subject_r[subject_len - 1])) {
355 				break;
356 			}
357 			subject_r[subject_len - 1] = '\0';
358 		}
359 		for (i = 0; subject_r[i]; i++) {
360 			if (iscntrl((unsigned char) subject_r[i])) {
361 				SKIP_LONG_HEADER_SEP(subject_r, i);
362 				subject_r[i] = ' ';
363 			}
364 		}
365 	} else {
366 		subject_r = subject;
367 	}
368 
369 	if (force_extra_parameters) {
370 		extra_cmd = php_escape_shell_cmd(force_extra_parameters);
371 	} else if (extra_cmd) {
372 		extra_cmd = php_escape_shell_cmd(ZSTR_VAL(extra_cmd));
373 	}
374 
375 	if (php_mail(to_r, subject_r, message, str_headers && ZSTR_LEN(str_headers) ? ZSTR_VAL(str_headers) : NULL, extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)) {
376 		RETVAL_TRUE;
377 	} else {
378 		RETVAL_FALSE;
379 	}
380 
381 	if (str_headers) {
382 		zend_string_release_ex(str_headers, 0);
383 	}
384 
385 	if (extra_cmd) {
386 		zend_string_release_ex(extra_cmd, 0);
387 	}
388 	if (to_r != to) {
389 		efree(to_r);
390 	}
391 	if (subject_r != subject) {
392 		efree(subject_r);
393 	}
394 }
395 /* }}} */
396 
397 
php_mail_log_crlf_to_spaces(char * message)398 void php_mail_log_crlf_to_spaces(char *message) {
399 	/* Find all instances of carriage returns or line feeds and
400 	 * replace them with spaces. Thus, a log line is always one line
401 	 * long
402 	 */
403 	char *p = message;
404 	while ((p = strpbrk(p, "\r\n"))) {
405 		*p = ' ';
406 	}
407 }
408 
php_mail_log_to_syslog(char * message)409 void php_mail_log_to_syslog(char *message) {
410 	/* Write 'message' to syslog. */
411 #ifdef HAVE_SYSLOG_H
412 	php_syslog(LOG_NOTICE, "%s", message);
413 #endif
414 }
415 
416 
php_mail_log_to_file(char * filename,char * message,size_t message_size)417 void php_mail_log_to_file(char *filename, char *message, size_t message_size) {
418 	/* Write 'message' to the given file. */
419 	uint32_t flags = IGNORE_URL_WIN | REPORT_ERRORS | STREAM_DISABLE_OPEN_BASEDIR;
420 	php_stream *stream = php_stream_open_wrapper(filename, "a", flags, NULL);
421 	if (stream) {
422 		php_stream_write(stream, message, message_size);
423 		php_stream_close(stream);
424 	}
425 }
426 
427 
php_mail_detect_multiple_crlf(char * hdr)428 static int php_mail_detect_multiple_crlf(char *hdr) {
429 	/* This function detects multiple/malformed multiple newlines. */
430 
431 	if (!hdr || !strlen(hdr)) {
432 		return 0;
433 	}
434 
435 	/* Should not have any newlines at the beginning. */
436 	/* RFC 2822 2.2. Header Fields */
437 	if (*hdr < 33 || *hdr > 126 || *hdr == ':') {
438 		return 1;
439 	}
440 
441 	while(*hdr) {
442 		if (*hdr == '\r') {
443 			if (*(hdr+1) == '\0' || *(hdr+1) == '\r' || (*(hdr+1) == '\n' && (*(hdr+2) == '\0' || *(hdr+2) == '\n' || *(hdr+2) == '\r'))) {
444 				/* Malformed or multiple newlines. */
445 				return 1;
446 			} else {
447 				hdr += 2;
448 			}
449 		} else if (*hdr == '\n') {
450 			if (*(hdr+1) == '\0' || *(hdr+1) == '\r' || *(hdr+1) == '\n') {
451 				/* Malformed or multiple newlines. */
452 				return 1;
453 			} else {
454 				hdr += 2;
455 			}
456 		} else {
457 			hdr++;
458 		}
459 	}
460 
461 	return 0;
462 }
463 
464 
465 /* {{{ php_mail
466  */
php_mail(char * to,char * subject,char * message,char * headers,char * extra_cmd)467 PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd)
468 {
469 #ifdef PHP_WIN32
470 	int tsm_err;
471 	char *tsm_errmsg = NULL;
472 #endif
473 	FILE *sendmail;
474 	int ret;
475 	char *sendmail_path = INI_STR("sendmail_path");
476 	char *sendmail_cmd = NULL;
477 	char *mail_log = INI_STR("mail.log");
478 	char *hdr = headers;
479 #if PHP_SIGCHILD
480 	void (*sig_handler)() = NULL;
481 #endif
482 
483 #define MAIL_RET(val) \
484 	if (hdr != headers) {	\
485 		efree(hdr);	\
486 	}	\
487 	return val;	\
488 
489 	if (mail_log && *mail_log) {
490 		char *logline;
491 
492 		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);
493 
494 		if (hdr) {
495 			php_mail_log_crlf_to_spaces(logline);
496 		}
497 
498 		if (!strcmp(mail_log, "syslog")) {
499 			php_mail_log_to_syslog(logline);
500 		} else {
501 			/* Add date when logging to file */
502 			char *tmp;
503 			time_t curtime;
504 			zend_string *date_str;
505 			size_t len;
506 
507 
508 			time(&curtime);
509 			date_str = php_format_date("d-M-Y H:i:s e", 13, curtime, 1);
510 			len = spprintf(&tmp, 0, "[%s] %s%s", date_str->val, logline, PHP_EOL);
511 
512 			php_mail_log_to_file(mail_log, tmp, len);
513 
514 			zend_string_free(date_str);
515 			efree(tmp);
516 		}
517 
518 		efree(logline);
519 	}
520 
521 	if (PG(mail_x_header)) {
522 		const char *tmp = zend_get_executed_filename();
523 		zend_string *f;
524 
525 		f = php_basename(tmp, strlen(tmp), NULL, 0);
526 
527 		if (headers != NULL && *headers) {
528 			spprintf(&hdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\n%s", php_getuid(), ZSTR_VAL(f), headers);
529 		} else {
530 			spprintf(&hdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f));
531 		}
532 		zend_string_release_ex(f, 0);
533 	}
534 
535 	if (hdr && php_mail_detect_multiple_crlf(hdr)) {
536 		php_error_docref(NULL, E_WARNING, "Multiple or malformed newlines found in additional_header");
537 		MAIL_RET(0);
538 	}
539 
540 	if (!sendmail_path) {
541 #ifdef PHP_WIN32
542 		/* handle old style win smtp sending */
543 		if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message, NULL, NULL, NULL) == FAILURE) {
544 			if (tsm_errmsg) {
545 				php_error_docref(NULL, E_WARNING, "%s", tsm_errmsg);
546 				efree(tsm_errmsg);
547 			} else {
548 				php_error_docref(NULL, E_WARNING, "%s", GetSMErrorText(tsm_err));
549 			}
550 			MAIL_RET(0);
551 		}
552 		MAIL_RET(1);
553 #else
554 		MAIL_RET(0);
555 #endif
556 	}
557 	if (extra_cmd != NULL) {
558 		spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, extra_cmd);
559 	} else {
560 		sendmail_cmd = sendmail_path;
561 	}
562 
563 #if PHP_SIGCHILD
564 	/* Set signal handler of SIGCHLD to default to prevent other signal handlers
565 	 * from being called and reaping the return code when our child exits.
566 	 * The original handler needs to be restored after pclose() */
567 	sig_handler = (void *)signal(SIGCHLD, SIG_DFL);
568 	if (sig_handler == SIG_ERR) {
569 		sig_handler = NULL;
570 	}
571 #endif
572 
573 #ifdef PHP_WIN32
574 	sendmail = popen_ex(sendmail_cmd, "wb", NULL, NULL);
575 #else
576 	/* Since popen() doesn't indicate if the internal fork() doesn't work
577 	 * (e.g. the shell can't be executed) we explicitly set it to 0 to be
578 	 * sure we don't catch any older errno value. */
579 	errno = 0;
580 	sendmail = popen(sendmail_cmd, "w");
581 #endif
582 	if (extra_cmd != NULL) {
583 		efree (sendmail_cmd);
584 	}
585 
586 	if (sendmail) {
587 #ifndef PHP_WIN32
588 		if (EACCES == errno) {
589 			php_error_docref(NULL, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path);
590 			pclose(sendmail);
591 #if PHP_SIGCHILD
592 			/* Restore handler in case of error on Windows
593 			   Not sure if this applicable on Win but just in case. */
594 			if (sig_handler) {
595 				signal(SIGCHLD, sig_handler);
596 			}
597 #endif
598 			MAIL_RET(0);
599 		}
600 #endif
601 		fprintf(sendmail, "To: %s\n", to);
602 		fprintf(sendmail, "Subject: %s\n", subject);
603 		if (hdr != NULL) {
604 			fprintf(sendmail, "%s\n", hdr);
605 		}
606 		fprintf(sendmail, "\n%s\n", message);
607 		ret = pclose(sendmail);
608 
609 #if PHP_SIGCHILD
610 		if (sig_handler) {
611 			signal(SIGCHLD, sig_handler);
612 		}
613 #endif
614 
615 #ifdef PHP_WIN32
616 		if (ret == -1)
617 #else
618 #if defined(EX_TEMPFAIL)
619 		if ((ret != EX_OK)&&(ret != EX_TEMPFAIL))
620 #elif defined(EX_OK)
621 		if (ret != EX_OK)
622 #else
623 		if (ret != 0)
624 #endif
625 #endif
626 		{
627 			MAIL_RET(0);
628 		} else {
629 			MAIL_RET(1);
630 		}
631 	} else {
632 		php_error_docref(NULL, E_WARNING, "Could not execute mail delivery program '%s'", sendmail_path);
633 #if PHP_SIGCHILD
634 		if (sig_handler) {
635 			signal(SIGCHLD, sig_handler);
636 		}
637 #endif
638 		MAIL_RET(0);
639 	}
640 
641 	MAIL_RET(1); /* never reached */
642 }
643 /* }}} */
644 
645 /* {{{ PHP_MINFO_FUNCTION
646  */
PHP_MINFO_FUNCTION(mail)647 PHP_MINFO_FUNCTION(mail)
648 {
649 	char *sendmail_path = INI_STR("sendmail_path");
650 
651 #ifdef PHP_WIN32
652 	if (!sendmail_path) {
653 		php_info_print_table_row(2, "Internal Sendmail Support for Windows", "enabled");
654 	} else {
655 		php_info_print_table_row(2, "Path to sendmail", sendmail_path);
656 	}
657 #else
658 	php_info_print_table_row(2, "Path to sendmail", sendmail_path);
659 #endif
660 }
661 /* }}} */
662 
663 /*
664  * Local variables:
665  * tab-width: 4
666  * c-basic-offset: 4
667  * End:
668  * vim600: sw=4 ts=4 fdm=marker
669  * vim<600: sw=4 ts=4
670  */
671