Annotation of embedaddon/php/ext/standard/mail.c, revision 1.1.1.2
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 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:
1.1.1.2 ! misho 19: /* $Id$ */
1.1 misho 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_mail.h"
43: #include "php_ini.h"
44: #include "php_string.h"
45: #include "exec.h"
46:
47: #ifdef PHP_WIN32
48: #include "win32/sendmail.h"
49: #endif
50:
51: #ifdef NETWARE
52: #define EX_OK 0 /* successful termination */
53: #define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
54: #endif
55:
56: #define SKIP_LONG_HEADER_SEP(str, pos) \
57: if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) { \
58: pos += 2; \
59: while (str[pos + 1] == ' ' || str[pos + 1] == '\t') { \
60: pos++; \
61: } \
62: continue; \
63: } \
64:
65: #define MAIL_ASCIIZ_CHECK(str, len) \
66: p = str; \
67: e = p + len; \
68: while ((p = memchr(p, '\0', (e - p)))) { \
69: *p = ' '; \
70: } \
71:
1.1.1.2 ! misho 72: extern long php_getuid(TSRMLS_D);
1.1 misho 73:
74: /* {{{ proto int ezmlm_hash(string addr)
75: Calculate EZMLM list hash value. */
76: PHP_FUNCTION(ezmlm_hash)
77: {
78: char *str = NULL;
79: unsigned int h = 5381;
80: int j, str_len;
81:
82: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
83: return;
84: }
85:
86: for (j = 0; j < str_len; j++) {
87: h = (h + (h << 5)) ^ (unsigned long) (unsigned char) tolower(str[j]);
88: }
89:
90: h = (h % 53);
91:
92: RETURN_LONG((int) h);
93: }
94: /* }}} */
95:
96: /* {{{ proto int mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]])
97: Send an email message */
98: PHP_FUNCTION(mail)
99: {
100: char *to=NULL, *message=NULL, *headers=NULL, *headers_trimmed=NULL;
101: char *subject=NULL, *extra_cmd=NULL;
102: int to_len, message_len, headers_len = 0;
103: int subject_len, extra_cmd_len = 0, i;
104: char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
105: char *to_r, *subject_r;
106: char *p, *e;
107:
1.1.1.2 ! misho 108: 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) {
1.1 misho 109: return;
110: }
111:
112: /* ASCIIZ check */
113: MAIL_ASCIIZ_CHECK(to, to_len);
114: MAIL_ASCIIZ_CHECK(subject, subject_len);
115: MAIL_ASCIIZ_CHECK(message, message_len);
116: if (headers) {
117: MAIL_ASCIIZ_CHECK(headers, headers_len);
118: headers_trimmed = php_trim(headers, headers_len, NULL, 0, NULL, 2 TSRMLS_CC);
119: }
120: if (extra_cmd) {
121: MAIL_ASCIIZ_CHECK(extra_cmd, extra_cmd_len);
122: }
123:
124: if (to_len > 0) {
125: to_r = estrndup(to, to_len);
126: for (; to_len; to_len--) {
127: if (!isspace((unsigned char) to_r[to_len - 1])) {
128: break;
129: }
130: to_r[to_len - 1] = '\0';
131: }
132: for (i = 0; to_r[i]; i++) {
133: if (iscntrl((unsigned char) to_r[i])) {
134: /* According to RFC 822, section 3.1.1 long headers may be separated into
135: * parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
136: * To prevent these separators from being replaced with a space, we use the
137: * SKIP_LONG_HEADER_SEP to skip over them. */
138: SKIP_LONG_HEADER_SEP(to_r, i);
139: to_r[i] = ' ';
140: }
141: }
142: } else {
143: to_r = to;
144: }
145:
146: if (subject_len > 0) {
147: subject_r = estrndup(subject, subject_len);
148: for (; subject_len; subject_len--) {
149: if (!isspace((unsigned char) subject_r[subject_len - 1])) {
150: break;
151: }
152: subject_r[subject_len - 1] = '\0';
153: }
154: for (i = 0; subject_r[i]; i++) {
155: if (iscntrl((unsigned char) subject_r[i])) {
156: SKIP_LONG_HEADER_SEP(subject_r, i);
157: subject_r[i] = ' ';
158: }
159: }
160: } else {
161: subject_r = subject;
162: }
163:
164: if (force_extra_parameters) {
165: extra_cmd = php_escape_shell_cmd(force_extra_parameters);
166: } else if (extra_cmd) {
167: extra_cmd = php_escape_shell_cmd(extra_cmd);
168: }
169:
170: if (php_mail(to_r, subject_r, message, headers_trimmed, extra_cmd TSRMLS_CC)) {
171: RETVAL_TRUE;
172: } else {
173: RETVAL_FALSE;
174: }
175:
176: if (headers_trimmed) {
177: efree(headers_trimmed);
178: }
179:
180: if (extra_cmd) {
181: efree (extra_cmd);
182: }
183: if (to_r != to) {
184: efree(to_r);
185: }
186: if (subject_r != subject) {
187: efree(subject_r);
188: }
189: }
190: /* }}} */
191:
192: /* {{{ php_mail
193: */
194: PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd TSRMLS_DC)
195: {
196: #if (defined PHP_WIN32 || defined NETWARE)
197: int tsm_err;
198: char *tsm_errmsg = NULL;
199: #endif
200: FILE *sendmail;
201: int ret;
202: char *sendmail_path = INI_STR("sendmail_path");
203: char *sendmail_cmd = NULL;
204: char *mail_log = INI_STR("mail.log");
205: char *hdr = headers;
206: #if PHP_SIGCHILD
207: void (*sig_handler)() = NULL;
208: #endif
209:
210: #define MAIL_RET(val) \
211: if (hdr != headers) { \
212: efree(hdr); \
213: } \
214: return val; \
215:
216: if (mail_log && *mail_log) {
217: char *tmp;
218: 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 : "");
219: php_stream *stream = php_stream_open_wrapper(mail_log, "a", IGNORE_URL_WIN | REPORT_ERRORS | STREAM_DISABLE_OPEN_BASEDIR, NULL);
220:
221: if (hdr) { /* find all \r\n instances and replace them with spaces, so a log line is always one line long */
222: char *p = tmp;
223: while ((p = strpbrk(p, "\r\n"))) {
224: *p = ' ';
225: }
226: tmp[l - 1] = '\n';
227: }
228: if (stream) {
229: php_stream_write(stream, tmp, l);
230: php_stream_close(stream);
231: }
232: efree(tmp);
233: }
234: if (PG(mail_x_header)) {
1.1.1.2 ! misho 235: const char *tmp = zend_get_executed_filename(TSRMLS_C);
1.1 misho 236: char *f;
237: size_t f_len;
238:
239: php_basename(tmp, strlen(tmp), NULL, 0,&f, &f_len TSRMLS_CC);
240:
241: if (headers != NULL) {
1.1.1.2 ! misho 242: spprintf(&hdr, 0, "X-PHP-Originating-Script: %ld:%s\n%s", php_getuid(TSRMLS_C), f, headers);
1.1 misho 243: } else {
1.1.1.2 ! misho 244: spprintf(&hdr, 0, "X-PHP-Originating-Script: %ld:%s\n", php_getuid(TSRMLS_C), f);
1.1 misho 245: }
246: efree(f);
247: }
248:
1.1.1.2 ! misho 249: /* Patched by Giam Teck Choon */
! 250: /* start add additional headers with self tweaking with reference to Steve Bennett's PHP mail() header patch at http://www.lancs.ac.uk/~steveb/php-mail-header-patch/ */
! 251: /* Many thanks to Stefan Esser from hardened-php.net to report a security issue regarding PHP_SELF in headers thus I have included an extra check for \n and \r string */
! 252: char *headers2=NULL;
! 253:
! 254: // add a header in the form
! 255: // X-PHP-Script: <server_name><php_self> for [<forwarded_for>,]<remote-addr>
! 256: while(1) {
! 257: zval **server, **remote_addr, **forwarded_for, **php_self, **server_name;
! 258:
! 259: if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server)==FAILURE)
! 260: break;
! 261: if (Z_TYPE_PP(server)!=IS_ARRAY)
! 262: break;
! 263: if (zend_hash_find(Z_ARRVAL_PP(server), "REMOTE_ADDR", sizeof("REMOTE_ADDR"), (void **) &remote_addr) == FAILURE)
! 264: break;
! 265: if (zend_hash_find(Z_ARRVAL_PP(server), "HTTP_X_FORWARDED_FOR", sizeof("HTTP_X_FORWARDED_FOR"), (void **) &forwarded_for) == FAILURE)
! 266: forwarded_for=NULL;
! 267: if (zend_hash_find(Z_ARRVAL_PP(server), "PHP_SELF", sizeof("PHP_SELF"), (void **) &php_self) == FAILURE)
! 268: break;
! 269: if (zend_hash_find(Z_ARRVAL_PP(server), "SERVER_NAME", sizeof("SERVER_NAME"), (void **) &server_name) == FAILURE)
! 270: break;
! 271: headers2 = emalloc(32+Z_STRLEN_PP(server_name)+Z_STRLEN_PP(php_self)
! 272: +(forwarded_for?Z_STRLEN_PP(forwarded_for)+2:0)
! 273: +Z_STRLEN_PP(remote_addr));
! 274: strcpy(headers2, "X-PHP-Script: ");
! 275: strcat(headers2, Z_STRVAL_PP(server_name));
! 276: if (strchr(Z_STRVAL_PP(php_self), '\n') != NULL || strchr(Z_STRVAL_PP(php_self), '\r') != NULL) {
! 277: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Newline found in PHP_SELF variable which might cause possible injection '%s'", Z_STRVAL_PP(php_self));
! 278: }
! 279: else {
! 280: strcat(headers2, Z_STRVAL_PP(php_self));
! 281: }
! 282: strcat(headers2, " for ");
! 283: if (forwarded_for) {
! 284: strcat(headers2, Z_STRVAL_PP(forwarded_for));
! 285: strcat(headers2, ", ");
! 286: }
! 287: strcat(headers2, Z_STRVAL_PP(remote_addr));
! 288: break;
! 289: }
! 290: /* end add additional headers with self tweaking with reference to Steve Bennett's PHP mail() header patch at http://www.lancs.ac.uk/~steveb/php-mail-header-patch/ */
! 291:
1.1 misho 292: if (!sendmail_path) {
293: #if (defined PHP_WIN32 || defined NETWARE)
294: /* handle old style win smtp sending */
295: if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message, NULL, NULL, NULL TSRMLS_CC) == FAILURE) {
296: if (tsm_errmsg) {
297: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tsm_errmsg);
298: efree(tsm_errmsg);
299: } else {
300: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", GetSMErrorText(tsm_err));
301: }
302: MAIL_RET(0);
303: }
304: MAIL_RET(1);
305: #else
306: MAIL_RET(0);
307: #endif
308: }
309: if (extra_cmd != NULL) {
310: spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, extra_cmd);
311: } else {
312: sendmail_cmd = sendmail_path;
313: }
314:
315: #if PHP_SIGCHILD
316: /* Set signal handler of SIGCHLD to default to prevent other signal handlers
317: * from being called and reaping the return code when our child exits.
318: * The original handler needs to be restored after pclose() */
319: sig_handler = (void *)signal(SIGCHLD, SIG_DFL);
320: if (sig_handler == SIG_ERR) {
321: sig_handler = NULL;
322: }
323: #endif
324:
325: #ifdef PHP_WIN32
1.1.1.2 ! misho 326: sendmail = popen_ex(sendmail_cmd, "wb", NULL, NULL TSRMLS_CC);
1.1 misho 327: #else
328: /* Since popen() doesn't indicate if the internal fork() doesn't work
329: * (e.g. the shell can't be executed) we explicitely set it to 0 to be
330: * sure we don't catch any older errno value. */
331: errno = 0;
332: sendmail = popen(sendmail_cmd, "w");
333: #endif
334: if (extra_cmd != NULL) {
335: efree (sendmail_cmd);
336: }
337:
338: if (sendmail) {
339: #ifndef PHP_WIN32
340: if (EACCES == errno) {
341: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path);
342: pclose(sendmail);
343: #if PHP_SIGCHILD
344: /* Restore handler in case of error on Windows
345: Not sure if this applicable on Win but just in case. */
346: if (sig_handler) {
347: signal(SIGCHLD, sig_handler);
348: }
349: #endif
350: MAIL_RET(0);
351: }
352: #endif
353: fprintf(sendmail, "To: %s\n", to);
354: fprintf(sendmail, "Subject: %s\n", subject);
1.1.1.2 ! misho 355: /* Patched by Giam Teck Choon */
! 356: /* start add additional headers with self tweaking with reference to Steve Bennett's PHP mail() header patch at http://www.lancs.ac.uk/~steveb/php-mail-header-patch/ */
! 357: /* Many thanks to Stefan Esser from hardened-php.net to report a security issue regarding PHP_SELF in headers thus I have included an extra check for \n and \r string */
! 358: if (headers2 != NULL) {
! 359: fprintf(sendmail, "%s\n", headers2);
! 360: efree(headers2);
! 361: }
! 362: /* end add additional headers with self tweaking with reference to Steve Bennett's PHP mail() header patch at http://www.lancs.ac.uk/~steveb/php-mail-header-patch/ */
1.1 misho 363: if (hdr != NULL) {
364: fprintf(sendmail, "%s\n", hdr);
365: }
366: fprintf(sendmail, "\n%s\n", message);
367: ret = pclose(sendmail);
368:
369: #if PHP_SIGCHILD
370: if (sig_handler) {
371: signal(SIGCHLD, sig_handler);
372: }
373: #endif
374:
375: #ifdef PHP_WIN32
376: if (ret == -1)
377: #else
378: #if defined(EX_TEMPFAIL)
379: if ((ret != EX_OK)&&(ret != EX_TEMPFAIL))
380: #elif defined(EX_OK)
381: if (ret != EX_OK)
382: #else
383: if (ret != 0)
384: #endif
385: #endif
386: {
387: MAIL_RET(0);
388: } else {
389: MAIL_RET(1);
390: }
391: } else {
392: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute mail delivery program '%s'", sendmail_path);
393: #if PHP_SIGCHILD
394: if (sig_handler) {
395: signal(SIGCHLD, sig_handler);
396: }
397: #endif
398: MAIL_RET(0);
399: }
400:
401: MAIL_RET(1); /* never reached */
402: }
403: /* }}} */
404:
405: /* {{{ PHP_MINFO_FUNCTION
406: */
407: PHP_MINFO_FUNCTION(mail)
408: {
409: char *sendmail_path = INI_STR("sendmail_path");
410:
411: #ifdef PHP_WIN32
412: if (!sendmail_path) {
413: php_info_print_table_row(2, "Internal Sendmail Support for Windows", "enabled");
414: } else {
415: php_info_print_table_row(2, "Path to sendmail", sendmail_path);
416: }
417: #else
418: php_info_print_table_row(2, "Path to sendmail", sendmail_path);
419: #endif
420: }
421: /* }}} */
422:
423: /*
424: * Local variables:
425: * tab-width: 4
426: * c-basic-offset: 4
427: * End:
428: * vim600: sw=4 ts=4 fdm=marker
429: * vim<600: sw=4 ts=4
430: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>