/[pkg-mixmaster]/trunk/Mix/Src/mail.c
ViewVC logotype

Contents of /trunk/Mix/Src/mail.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 116 - (show annotations) (download)
Mon Jul 29 23:52:00 2002 UTC (10 years, 9 months ago) by weaselp
File MIME type: text/plain
File size: 16146 byte(s)
Make smtp sending similar to local /usr/lib/sendmail sending (wrt header/body seperation; Closes: #482052).
Add X-Loop header on mailbox forwarded messages.
1 /* Mixmaster version 3 -- (C) 1999 Anonymizer Inc.
2
3 Mixmaster may be redistributed and modified under certain conditions.
4 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
5 ANY KIND, either express or implied. See the file COPYRIGHT for
6 details.
7
8 Socket-based mail transport services
9 $Id: mail.c,v 1.4 2002/07/29 23:52:00 weaselp Exp $ */
10
11
12 #include "mix3.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #if defined(UNIX) && defined(USE_SOCK)
18 #include <unistd.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <netdb.h>
25 #include <fcntl.h>
26 #endif
27
28 int sendinfofile(char *name, char *logname, BUFFER *address, BUFFER *header)
29 {
30 FILE *f, *log = NULL;
31 BUFFER *msg, *addr;
32 char line[LINELEN];
33 int ret = -1;
34
35 if (bufeq(address, ANONNAME))
36 return (0); /* don't reply to our own anon messages */
37 f = mix_openfile(name, "r");
38 if (f == NULL)
39 return (-1);
40
41 addr = buf_new();
42 rfc822_addr(address, addr);
43 if (addr->length == 0)
44 buf_set(addr, address), buf_nl(addr);
45
46 if (logname != NULL) {
47 if ((log = mix_openfile(logname, "r+")) != NULL) {
48 /* log recipients to prevent mail loop */
49 while (fgets(line, sizeof(line), log) != NULL)
50 if (strieq(line, addr->data))
51 goto end;
52 } else if ((log = mix_openfile(logname, "w")) == NULL) {
53 errlog(ERRORMSG, "Can't create %s.\n", logname);
54 ret = -1;
55 goto end;
56 }
57 fprintf(log, "%s", addr->data);
58 }
59 msg = buf_new();
60 if (header)
61 buf_cat(msg, header), buf_nl(msg);
62 while (fgets(line, sizeof(line), f) != NULL) {
63 if (streq(line, "DESTINATION-BLOCK\n"))
64 buf_appendf(msg, "destination-block %b", addr);
65 else
66 buf_appends(msg, line);
67 }
68 ret = sendmail(msg, REMAILERNAME, address);
69 fclose(f);
70 buf_free(msg);
71 end:
72 if (log)
73 fclose(log);
74 buf_free(addr);
75 return (ret);
76 }
77
78 int smtpsend(BUFFER *head, BUFFER *message, char *from);
79
80
81 int sendmail_loop(BUFFER *message, char *from, BUFFER *address)
82 {
83 BUFFER *msg;
84 int err;
85
86 msg = buf_new();
87 buf_appendf(msg, "X-Loop: %s\n", REMAILERADDR);
88 buf_cat(msg, message);
89 err = sendmail(msg, from, address);
90 buf_free(msg);
91
92 return(err);
93 };
94
95 int sendmail(BUFFER *message, char *from, BUFFER *address)
96 {
97 /* returns: 0: ok 1: problem, try again -1: failed */
98
99 BUFFER *head, *block;
100 FILE *f;
101 int err = -1;
102
103 head = buf_new();
104
105 block = readdestblk( );
106 if ( !block ) block = buf_new( );
107
108 if (address != NULL &&
109 (address->length == 0 || doblock(address, block, 1) == -1))
110 goto end;
111
112 if (from != NULL) {
113 buf_setf(head, "From: %s", from);
114 hdr_encode(head, 255);
115 buf_nl(head);
116 }
117 if (address != NULL)
118 buf_appendf(head, "To: %b\n", address);
119
120 buf_rewind(message);
121
122 if (SMTPRELAY[0])
123 err = smtpsend(head, message, from);
124 else if (strieq(SENDMAIL, "outfile")) {
125 char path[PATHMAX];
126 FILE *f = NULL;
127 int i;
128
129 for (i = 0; i < 10000; i++) {
130 sprintf(path, "%s%cout%i.txt", POOLDIR, DIRSEP, i);
131 f = fopen(path, "r");
132 if (f)
133 fclose(f);
134 else
135 break;
136 }
137 f = fopen(path, "w");
138 if (f != NULL) {
139 err = buf_write(head, f);
140 err = buf_write(message, f);
141 fclose(f);
142 } else
143 errlog(ERRORMSG, "Can't create %s!\n", path);
144 } else {
145 if (SENDANONMAIL[0] != '\0' && (from == NULL || streq(from, ANONNAME)))
146 f = openpipe(SENDANONMAIL);
147 else
148 f = openpipe(SENDMAIL);
149 if (f != NULL) {
150 err = buf_write(head, f);
151 err = buf_write(message, f);
152 closepipe(f);
153 }
154 }
155 if (err != 0)
156 err = 1; /* error while sending, retry later */
157 end:
158 buf_free(block);
159 buf_free(head);
160 return (err);
161 }
162
163 /* socket communication **********************************************/
164
165 #ifdef USE_SOCK
166 #ifdef WIN32
167 WSADATA w;
168
169 int sock_init()
170 {
171 if (WSAStartup(MAKEWORD(2, 0), &w) != 0) {
172 errlog(ERRORMSG, "Unable to initialize WINSOCK.\n");
173 return 0;
174 }
175 return 1;
176 }
177
178 void sock_exit(void)
179 {
180 WSACleanup();
181 }
182 #endif
183
184 SOCKET opensocket(char *hostname, int port)
185 {
186 struct hostent *hp;
187 struct sockaddr_in server;
188 SOCKET s;
189
190 if ((hp = gethostbyname(hostname)) == NULL)
191 return (INVALID_SOCKET);
192
193 memset((char *) &server, 0, sizeof(server));
194 server.sin_family = AF_INET;
195 server.sin_addr.s_addr = *(unsigned long *) hp->h_addr;
196 server.sin_port = htons((unsigned short) port);
197
198 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
199 if (s != INVALID_SOCKET)
200 if (connect(s, (struct sockaddr *) &server, sizeof(server)) < 0) {
201 closesocket(s);
202 return (INVALID_SOCKET);
203 }
204 return (s);
205 }
206
207 #ifndef WIN32
208 int closesocket(SOCKET s)
209 {
210 return (close(s));
211 }
212 #endif
213
214 int sock_getline(SOCKET s, BUFFER *line)
215 {
216 char c;
217 int ok;
218
219 buf_clear(line);
220 while ((ok = recv(s, &c, 1, 0)) > 0) {
221 if (c == '\n')
222 break;
223 if (c != '\r')
224 buf_appendc(line, c);
225 }
226 if (ok <= 0)
227 return (-1);
228 if (line->length == 0)
229 return (1);
230 return (0);
231 }
232
233 int sock_cat(SOCKET s, BUFFER *b)
234 {
235 int p = 0, n;
236
237 do {
238 n = send(s, b->data, b->length, 0);
239 if (n < 0)
240 return (-1);
241 p += n;
242 } while (p < b->length);
243 return (0);
244 }
245 #else
246 SOCKET opensocket(char *hostname, int port)
247 {
248 return (INVALID_SOCKET);
249 }
250
251 int closesocket(SOCKET s)
252 {
253 return (INVALID_SOCKET);
254 }
255
256 int sock_getline(SOCKET s, BUFFER *line)
257 {
258 return (-1);
259 }
260
261 int sock_cat(SOCKET s, BUFFER *b)
262 {
263 return (-1);
264 }
265 #endif
266
267 /* send messages by SMTP ************************************************/
268
269 static int sock_getsmtp(SOCKET s, BUFFER *line)
270 {
271 int ret;
272
273 do
274 ret = sock_getline(s, line);
275 while (line->length >= 4 && line->data[3] == '-');
276 return (ret);
277 }
278
279 SOCKET smtp_open(void)
280 {
281 int s = INVALID_SOCKET;
282 BUFFER *line;
283
284 #ifdef USE_SOCK
285 if (SMTPRELAY[0] != '\0')
286 s = opensocket(SMTPRELAY, 25);
287 if (s != INVALID_SOCKET) {
288 line = buf_new();
289 sock_getsmtp(s, line);
290 if (line->data[0] != '2') {
291 errlog(ERRORMSG, "SMTP relay not ready. %b\n", line);
292 closesocket(s);
293 s = INVALID_SOCKET;
294 } else {
295 errlog(DEBUGINFO, "Opening SMTP connection.\n");
296 buf_sets(line, "HELO ");
297 if (HELONAME[0])
298 buf_appends(line, HELONAME);
299 else if (strchr(ENVFROM, '@'))
300 buf_appends(line, strchr(ENVFROM, '@') + 1);
301 else {
302 struct sockaddr_in sa;
303 int len = sizeof(sa);
304 struct hostent *hp;
305
306 if (getsockname(s, (struct sockaddr *) &sa, &len) == 0 &&
307 (hp = gethostbyaddr((char *) &sa.sin_addr, sizeof(sa.sin_addr),
308 AF_INET)) != NULL)
309 buf_appends(line, (char *) hp->h_name);
310 else if (strchr(REMAILERADDR, '@'))
311 buf_appends(line, strchr(REMAILERADDR, '@') + 1);
312 else
313 buf_appends(line, SHORTNAME);
314 }
315 buf_appends(line, "\r\n");
316 sock_cat(s, line);
317 sock_getsmtp(s, line);
318 if (line->data[0] != '2') {
319 errlog(ERRORMSG, "SMTP relay refuses HELO: %b\n", line);
320 closesocket(s);
321 s = INVALID_SOCKET;
322 }
323 }
324 buf_free(line);
325 }
326 #endif
327 return (s);
328 }
329
330 int smtp_close(SOCKET s)
331 {
332 BUFFER *line;
333 int ret = -1;
334
335 #ifdef USE_SOCK
336 line = buf_new();
337 buf_sets(line, "QUIT\r\n");
338 sock_cat(s, line);
339 if (sock_getsmtp(s, line) == 0 && line->data[0] == '2') {
340 errlog(DEBUGINFO, "Closing SMTP connection.\n");
341 ret = 0;
342 } else
343 errlog(WARNING, "SMTP quit failed: %b\n", line);
344 closesocket(s);
345 buf_free(line);
346 #endif
347 return (ret);
348 }
349
350 int smtp_send(SOCKET relay, BUFFER *head, BUFFER *message, char *from)
351 {
352 BUFFER *rcpt, *line, *field, *content;
353 int ret = -1;
354
355 #ifdef USE_SOCK
356 line = buf_new();
357 field = buf_new();
358 content = buf_new();
359 rcpt = buf_new();
360
361 while (buf_getheader(head, field, content) == 0)
362 if (bufieq(field, "to"))
363 #ifdef BROKEN_MTA
364 if (!bufifind(rcpt, content->data))
365 /* Do not add the same recipient twice.
366 Needed for brain-dead MTAs. */
367 #endif //BROKEN_MTA
368 rfc822_addr(content, rcpt);
369 buf_rewind(head);
370
371 while (buf_isheader(message) && buf_getheader(message, field, content) == 0) {
372 if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) {
373 #ifdef BROKEN_MTA
374 if (!bufifind(rcpt, content->data))
375 /* Do not add the same recipient twice.
376 Needed for brain-dead MTAs. */
377 #endif //BROKEN_MTA
378 rfc822_addr(content, rcpt);
379 }
380 if (!bufieq(field, "bcc"))
381 buf_appendheader(head, field, content);
382 }
383 buf_nl(head);
384
385 buf_clear(content);
386 if (from) {
387 buf_sets(line, from);
388 rfc822_addr(line, content);
389 buf_chop(content);
390 }
391 if (bufieq(content, REMAILERADDR) || bufieq(content, ANONADDR))
392 buf_clear(content);
393 if (content->length == 0)
394 buf_sets(content, ENVFROM[0] ? ENVFROM : ANONADDR);
395
396 buf_setf(line, "MAIL FROM:<%b>\r\n", content);
397 sock_cat(relay, line);
398 sock_getsmtp(relay, line);
399 if (!line->data[0] == '2') {
400 errlog(ERRORMSG, "SMTP relay does not accept mail: %b\n", line);
401 goto end;
402 }
403 while (buf_getline(rcpt, content) == 0) {
404 buf_setf(line, "RCPT TO:<%b>\r\n", content);
405 sock_cat(relay, line);
406 sock_getsmtp(relay, line);
407 if (bufleft(line, "421")) {
408 errlog(ERRORMSG, "SMTP relay error: %b\n", line);
409 goto end;
410 }
411 }
412
413 buf_sets(line, "DATA\r\n");
414 sock_cat(relay, line);
415 sock_getsmtp(relay, line);
416 if (!bufleft(line, "354")) {
417 errlog(WARNING, "SMTP relay does not accept message: %b\n", line);
418 goto end;
419 }
420 while (buf_getline(head, line) >= 0) {
421 buf_appends(line, "\r\n");
422 if (bufleft(line, ".")) {
423 buf_setf(content, ".%b", line);
424 buf_move(line, content);
425 }
426 sock_cat(relay, line);
427 }
428 while (buf_getline(message, line) >= 0) {
429 buf_appends(line, "\r\n");
430 if (bufleft(line, ".")) {
431 buf_setf(content, ".%b", line);
432 buf_move(line, content);
433 }
434 sock_cat(relay, line);
435 }
436 buf_sets(line, ".\r\n");
437 sock_cat(relay, line);
438 sock_getsmtp(relay, line);
439 if (bufleft(line, "2"))
440 ret = 0;
441 else
442 errlog(WARNING, "SMTP relay will not send message: %b\n", line);
443 end:
444 buf_free(line);
445 buf_free(field);
446 buf_free(content);
447 buf_free(rcpt);
448 #endif
449 return (ret);
450 }
451
452 static SOCKET sendmail_state = INVALID_SOCKET;
453
454 void sendmail_begin(void)
455 {
456 /* begin mail sending session */
457 if (sendmail_state == INVALID_SOCKET)
458 sendmail_state = smtp_open();
459 }
460 void sendmail_end(void)
461 {
462 /* end mail sending session */
463 if (sendmail_state != INVALID_SOCKET) {
464 smtp_close(sendmail_state);
465 sendmail_state = INVALID_SOCKET;
466 }
467 }
468
469 int smtpsend(BUFFER *head, BUFFER *message, char *from)
470 {
471 SOCKET s;
472 int ret = -1;
473
474 if (sendmail_state != INVALID_SOCKET)
475 ret = smtp_send(sendmail_state, head, message, from);
476 else {
477 s = smtp_open();
478 if (s != INVALID_SOCKET) {
479 ret = smtp_send(s, head, message, from);
480 smtp_close(s);
481 }
482 }
483 return (ret);
484 }
485
486 /* retrieve mail with POP3 **********************************************/
487 #ifdef USE_SOCK
488 int pop3_close(SOCKET s);
489
490 #define POP3_ANY 0
491 #define POP3_APOP 1
492 #define POP3_PASS 2
493
494 SOCKET pop3_open(char *user, char *host, char *pass, int auth)
495 {
496 SOCKET server = INVALID_SOCKET;
497 BUFFER *line;
498 int authenticated = 0;
499 char c, md[33];
500
501 line = buf_new();
502 server = opensocket(host, 110);
503 if (server == INVALID_SOCKET)
504 errlog(NOTICE, "Can't connect to POP3 server %s.\n", host);
505 else {
506 sock_getline(server, line);
507 if (!bufleft(line, "+")) {
508 errlog(WARNING, "No POP3 service at %s.\n", host);
509 closesocket(server);
510 server = INVALID_SOCKET;
511 }
512 }
513 if (server != INVALID_SOCKET) {
514 errlog(DEBUGINFO, "Opening POP3 connection to %s.\n", host);
515 do
516 c = buf_getc(line);
517 while (c != '<' && c != -1);
518 while (c != '>' && c != -1) {
519 buf_appendc(line, c);
520 c = buf_getc(line);
521 }
522 if (c == '>' && (auth == POP3_ANY || auth == POP3_APOP)) {
523 buf_appendc(line, c);
524 buf_appends(line, pass);
525 digest_md5(line, line);
526 id_encode(line->data, md);
527 buf_setf(line, "APOP %s %s\r\n", user, md);
528 sock_cat(server, line);
529 sock_getline(server, line);
530 if (bufleft(line, "+"))
531 authenticated = 1;
532 else {
533 errlog(auth == POP3_APOP ? ERRORMSG : NOTICE,
534 "POP3 APOP auth at %s failed: %b\n", host, line);
535 buf_sets(line, "QUIT\r\n");
536 sock_cat(server, line);
537 closesocket(server);
538 server = pop3_open(user, host, pass, POP3_PASS);
539 goto end;
540 }
541 }
542 if (!authenticated) {
543 buf_setf(line, "USER %s\r\n", user);
544 sock_cat(server, line);
545 sock_getline(server, line);
546 if (!bufleft(line, "+"))
547 errlog(ERRORMSG, "POP3 USER command at %s failed: %b\n", host, line);
548 else {
549 buf_setf(line, "PASS %s\r\n", pass);
550 sock_cat(server, line);
551 sock_getline(server, line);
552 if (bufleft(line, "+"))
553 authenticated = 1;
554 else
555 errlog(ERRORMSG, "POP3 auth at %s failed: %b\n", host, line);
556 }
557 }
558 if (!authenticated) {
559 pop3_close(server);
560 closesocket(server);
561 server = INVALID_SOCKET;
562 }
563 }
564 end:
565 buf_free(line);
566 return (server);
567 }
568
569 int pop3_close(SOCKET s)
570 {
571 BUFFER *line;
572 int ret = -1;
573
574 line = buf_new();
575 buf_sets(line, "QUIT\r\n");
576 sock_cat(s, line);
577 sock_getline(s, line);
578 if (bufleft(line, "+")) {
579 ret = 0;
580 errlog(DEBUGINFO, "Closing POP3 connection.\n");
581 } else
582 errlog(ERRORMSG, "POP3 QUIT failed:\n", line->data);
583 buf_free(line);
584 return (ret);
585 }
586
587 int pop3_stat(SOCKET s)
588 {
589 BUFFER *line;
590 int val = -1;
591
592 line = buf_new();
593 buf_sets(line, "STAT\r\n");
594 sock_cat(s, line);
595 sock_getline(s, line);
596 if (bufleft(line, "+"))
597 sscanf(line->data, "+%*s %d", &val);
598 buf_free(line);
599 return (val);
600 }
601
602 int pop3_list(SOCKET s, int n)
603 {
604 BUFFER *line;
605 int val = -1;
606
607 line = buf_new();
608 buf_setf(line, "LIST %d\r\n", n);
609 sock_cat(s, line);
610 sock_getline(s, line);
611 if (bufleft(line, "+"))
612 sscanf(line->data, "+%*s %d", &val);
613 buf_free(line);
614 return (val);
615 }
616
617 int pop3_dele(SOCKET s, int n)
618 {
619 BUFFER *line;
620 int ret = 0;
621
622 line = buf_new();
623 buf_setf(line, "DELE %d\r\n", n);
624 sock_cat(s, line);
625 sock_getline(s, line);
626 if (!bufleft(line, "+"))
627 ret = -1;
628 buf_free(line);
629 return (ret);
630 }
631
632 int pop3_retr(SOCKET s, int n, BUFFER *msg)
633 {
634 BUFFER *line;
635 int ret = -1;
636
637 line = buf_new();
638 buf_clear(msg);
639 buf_setf(line, "RETR %d\r\n", n);
640 sock_cat(s, line);
641 sock_getline(s, line);
642 if (bufleft(line, "+")) {
643 for (;;) {
644 if (sock_getline(s, line) == -1)
645 break;
646 if (bufeq(line, ".")) {
647 ret = 0;
648 break;
649 } else if (bufleft(line, ".")) {
650 buf_append(msg, line->data + 1, line->length - 1);
651 } else
652 buf_cat(msg, line);
653 buf_nl(msg);
654 }
655 }
656 buf_free(line);
657 return (ret);
658 }
659
660 void pop3get(void)
661 {
662 FILE *f;
663 char cfg[LINELEN], user[LINELEN], host[LINELEN], pass[LINELEN], auth[5];
664 SOCKET server;
665 BUFFER *line, *msg;
666 int i = 0, num = 0;
667
668 line = buf_new();
669 msg = buf_new();
670 f = mix_openfile(POP3CONF, "r");
671 if (f != NULL)
672 while (fgets(cfg, sizeof(cfg), f) != NULL) {
673 if (strchr(cfg, '@'))
674 strchr(cfg, '@')[0] = ' ';
675 if (sscanf(cfg, "%127s %127s %127s %4s", user, host, pass, auth) < 3)
676 continue;
677 i = POP3_ANY;
678 if (strileft(auth, "apop"))
679 i = POP3_APOP;
680 if (strileft(auth, "pass"))
681 i = POP3_PASS;
682 server = pop3_open(user, host, pass, i);
683 if (server != INVALID_SOCKET) {
684 num = pop3_stat(server);
685 if (num < 0)
686 errlog(WARNING, "POP3 protocol error at %s.\n", host);
687 else if (num == 0)
688 errlog(DEBUGINFO, "No mail at %s.\n", host);
689 else
690 for (i = 1; i <= num; i++) {
691 if (POP3SIZELIMIT > 0 &&
692 pop3_list(server, i) > POP3SIZELIMIT * 1024) {
693 errlog(WARNING, "Over size message on %s.", host);
694 if (POP3DEL == 1)
695 pop3_dele(server, i);
696 } else {
697 if (pop3_retr(server, i, msg) == 0 &&
698 pool_add(msg, "inf") == 0)
699 pop3_dele(server, i);
700 else {
701 errlog(WARNING, "POP3 error while getting mail from %s.",
702 host);
703 closesocket(server);
704 goto end;
705 }
706 }
707 }
708 pop3_close(server);
709 closesocket(server);
710 }
711 }
712 end:
713 if (f != NULL)
714 fclose(f);
715 buf_free(line);
716 buf_free(msg);
717 }
718 #endif

  ViewVC Help
Powered by ViewVC 1.1.5