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