This source file includes following definitions.
- PHP_FUNCTION
- PHP_FUNCTION
- php_mail_log_crlf_to_spaces
- php_mail_log_to_syslog
- php_mail_log_to_file
- php_mail_detect_multiple_crlf
- php_mail
- PHP_MINFO_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
31 #if HAVE_SYSEXITS_H
32 #include <sysexits.h>
33 #endif
34 #if HAVE_SYS_SYSEXITS_H
35 #include <sys/sysexits.h>
36 #endif
37
38 #if PHP_SIGCHILD
39 #if HAVE_SIGNAL_H
40 #include <signal.h>
41 #endif
42 #endif
43
44 #include "php_syslog.h"
45 #include "php_mail.h"
46 #include "php_ini.h"
47 #include "php_string.h"
48 #include "exec.h"
49
50 #ifdef PHP_WIN32
51 #include "win32/sendmail.h"
52 #endif
53
54 #ifdef NETWARE
55 #define EX_OK 0
56 #define EX_TEMPFAIL 75
57 #endif
58
59 #define SKIP_LONG_HEADER_SEP(str, pos) \
60 if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) { \
61 pos += 2; \
62 while (str[pos + 1] == ' ' || str[pos + 1] == '\t') { \
63 pos++; \
64 } \
65 continue; \
66 } \
67
68 #define MAIL_ASCIIZ_CHECK(str, len) \
69 p = str; \
70 e = p + len; \
71 while ((p = memchr(p, '\0', (e - p)))) { \
72 *p = ' '; \
73 } \
74
75 extern zend_long php_getuid(void);
76
77
78
79 PHP_FUNCTION(ezmlm_hash)
80 {
81 char *str = NULL;
82 unsigned int h = 5381;
83 size_t j, str_len;
84
85 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) == FAILURE) {
86 return;
87 }
88
89 for (j = 0; j < str_len; j++) {
90 h = (h + (h << 5)) ^ (zend_ulong) (unsigned char) tolower(str[j]);
91 }
92
93 h = (h % 53);
94
95 RETURN_LONG((zend_long) h);
96 }
97
98
99
100
101 PHP_FUNCTION(mail)
102 {
103 char *to=NULL, *message=NULL;
104 char *subject=NULL;
105 zend_string *extra_cmd=NULL, *headers=NULL, *headers_trimmed=NULL;
106 size_t to_len, message_len;
107 size_t subject_len, i;
108 char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
109 char *to_r, *subject_r;
110 char *p, *e;
111
112 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|SS", &to, &to_len, &subject, &subject_len, &message, &message_len, &headers, &extra_cmd) == FAILURE) {
113 return;
114 }
115
116
117 MAIL_ASCIIZ_CHECK(to, to_len);
118 MAIL_ASCIIZ_CHECK(subject, subject_len);
119 MAIL_ASCIIZ_CHECK(message, message_len);
120 if (headers) {
121 MAIL_ASCIIZ_CHECK(ZSTR_VAL(headers), ZSTR_LEN(headers));
122 headers_trimmed = php_trim(headers, NULL, 0, 2);
123 }
124 if (extra_cmd) {
125 MAIL_ASCIIZ_CHECK(ZSTR_VAL(extra_cmd), ZSTR_LEN(extra_cmd));
126 }
127
128 if (to_len > 0) {
129 to_r = estrndup(to, to_len);
130 for (; to_len; to_len--) {
131 if (!isspace((unsigned char) to_r[to_len - 1])) {
132 break;
133 }
134 to_r[to_len - 1] = '\0';
135 }
136 for (i = 0; to_r[i]; i++) {
137 if (iscntrl((unsigned char) to_r[i])) {
138
139
140
141
142 SKIP_LONG_HEADER_SEP(to_r, i);
143 to_r[i] = ' ';
144 }
145 }
146 } else {
147 to_r = to;
148 }
149
150 if (subject_len > 0) {
151 subject_r = estrndup(subject, subject_len);
152 for (; subject_len; subject_len--) {
153 if (!isspace((unsigned char) subject_r[subject_len - 1])) {
154 break;
155 }
156 subject_r[subject_len - 1] = '\0';
157 }
158 for (i = 0; subject_r[i]; i++) {
159 if (iscntrl((unsigned char) subject_r[i])) {
160 SKIP_LONG_HEADER_SEP(subject_r, i);
161 subject_r[i] = ' ';
162 }
163 }
164 } else {
165 subject_r = subject;
166 }
167
168 if (force_extra_parameters) {
169 extra_cmd = php_escape_shell_cmd(force_extra_parameters);
170 } else if (extra_cmd) {
171 extra_cmd = php_escape_shell_cmd(ZSTR_VAL(extra_cmd));
172 }
173
174 if (php_mail(to_r, subject_r, message, headers_trimmed ? ZSTR_VAL(headers_trimmed) : NULL, extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)) {
175 RETVAL_TRUE;
176 } else {
177 RETVAL_FALSE;
178 }
179
180 if (headers_trimmed) {
181 zend_string_release(headers_trimmed);
182 }
183
184 if (extra_cmd) {
185 zend_string_release(extra_cmd);
186 }
187 if (to_r != to) {
188 efree(to_r);
189 }
190 if (subject_r != subject) {
191 efree(subject_r);
192 }
193 }
194
195
196
197 void php_mail_log_crlf_to_spaces(char *message) {
198
199
200
201
202 char *p = message;
203 while ((p = strpbrk(p, "\r\n"))) {
204 *p = ' ';
205 }
206 }
207
208 void php_mail_log_to_syslog(char *message) {
209
210 #ifdef HAVE_SYSLOG_H
211 php_syslog(LOG_NOTICE, "%s", message);
212 #endif
213 }
214
215
216 void php_mail_log_to_file(char *filename, char *message, size_t message_size) {
217
218 uint flags = IGNORE_URL_WIN | REPORT_ERRORS | STREAM_DISABLE_OPEN_BASEDIR;
219 php_stream *stream = php_stream_open_wrapper(filename, "a", flags, NULL);
220 if (stream) {
221 php_stream_write(stream, message, message_size);
222 php_stream_close(stream);
223 }
224 }
225
226
227 static int php_mail_detect_multiple_crlf(char *hdr) {
228
229
230 if (!hdr || !strlen(hdr)) {
231 return 0;
232 }
233
234
235
236 if (*hdr < 33 || *hdr > 126 || *hdr == ':') {
237 return 1;
238 }
239
240 while(*hdr) {
241 if (*hdr == '\r') {
242 if (*(hdr+1) == '\0' || *(hdr+1) == '\r' || (*(hdr+1) == '\n' && (*(hdr+2) == '\0' || *(hdr+2) == '\n' || *(hdr+2) == '\r'))) {
243
244 return 1;
245 } else {
246 hdr += 2;
247 }
248 } else if (*hdr == '\n') {
249 if (*(hdr+1) == '\0' || *(hdr+1) == '\r' || *(hdr+1) == '\n') {
250
251 return 1;
252 } else {
253 hdr += 2;
254 }
255 } else {
256 hdr++;
257 }
258 }
259
260 return 0;
261 }
262
263
264
265
266 PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd)
267 {
268 #if (defined PHP_WIN32 || defined NETWARE)
269 int tsm_err;
270 char *tsm_errmsg = NULL;
271 #endif
272 FILE *sendmail;
273 int ret;
274 char *sendmail_path = INI_STR("sendmail_path");
275 char *sendmail_cmd = NULL;
276 char *mail_log = INI_STR("mail.log");
277 char *hdr = headers;
278 #if PHP_SIGCHILD
279 void (*sig_handler)() = NULL;
280 #endif
281
282 #define MAIL_RET(val) \
283 if (hdr != headers) { \
284 efree(hdr); \
285 } \
286 return val; \
287
288 if (mail_log && *mail_log) {
289 char *tmp;
290 time_t curtime;
291 size_t l;
292 zend_string *date_str;
293
294 time(&curtime);
295 date_str = php_format_date("d-M-Y H:i:s e", 13, curtime, 1);
296
297 l = spprintf(&tmp, 0, "[%s] mail() on [%s:%d]: To: %s -- Headers: %s\n", ZSTR_VAL(date_str), zend_get_executed_filename(), zend_get_executed_lineno(), to, hdr ? hdr : "");
298
299 zend_string_free(date_str);
300
301 if (hdr) {
302 php_mail_log_crlf_to_spaces(tmp);
303 }
304
305 if (!strcmp(mail_log, "syslog")) {
306
307 tmp[l - 1] = 0;
308 php_mail_log_to_syslog(tmp);
309 }
310 else {
311
312 tmp[l - 1] = '\n';
313 php_mail_log_to_file(mail_log, tmp, l);
314 }
315
316 efree(tmp);
317 }
318
319 if (PG(mail_x_header)) {
320 const char *tmp = zend_get_executed_filename();
321 zend_string *f;
322
323 f = php_basename(tmp, strlen(tmp), NULL, 0);
324
325 if (headers != NULL && *headers) {
326 spprintf(&hdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\n%s", php_getuid(), ZSTR_VAL(f), headers);
327 } else {
328 spprintf(&hdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f));
329 }
330 zend_string_release(f);
331 }
332
333 if (hdr && php_mail_detect_multiple_crlf(hdr)) {
334 php_error_docref(NULL, E_WARNING, "Multiple or malformed newlines found in additional_header");
335 MAIL_RET(0);
336 }
337
338 if (!sendmail_path) {
339 #if (defined PHP_WIN32 || defined NETWARE)
340
341 if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message, NULL, NULL, NULL) == FAILURE) {
342 if (tsm_errmsg) {
343 php_error_docref(NULL, E_WARNING, "%s", tsm_errmsg);
344 efree(tsm_errmsg);
345 } else {
346 php_error_docref(NULL, E_WARNING, "%s", GetSMErrorText(tsm_err));
347 }
348 MAIL_RET(0);
349 }
350 MAIL_RET(1);
351 #else
352 MAIL_RET(0);
353 #endif
354 }
355 if (extra_cmd != NULL) {
356 spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, extra_cmd);
357 } else {
358 sendmail_cmd = sendmail_path;
359 }
360
361 #if PHP_SIGCHILD
362
363
364
365 sig_handler = (void *)signal(SIGCHLD, SIG_DFL);
366 if (sig_handler == SIG_ERR) {
367 sig_handler = NULL;
368 }
369 #endif
370
371 #ifdef PHP_WIN32
372 sendmail = popen_ex(sendmail_cmd, "wb", NULL, NULL);
373 #else
374
375
376
377 errno = 0;
378 sendmail = popen(sendmail_cmd, "w");
379 #endif
380 if (extra_cmd != NULL) {
381 efree (sendmail_cmd);
382 }
383
384 if (sendmail) {
385 #ifndef PHP_WIN32
386 if (EACCES == errno) {
387 php_error_docref(NULL, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path);
388 pclose(sendmail);
389 #if PHP_SIGCHILD
390
391
392 if (sig_handler) {
393 signal(SIGCHLD, sig_handler);
394 }
395 #endif
396 MAIL_RET(0);
397 }
398 #endif
399 fprintf(sendmail, "To: %s\n", to);
400 fprintf(sendmail, "Subject: %s\n", subject);
401 if (hdr != NULL) {
402 fprintf(sendmail, "%s\n", hdr);
403 }
404 fprintf(sendmail, "\n%s\n", message);
405 ret = pclose(sendmail);
406
407 #if PHP_SIGCHILD
408 if (sig_handler) {
409 signal(SIGCHLD, sig_handler);
410 }
411 #endif
412
413 #ifdef PHP_WIN32
414 if (ret == -1)
415 #else
416 #if defined(EX_TEMPFAIL)
417 if ((ret != EX_OK)&&(ret != EX_TEMPFAIL))
418 #elif defined(EX_OK)
419 if (ret != EX_OK)
420 #else
421 if (ret != 0)
422 #endif
423 #endif
424 {
425 MAIL_RET(0);
426 } else {
427 MAIL_RET(1);
428 }
429 } else {
430 php_error_docref(NULL, E_WARNING, "Could not execute mail delivery program '%s'", sendmail_path);
431 #if PHP_SIGCHILD
432 if (sig_handler) {
433 signal(SIGCHLD, sig_handler);
434 }
435 #endif
436 MAIL_RET(0);
437 }
438
439 MAIL_RET(1);
440 }
441
442
443
444
445 PHP_MINFO_FUNCTION(mail)
446 {
447 char *sendmail_path = INI_STR("sendmail_path");
448
449 #ifdef PHP_WIN32
450 if (!sendmail_path) {
451 php_info_print_table_row(2, "Internal Sendmail Support for Windows", "enabled");
452 } else {
453 php_info_print_table_row(2, "Path to sendmail", sendmail_path);
454 }
455 #else
456 php_info_print_table_row(2, "Path to sendmail", sendmail_path);
457 #endif
458 }
459
460
461
462
463
464
465
466
467
468