/[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 332 - (show annotations) (download)
Wed Oct 9 20:53:32 2002 UTC (10 years, 7 months ago) by weaselp
File MIME type: text/plain
File size: 14726 byte(s)
Whitespace cleanup:
for i in *.c; do cp -a $i $i.orig; sed -e 's/^        /<TAB>/' $i.orig > $i; rm $i.orig; done
for i in *.c *.h; do cp -a $i $i.orig; sed -e 's/[ <TAB>]*$//' $i.orig > $i; rm $i.orig; done
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 $Id: rem.c,v 1.30 2002/10/09 20:53:31 weaselp Exp $ */
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 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 int quoted_printable = 0; /* is this message quoted printable encoded */
52
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 type = REQUESTOPKEY;
107 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 bufieq(field, "send-to") || bufieq(field, "remix-to") ||
123 bufieq(field, "encrypt-to"))
124 type = CPUNKMSG;
125 else if (bufieq(field, "content-transfer-encoding")
126 && bufieq(content, "quoted-printable")) {
127 quoted_printable = 1;
128 }
129
130 }
131 hdrend:
132 if (quoted_printable)
133 qp_decode_message(message);
134
135 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 } else
169 create_dummy_mailin();
170 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 } else
178 create_dummy_mailin();
179 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 int create_dummy_mailin()
229 {
230 while (rnd_number(100) < INDUMMYP) {
231 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 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 err = buf_write_sync(msg, f);
272 }
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 sprintf(fname, "%s%cp%02x%02x%02x%01x.%02x", POOLDIR, DIRSEP,
285 mid->data[0], mid->data[1], mid->data[2], mid->data[3] & 15,
286 packetnum);
287 #else /* end of SHORTNAMES */
288 sprintf(fname, "%s%cp%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP,
289 packetnum, mid->data[0], mid->data[1], mid->data[2], mid->data[3],
290 mid->data[4], mid->data[5] & 15);
291 #endif /* else if not SHORTNAMES */
292 return (0);
293 }
294
295 void pool_packetexp(void)
296 {
297 char *path;
298 DIR *d;
299 struct dirent *e;
300 struct stat sb;
301
302 d = opendir(POOLDIR);
303 errlog(DEBUGINFO, "Checking for old parts.\n");
304 if (d != NULL)
305 for (;;) {
306 e = readdir(d);
307 if (e == NULL)
308 break;
309 if (e->d_name[0] == 'p' || e->d_name[0] == 'e' || e->d_name[0] == 't') {
310 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 }
332 }
333 }
334 closedir(d);
335 }
336
337 void logmail(char *mailbox, BUFFER *message)
338 {
339 time_t t;
340 struct tm *tc;
341 char line[LINELEN];
342
343 /* mailbox is "|program", "user@host", "stdout", "Maildir/" or "filename" */
344 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 errlog(DEBUGINFO, "Piping message to %s.\n", mailbox + 1);
353 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 sendmail_loop(message, NULL, content);
370 isloop:
371 buf_free(field);
372 buf_free(content);
373 } else if (mailbox[strlen(mailbox)-1] == DIRSEP) {
374 /* 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 } 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 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 buf_write(message, mbox);
395 fprintf(mbox, "\n");
396 unlock(mbox);
397 fclose(mbox);
398 }
399 }
400
401 int blockrequest(BUFFER *message)
402 {
403 int request = 0;
404 BUFFER *from, *line, *field, *content, *addr;
405 FILE *f;
406 char *destblklst = (char *)malloc( strlen(DESTBLOCK)+1 );
407 char *destblk;
408
409 from = buf_new();
410 line = buf_new();
411 field = buf_new();
412 content = buf_new();
413 addr = buf_new();
414
415 buf_rewind(message);
416 while (buf_getheader(message, field, content) == 0)
417 if (bufieq(field, "from"))
418 buf_set(from, content);
419 else if (bufieq(field, "subject"))
420 buf_cat(message, content);
421 /* Append the subject to the message body so destination block requests
422 in the subject line work too (we process the body a few lines down) */
423 while (buf_getline(message, line) != -1)
424 if (bufifind(line, "destination-block")) {
425 buf_clear(addr);
426 request = 1;
427 {
428 int c = 0;
429
430 while (!strileft(line->data + line->ptr, "block"))
431 line->ptr++;
432 while (c != ' ' && c != -1)
433 c = tolower(buf_getc(line));
434 while (c == ' ')
435 c = buf_getc(line);
436 if (c != -1)
437 do {
438 buf_appendc(addr, c);
439 c = buf_getc(line);
440 } while (c > ' ');
441 }
442 if (addr->length == 0) {
443 rfc822_addr (from, addr);
444 buf_chop(addr);
445 }
446 if (bufieq(addr, REMAILERADDR)) {
447 errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
448 return (2);
449 }
450 if (buf_ieq(addr, from))
451 errlog(NOTICE, "Blocking request for %b\n", addr);
452 else
453 errlog(NOTICE, "Blocking request for %b from %b\n", addr, from);
454 if (AUTOBLOCK) {
455 buf_clear(line);
456 rfc822_addr(addr, line);
457 if (line->length == 0) {
458 errlog(LOG, "Nothing to block after rfc822_addr().\n");
459 } else
460 if (bufleft(line, "/")) {
461 errlog(LOG, "Ignoring blocking request: %b is a regex.\n", addr);
462 } else {
463 if (strchr(line->data, '@') && strchr(strchr(line->data, '@'), '.')) {
464 strcpy( destblklst, DESTBLOCK );
465 destblk = strtok( destblklst, " " );
466 f = mix_openfile( destblk, "a" );
467 free( destblklst );
468 if (f != NULL) {
469 lock(f);
470
471 buf_chop(line);
472 sendinfofile(BLOCKFILE, NULL, line, NULL);
473 if (line->length) {
474 fprintf(f, "%s\n", line->data);
475 } else
476 errlog(NOTICE, "%b already blocked.\n", addr);
477 unlock(f);
478 fclose(f);
479 } else
480 errlog(ERRORMSG, "Can't write to %s.\n", DESTBLOCK);
481 } else
482 errlog(WARNING, "Invalid address not added to %s: %b\n", DESTBLOCK,
483 addr);
484 }
485 }
486 }
487 return (request);
488 }
489
490
491 int idexp(void)
492 {
493 FILE *f;
494 BUFFER *b;
495 long now, then;
496 LOCK *i;
497 idlog_t idbuf;
498 long fpi = sizeof(idlog_t), fpo = sizeof(idlog_t);
499
500 if (IDEXP == 0)
501 return (0);
502
503 b = buf_new();
504 f = mix_openfile(IDLOG, "rb+");
505 if (f == NULL)
506 return (-1);
507 i = lockfile(IDLOG);
508 now = time(NULL);
509 if (fread(&idbuf, 1, sizeof(idlog_t), f) != sizeof(idlog_t)) { /* replace first line */
510 fclose(f);
511 unlockfile(i);
512 return (-1);
513 }
514 then = idbuf.time;
515 memset(idbuf.id,0,sizeof(idbuf.id));
516 idbuf.time = now - IDEXP;
517 fseek(f,0,SEEK_SET);
518 fwrite(&idbuf,1,sizeof(idlog_t),f);
519 fseek(f,fpi,SEEK_SET); /* this fseek does nothing, but MSVC CRT happilly reads past EOF (!!!) if we do not fseek here :-/ */
520 while (fread(&idbuf, 1, sizeof(idlog_t), f) == sizeof(idlog_t)) {
521 fpi+=sizeof(idlog_t);
522 then = idbuf.time;
523 if (now - then < IDEXP &&
524 now - then > - SECONDSPERDAY * 180 )
525 /* also expire packets that are dated more than half a year in the future.
526 * That way we get rid of invalid packets introduced by the switch to a
527 * binary id.log. */
528 {
529 fseek(f,fpo,SEEK_SET);
530 fwrite(&idbuf,1,sizeof(idlog_t),f);
531 fpo += sizeof(idlog_t);
532 fseek(f,fpi,SEEK_SET);
533 }
534 }
535 #ifdef _MSC
536 chsize(fileno(f),fpo);
537 #else /* end of _MSC */
538 ftruncate(fileno(f),fpo);
539 #endif /* else if not _MSC */
540 fclose(f);
541 unlockfile(i);
542 buf_free(b);
543 return (0);
544 }

  ViewVC Help
Powered by ViewVC 1.1.5