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

  ViewVC Help
Powered by ViewVC 1.1.5