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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 710 - (show annotations) (download)
Wed Jan 21 00:47:21 2004 UTC (9 years, 5 months ago) by rabbi
File MIME type: text/plain
File size: 18749 byte(s)
Updated copyright dates, doc issues, misc fixes.
1 /* Mixmaster version 3.0 -- (C) 1999 - 2004 Anonymizer Inc. and others.
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 Process remailer messages
9 $Id$ */
10
11
12 #include "mix3.h"
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16 #include <ctype.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #ifdef POSIX
20 #include <unistd.h>
21 #else /* end of POSIX */
22 #include <io.h>
23 #endif /* else if not POSIX */
24 #ifndef _MSC
25 #include <dirent.h>
26 #endif /* not _MSC */
27 #include <assert.h>
28
29 int blockrequest(BUFFER *message);
30 int create_dummy_mailin();
31
32 #define REQUESTHELP 100
33 #define REQUESTSTATS 101
34 #define REQUESTKEY 200
35 #define REQUESTCONF 201
36 #define REQUESTOPKEY 202
37 #define REQUESTOTHER 203
38 #define BLOCKREQUEST 666
39 #define DISABLED 99
40
41 #define CPUNKMSG 1
42 #define MIXMSG 2
43
44
45 /** \brief get replies for additional information requests
46 *
47 * \param reply The buffer to store the reply in
48 * \param file The file or name of information a user requested
49 * \returns 0 on success; -1 if a ressource has a valid name
50 * but doesn't exist; 1 if the ressource name isn't valid.
51 *
52 * This function returns additional information that a
53 * user may have requested. One obvious example is help files
54 * in different languages. We don't want to hack the source every
55 * time we or somebody else adds a new language.
56 *
57 * Therefore we add a new directory where the operator may
58 * just create new files (say "remailer-help-de"). If a user
59 * requests that using this (file|ressource) name in the
60 * subject line we respond by sending it.
61 *
62 * Perhaps we should build something that returns an index of
63 * available files (FIXME if done).
64 *
65 * A ressource name needs to start with the string "remailer-"
66 * and must only consist of alphanumerical characters and dashes.
67 * Checking is done by this function and an error returned
68 * if this is violated.
69 */
70 int get_otherrequests_reply(BUFFER *reply, BUFFER *filename)
71 {
72 FILE *f = NULL;
73 int c;
74 int err;
75 BUFFER *path;
76
77 path = buf_new();
78
79 assert(filename);
80 assert(reply);
81
82 buf_rewind(filename);
83 err = bufileft(filename, "remailer-");
84 if (! err) {
85 err = 1;
86 goto end;
87 };
88
89 while ((c = buf_getc(filename)) != -1) {
90 int ok = (c >= 'A' && c <= 'Z') ||
91 (c >= 'a' && c <= 'z') ||
92 (c >= '0' && c <= '9') ||
93 c == '-';
94 if (!ok) {
95 err = 1;
96 goto end;
97 };
98 };
99 buf_rewind(filename);
100
101 buf_appends(path, REQUESTDIR);
102 buf_appends(path, "/");
103 buf_cat(path, filename);
104
105 f = mix_openfile(path->data, "r");
106 if (f == NULL) {
107 err = -1;
108 goto end;
109 };
110
111 buf_read(reply, f);
112 err = 0;
113 end:
114 if (f)
115 fclose(f);
116 buf_free(path);
117 return (err);
118 }
119
120 int mix_decrypt(BUFFER *message)
121 {
122 int type = 0;
123 BUFFER *field, *content;
124 BUFFER *to, *subject, *replyto, *reply;
125 BUFFER *otherrequest;
126 FILE *f;
127 BUFFER *block;
128 int err = 0;
129 int quoted_printable = 0; /* is this message quoted printable encoded */
130
131 mix_init(NULL);
132 field = buf_new();
133 content = buf_new();
134 to = buf_new();
135 replyto = buf_new();
136 reply = buf_new();
137 block = buf_new();
138 subject = buf_new();
139 otherrequest = buf_new();
140 buf_sets(subject, "Subject: Re: your mail");
141
142 buf_rewind(message);
143
144 f = mix_openfile(SOURCEBLOCK, "r");
145 if (f != NULL) {
146 buf_read(block, f);
147 fclose(f);
148 }
149 for (;;) {
150 err = buf_getheader(message, field, content);
151 if (err == 1) {
152 /* "::" marks for additional header lines */
153 while (buf_lookahead(message, field) == 1)
154 buf_getheader(message, field, content);
155 if (isline(field, HDRMARK))
156 continue;
157 else
158 goto hdrend;
159 }
160 if (err == -1)
161 goto hdrend;
162
163 if ((bufieq(field, "from") || bufieq(field, "sender") || bufieq(field,"received")) &&
164 doblock(content, block, 1) != 0)
165 goto end;
166
167 if (bufieq(field, "to"))
168 buf_cat(to, content);
169 else if (bufieq(field, "from") && replyto->length == 0)
170 /* reply to From address if no Reply-To header present */
171 buf_set(replyto, content);
172 else if (bufieq(field, "reply-to"))
173 buf_set(replyto, content);
174 else if (MIX && bufieq(field, "remailer-type") &&
175 bufileft(content, "mixmaster"))
176 type = MIXMSG;
177 else if (bufieq(field, "subject")) {
178 if (bufieq(content, "help") || bufieq(content, "remailer-help"))
179 type = REQUESTHELP;
180 else if (bufieq(content, "remailer-stats"))
181 type = REQUESTSTATS;
182 else if (bufieq(content, "remailer-key"))
183 type = REQUESTKEY;
184 else if (bufieq(content, "remailer-adminkey"))
185 type = REQUESTOPKEY;
186 else if (bufieq(content, "remailer-conf"))
187 type = REQUESTCONF;
188 else if (bufileft(content, "remailer-")) {
189 type = REQUESTOTHER;
190 buf_set(otherrequest, content);
191 } else if (bufileft(content, "destination-block"))
192 type = BLOCKREQUEST;
193 else {
194 buf_sets(subject, "Subject: ");
195 if (!bufileft(content, "re:"))
196 buf_appends(subject, "Re: ");
197 buf_cat(subject, content);
198 }
199 } else if (bufieq(field, "test-to") || bufieq(field, "encrypted") ||
200 bufieq(field, "anon-to") ||
201 bufieq(field, "request-remailing-to") ||
202 bufieq(field, "remail-to") || bufieq(field, "anon-post-to") ||
203 bufieq(field, "post-to") || bufieq(field, "anon-send-to") ||
204 bufieq(field, "send-to") || bufieq(field, "remix-to") ||
205 bufieq(field, "encrypt-to"))
206 type = CPUNKMSG;
207 else if (bufieq(field, "content-transfer-encoding")
208 && bufieq(content, "quoted-printable")) {
209 quoted_printable = 1;
210 }
211
212 }
213 hdrend:
214 if (quoted_printable)
215 qp_decode_message(message);
216
217 if (type > 0 && REMAIL == 0)
218 type = DISABLED;
219 switch (type) {
220 case REQUESTHELP:
221 if (sendinfofile(HELPFILE, NULL, replyto, NULL) == -1)
222 errlog(WARNING, "No help file available.\n");
223 break;
224 case REQUESTKEY:
225 err = key(reply);
226 if (err == 0)
227 err = sendmail(reply, REMAILERNAME, replyto);
228 break;
229 case REQUESTOPKEY:
230 err = adminkey(reply);
231 if (err == 0)
232 err = sendmail(reply, REMAILERNAME, replyto);
233 break;
234 case REQUESTSTATS:
235 err = stats(reply);
236 if (err == 0)
237 err = sendmail(reply, REMAILERNAME, replyto);
238 break;
239 case REQUESTCONF:
240 err = conf(reply);
241 if (err == 0)
242 err = sendmail(reply, REMAILERNAME, replyto);
243 break;
244 case REQUESTOTHER:
245 err = get_otherrequests_reply(reply, otherrequest);
246 if (err == 0)
247 err = sendmail(reply, REMAILERNAME, replyto);
248 break;
249 case CPUNKMSG:
250 err = t1_decrypt(message);
251 if (err != 0) {
252 errlog(LOG, "Invalid type 1 message from %b\n", replyto);
253 sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
254 logmail(err == -2 ? MAILUSAGE : MAILERROR, message);
255 } else
256 create_dummy_mailin();
257 break;
258 case MIXMSG:
259 err = t2_decrypt(message);
260 if (err == -1) {
261 errlog(LOG, "Invalid type 2 message from %b\n", replyto);
262 sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
263 logmail(MAILERROR, message);
264 } else
265 create_dummy_mailin();
266 break;
267 case BLOCKREQUEST:
268 blockrequest(message);
269 logmail(MAILBLOCK, message);
270 break;
271 case DISABLED:
272 errlog(ERRORMSG, "Remailer is disabled.\n");
273 buf_sets(reply, "Subject: remailer error\n\nThe remailer is disabled.\n");
274 sendmail(reply, REMAILERNAME, replyto);
275 logmail(MAILERROR, message);
276 break;
277 default:
278 if (strifind
279 (replyto->data, "mailer-daemon")) {
280 errlog(LOG, "Bounce mail from %b\n", replyto);
281 logmail(MAILBOUNCE, message);
282 } else if (bufifind(to, REMAILERADDR) && blockrequest(message))
283 logmail(MAILBLOCK, message);
284 else if (!AUTOREPLY)
285 logmail(MAILBOX, message);
286 else if (bufifind(to, REMAILERADDR)) {
287 errlog(LOG, "Non-remailer message from %b\n", replyto);
288 sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
289 logmail(MAILUSAGE, message);
290 } else if (bufifind(to, COMPLAINTS)) {
291 errlog(WARNING, "Abuse complaint from %b\n", replyto);
292 sendinfofile(ABUSEFILE, NULL, replyto, subject);
293 logmail(MAILABUSE, message);
294 } else if (ANONADDR[0] && bufifind(to, ANONADDR)) {
295 errlog(LOG, "Reply to anonymous message from %b\n", replyto);
296 sendinfofile(REPLYFILE, NULL, replyto, subject);
297 logmail(MAILANON, message);
298 } else {
299 errlog(DEBUGINFO, "Mail from %b\n", replyto);
300 logmail(MAILBOX, message);
301 }
302 err = 1;
303 }
304 end:
305 buf_free(field);
306 buf_free(content);
307 buf_free(to);
308 buf_free(replyto);
309 buf_free(reply);
310 buf_free(block);
311 buf_free(subject);
312 buf_free(otherrequest);
313 return (err);
314 }
315
316 int create_dummy_mailin()
317 {
318 while (rnd_number(100) < INDUMMYP) {
319 errlog(DEBUGINFO, "Generating dummy message with incoming mail.\n");
320 if (mix_encrypt(MSG_NULL, NULL, NULL, 1, NULL) == -1)
321 return -1;
322 }
323 return 0;
324 }
325
326 int t2_decrypt(BUFFER *in)
327 {
328 int err = 0;
329 BUFFER *msg;
330
331 msg = buf_new();
332 do {
333 err = mix_dearmor(in, msg);
334 if (err != -1) {
335 err = mix2_decrypt(msg);
336 }
337 }
338 while (in->ptr + 1000 < in->length); /* accept several packets in one message */
339
340 buf_free(msg);
341 return (err);
342 }
343
344 int mix_pool(BUFFER *msg, int type, long latent)
345 {
346 char path[PATHMAX], pathtmp[PATHMAX];
347 FILE *f;
348 int err = -1;
349
350 f = pool_new(latent > 0 ? "lat" : "msg", pathtmp, path);
351 if (f != NULL) {
352 if (latent > 0)
353 fprintf(f, "%d %ld\n", type, latent + time(NULL));
354 else
355 fprintf(f, "%d 0\n", type);
356 err = buf_write_sync(msg, f);
357 }
358 if (err == 0) {
359 rename(pathtmp, path);
360 errlog(DEBUGINFO, "Added message to pool.\n");
361 }
362 return (err);
363 }
364
365 int pool_packetfile(char *fname, BUFFER *mid, int packetnum)
366 /* create a filename */
367 {
368 #ifdef SHORTNAMES
369 sprintf(fname, "%s%cp%02x%02x%02x%01x.%02x", POOLDIR, DIRSEP,
370 mid->data[0], mid->data[1], mid->data[2], mid->data[3] & 15,
371 packetnum);
372 #else /* end of SHORTNAMES */
373 sprintf(fname, "%s%cp%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP,
374 packetnum, mid->data[0], mid->data[1], mid->data[2], mid->data[3],
375 mid->data[4], mid->data[5] & 15);
376 #endif /* else if not SHORTNAMES */
377 return (0);
378 }
379
380 void pool_packetexp(void)
381 {
382 char *path;
383 DIR *d;
384 struct dirent *e;
385 struct stat sb;
386
387 d = opendir(POOLDIR);
388 errlog(DEBUGINFO, "Checking for old parts.\n");
389 if (d != NULL)
390 for (;;) {
391 e = readdir(d);
392 if (e == NULL)
393 break;
394 if (e->d_name[0] == 'p' || e->d_name[0] == 'e' || e->d_name[0] == 't') {
395 path=malloc(strlen(POOLDIR)+strlen(e->d_name)+strlen(DIRSEPSTR)+1);
396 if (path) {
397 strcpy(path, POOLDIR);
398 strcat(path, DIRSEPSTR);
399 strcat(path, e->d_name);
400 if (stat(path, &sb) == 0 && time(NULL) - sb.st_mtime > PACKETEXP) {
401 if (e->d_name[0] == 'p') {
402 errlog(NOTICE, "Expiring incomplete partial message %s.\n",
403 e->d_name);
404 }
405 else if (e->d_name[0] == 'e') {
406 errlog(NOTICE, "Expiring old error message %s.\n",
407 e->d_name);
408 }
409 else if (e->d_name[0] == 't') {
410 errlog(NOTICE, "Expiring moldy temporary message %s.\n",
411 e->d_name);
412 }
413 unlink(path);
414 }
415 free(path);
416 }
417 }
418 }
419 closedir(d);
420 }
421
422 void logmail(char *mailbox, BUFFER *message)
423 {
424 time_t t;
425 struct tm *tc;
426 char line[LINELEN];
427
428 /* mailbox is "|program", "user@host", "stdout", "Maildir/" or "filename" */
429 buf_rewind(message);
430 if (mailbox[0] == '\0') /* default action */
431 mailbox = MAILBOX;
432 if (strieq(mailbox, "stdout"))
433 buf_write(message, stdout);
434 else if (mailbox[0] == '|') {
435 FILE *p;
436
437 errlog(DEBUGINFO, "Piping message to %s.\n", mailbox + 1);
438 p = openpipe(mailbox + 1);
439 if (p != NULL) {
440 buf_write(message, p);
441 closepipe(p);
442 }
443 } else if (strchr(mailbox, '@')) {
444 BUFFER *field, *content;
445
446 field = buf_new();
447 content = buf_new();
448 while (buf_getheader(message, field, content) == 0)
449 if (bufieq(field, "x-loop") && bufifind(content, REMAILERADDR)) {
450 errlog(WARNING, "Loop detected! Message not sent to %s.\n", mailbox);
451 goto isloop;
452 }
453 buf_sets(content, mailbox);
454 sendmail_loop(message, NULL, content);
455 isloop:
456 buf_free(field);
457 buf_free(content);
458 } else if (mailbox[strlen(mailbox)-1] == DIRSEP) {
459 /* the user is requesting Maildir delivery */
460 if(maildirWrite(mailbox, message, 1) != 0) {
461 errlog(ERRORMSG, "Can't write to maildir %s\n", mailbox);
462 return;
463 }
464 } else {
465 FILE *mbox;
466
467 mbox = mix_openfile(mailbox, "a");
468 if (mbox == NULL) {
469 errlog(ERRORMSG, "Can't write to mail folder %s\n", mailbox);
470 return;
471 }
472 lock(mbox);
473 if (!bufileft(message, "From ")) {
474 t = time(NULL);
475 tc = localtime(&t);
476 strftime(line, LINELEN, "From Mixmaster %a %b %d %H:%M:%S %Y\n", tc);
477 fprintf(mbox, line);
478 }
479 buf_write(message, mbox);
480 fprintf(mbox, "\n\n");
481 unlock(mbox);
482 fclose(mbox);
483 }
484 }
485
486 int blockrequest(BUFFER *message)
487 {
488 int request = 0, num, i;
489 BUFFER *from, *line, *field, *content, *addr, *remailer_addr, *copy_addr;
490 REMAILER remailer[MAXREM];
491 FILE *f;
492 char *destblklst = (char *)malloc( strlen(DESTBLOCK)+1 );
493 char *destblk;
494
495 from = buf_new();
496 line = buf_new();
497 field = buf_new();
498 content = buf_new();
499 addr = buf_new();
500 remailer_addr = buf_new();
501 copy_addr = buf_new();
502
503 if (destblklst == NULL) {
504 errlog(ERRORMSG, "Can't malloc %n bytes for destblklst.\n", strlen(DESTBLOCK)+1);
505 goto end;
506 };
507
508 buf_rewind(message);
509 while (buf_getheader(message, field, content) == 0)
510 if (bufieq(field, "from"))
511 buf_set(from, content);
512 else if (bufieq(field, "subject"))
513 buf_cat(message, content);
514 /* Append the subject to the message body so destination block requests
515 in the subject line work too (we process the body a few lines down) */
516 while (buf_getline(message, line) != -1)
517 if (bufifind(line, "destination-block")) {
518 buf_clear(addr);
519 request = 1;
520 {
521 int c = 0;
522
523 while (!strileft(line->data + line->ptr, "block"))
524 line->ptr++;
525 while (c != ' ' && c != -1)
526 c = tolower(buf_getc(line));
527 while (c == ' ')
528 c = buf_getc(line);
529 if (c != -1)
530 do {
531 buf_appendc(addr, c);
532 c = buf_getc(line);
533 } while (c > ' ');
534 }
535 if (addr->length == 0) {
536 rfc822_addr (from, addr);
537 buf_chop(addr);
538 }
539 /* Check whether somebody wants us to block ourselves */
540 buf_set(copy_addr, addr);
541 buf_sets(remailer_addr, REMAILERADDR);
542 if (doblock(remailer_addr, copy_addr, 1)) {
543 errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
544 request = 2;
545 goto end;
546 }
547 /* Check if some evil person tries to block a known type II remailer */
548 num = mix2_rlist(remailer, NULL);
549 for (i = 0; i < num; i++) {
550 buf_sets(remailer_addr, remailer[i].addr);
551 if (doblock(remailer_addr, copy_addr, 1)) {
552 errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
553 request = 2;
554 goto end;
555 }
556 }
557 /* Check if some evil person tries to block a known type I remailer */
558 num = t1_rlist(remailer, NULL);
559 for (i = 0; i < num; i++) {
560 buf_sets(remailer_addr, remailer[i].addr);
561 if (doblock(remailer_addr, copy_addr, 1)) {
562 errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
563 request = 2;
564 goto end;
565 }
566 }
567
568 if (buf_ieq(addr, from))
569 errlog(NOTICE, "Blocking request for %b\n", addr);
570 else
571 errlog(NOTICE, "Blocking request for %b from %b\n", addr, from);
572 if (AUTOBLOCK) {
573 buf_clear(line);
574 rfc822_addr(addr, line);
575 if (line->length == 0) {
576 errlog(LOG, "Nothing to block after rfc822_addr().\n");
577 } else
578 if (bufleft(line, "/")) {
579 errlog(LOG, "Ignoring blocking request: %b is a regex.\n", addr);
580 } else {
581 if (strchr(line->data, '@') && strchr(strchr(line->data, '@'), '.')) {
582 strcpy( destblklst, DESTBLOCK );
583 destblk = strtok( destblklst, " " );
584 f = mix_openfile( destblk, "a" );
585 if (f != NULL) {
586 lock(f);
587
588 buf_chop(line);
589 sendinfofile(BLOCKFILE, NULL, line, NULL);
590 if (line->length) {
591 fprintf(f, "%s\n", line->data);
592 } else
593 errlog(NOTICE, "%b already blocked.\n", addr);
594 unlock(f);
595 fclose(f);
596 } else
597 errlog(ERRORMSG, "Can't write to %s.\n", DESTBLOCK);
598 } else
599 errlog(WARNING, "Invalid address not added to %s: %b\n", DESTBLOCK,
600 addr);
601 }
602 }
603 }
604
605 end:
606 free( destblklst );
607 buf_free(from);
608 buf_free(line);
609 buf_free(field);
610 buf_free(content);
611 buf_free(addr);
612 buf_free(remailer_addr);
613 buf_free(copy_addr);
614
615 return (request);
616 }
617
618
619 int idexp(void)
620 {
621 FILE *f;
622 long now, then;
623 LOCK *i;
624 idlog_t idbuf;
625 long fpi = sizeof(idlog_t), fpo = sizeof(idlog_t);
626
627 if (IDEXP == 0)
628 return (0);
629
630 f = mix_openfile(IDLOG, "rb+");
631 if (f == NULL)
632 return (-1);
633 i = lockfile(IDLOG);
634 now = time(NULL);
635 if (fread(&idbuf, 1, sizeof(idlog_t), f) != sizeof(idlog_t)) { /* replace first line */
636 fclose(f);
637 unlockfile(i);
638 return (-1);
639 }
640 then = idbuf.time;
641 memset(idbuf.id,0,sizeof(idbuf.id));
642 idbuf.time = now - IDEXP;
643 fseek(f,0,SEEK_SET);
644 fwrite(&idbuf,1,sizeof(idlog_t),f);
645 fseek(f,fpi,SEEK_SET); /* this fseek does nothing, but MSVC CRT happilly reads past EOF (!!!) if we do not fseek here :-/ */
646 while (fread(&idbuf, 1, sizeof(idlog_t), f) == sizeof(idlog_t)) {
647 fpi+=sizeof(idlog_t);
648 then = idbuf.time;
649 if (now - then < IDEXP &&
650 now - then > - SECONDSPERDAY * 180 )
651 /* also expire packets that are dated more than half a year in the future.
652 * That way we get rid of invalid packets introduced by the switch to a
653 * binary id.log. */
654 {
655 fseek(f,fpo,SEEK_SET);
656 fwrite(&idbuf,1,sizeof(idlog_t),f);
657 fpo += sizeof(idlog_t);
658 fseek(f,fpi,SEEK_SET);
659 }
660 }
661 #ifdef _MSC
662 chsize(fileno(f),fpo);
663 #else /* end of _MSC */
664 ftruncate(fileno(f),fpo);
665 #endif /* else if not _MSC */
666 fclose(f);
667 unlockfile(i);
668 return (0);
669 }
670
671
672 int pgpmaxexp(void)
673 {
674 FILE *f;
675 BUFFER *b;
676 long now, then;
677 LOCK *i;
678 char temp[LINELEN];
679
680 f = mix_openfile(PGPMAXCOUNT, "rb+");
681 if (f == NULL)
682 return (-1);
683 i = lockfile(PGPMAXCOUNT);
684 b = buf_new();
685 now = time(NULL);
686
687 while (fgets(temp, sizeof(temp), f) != NULL)
688 if (sscanf(temp, "%ld", &then) &&
689 then >= now - SECONDSPERDAY)
690 buf_appends(b, temp);
691
692 fseek(f,0,SEEK_SET);
693
694 buf_write(b, f);
695
696 #ifdef _MSC
697 chsize(fileno(f),b->length);
698 #else /* end of _MSC */
699 ftruncate(fileno(f),b->length);
700 #endif /* else if not _MSC */
701
702 fclose(f);
703 unlockfile(i);
704 buf_free(b);
705 return (0);
706 }

Properties

Name Value
svn:keywords Id

  ViewVC Help
Powered by ViewVC 1.1.5