/[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 56 - (show annotations) (download)
Mon Dec 17 01:46:35 2001 UTC (11 years, 5 months ago) by rabbi
File MIME type: text/plain
File size: 13155 byte(s)
Prohibit automatic blocking of entire domains.
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.10 2001/12/17 01:46:35 rabbi 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
22 #include <io.h>
23 #endif
24 #ifndef _MSC
25 #include <dirent.h>
26 #endif
27 #include <assert.h>
28
29 int blockrequest(BUFFER *message);
30
31 #define REQUESTHELP 100
32 #define REQUESTSTATS 101
33 #define REQUESTKEY 200
34 #define REQUESTCONF 201
35 #define REQUESTOPKEY 202
36 #define BLOCKREQUEST 666
37 #define DISABLED 99
38
39 #define CPUNKMSG 1
40 #define MIXMSG 2
41
42 int mix_decrypt(BUFFER *message)
43 {
44 int type = 0;
45 BUFFER *field, *content;
46 BUFFER *to, *subject, *replyto, *reply;
47 FILE *f;
48 BUFFER *block;
49 int err = 0;
50 int quoted_printable = 0; /* is this message quoted printable encoded */
51
52 mix_init(NULL);
53 field = buf_new();
54 content = buf_new();
55 to = buf_new();
56 replyto = buf_new();
57 reply = buf_new();
58 block = buf_new();
59 subject = buf_new();
60 buf_sets(subject, "Subject: Re: your mail");
61
62 buf_rewind(message);
63
64 f = mix_openfile(SOURCEBLOCK, "r");
65 if (f != NULL) {
66 buf_read(block, f);
67 fclose(f);
68 }
69 for (;;) {
70 err = buf_getheader(message, field, content);
71 if (err == 1) {
72 /* "::" marks for additional header lines */
73 while (buf_lookahead(message, field) == 1)
74 buf_getheader(message, field, content);
75 if (isline(field, HDRMARK))
76 continue;
77 else
78 goto hdrend;
79 }
80 if (err == -1)
81 goto hdrend;
82
83 if ((bufieq(field, "from") || bufieq(field, "sender") || bufieq(field,"received")) &&
84 doblock(content, block, 1) != 0)
85 goto end;
86
87 if (bufieq(field, "to"))
88 buf_cat(to, content);
89 else if (bufieq(field, "from") && replyto->length == 0)
90 /* reply to From address if no Reply-To header present */
91 buf_set(replyto, content);
92 else if (bufieq(field, "reply-to"))
93 buf_set(replyto, content);
94 else if (MIX && bufieq(field, "remailer-type") &&
95 bufileft(content, "mixmaster"))
96 type = MIXMSG;
97 else if (bufieq(field, "subject")) {
98 if (bufieq(content, "help") || bufieq(content, "remailer-help"))
99 type = REQUESTHELP;
100 else if (bufieq(content, "remailer-stats"))
101 type = REQUESTSTATS;
102 else if (bufieq(content, "remailer-key"))
103 type = REQUESTKEY;
104 else if (bufieq(content, "remailer-adminkey"))
105 type = REQUESTOPKEY;
106 else if (bufieq(content, "remailer-conf"))
107 type = REQUESTCONF;
108 else if (bufileft(content, "destination-block"))
109 type = BLOCKREQUEST;
110 else {
111 buf_sets(subject, "Subject: ");
112 if (!bufileft(content, "re:"))
113 buf_appends(subject, "Re: ");
114 buf_cat(subject, content);
115 }
116 } else if (bufieq(field, "test-to") || bufieq(field, "encrypted") ||
117 bufieq(field, "anon-to") ||
118 bufieq(field, "request-remailing-to") ||
119 bufieq(field, "remail-to") || bufieq(field, "anon-post-to") ||
120 bufieq(field, "post-to") || bufieq(field, "anon-send-to") ||
121 bufieq(field, "send-to") || bufieq(field, "remix-to"))
122 type = CPUNKMSG;
123 else if (bufieq(field, "content-transfer-encoding")
124 && bufieq(content, "quoted-printable")) {
125 quoted_printable = 1;
126 }
127
128 }
129 hdrend:
130 if (quoted_printable)
131 qp_decode_message(message);
132
133 if (type > 0 && REMAIL == 0)
134 type = DISABLED;
135 switch (type) {
136 case REQUESTHELP:
137 if (sendinfofile(HELPFILE, NULL, replyto, NULL) == -1)
138 errlog(WARNING, "No help file available.\n");
139 break;
140 case REQUESTKEY:
141 err = key(reply);
142 if (err == 0)
143 err = sendmail(reply, REMAILERNAME, replyto);
144 break;
145 case REQUESTOPKEY:
146 err = adminkey(reply);
147 if (err == 0)
148 err = sendmail(reply, REMAILERNAME, replyto);
149 break;
150 case REQUESTSTATS:
151 err = stats(reply);
152 if (err == 0)
153 err = sendmail(reply, REMAILERNAME, replyto);
154 break;
155 case REQUESTCONF:
156 err = conf(reply);
157 if (err == 0)
158 err = sendmail(reply, REMAILERNAME, replyto);
159 break;
160 case CPUNKMSG:
161 err = t1_decrypt(message);
162 if (err != 0) {
163 errlog(LOG, "Invalid type 1 message from %b\n", replyto);
164 sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
165 logmail(err == -2 ? MAILUSAGE : MAILERROR, message);
166 }
167 break;
168 case MIXMSG:
169 err = t2_decrypt(message);
170 if (err == -1) {
171 errlog(LOG, "Invalid type 2 message from %b\n", replyto);
172 sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
173 logmail(MAILERROR, message);
174 }
175 break;
176 case BLOCKREQUEST:
177 blockrequest(message);
178 logmail(MAILBLOCK, message);
179 break;
180 case DISABLED:
181 errlog(ERRORMSG, "Remailer is disabled.\n");
182 buf_sets(reply, "Subject: remailer error\n\nThe remailer is disabled.\n");
183 sendmail(reply, REMAILERNAME, replyto);
184 logmail(MAILERROR, message);
185 break;
186 default:
187 if (strifind
188 (replyto->data, "mailer-daemon")) {
189 errlog(LOG, "Bounce mail from %b\n", replyto);
190 logmail(MAILBOUNCE, message);
191 } else if (bufifind(to, REMAILERADDR) && blockrequest(message))
192 logmail(MAILBLOCK, message);
193 else if (!AUTOREPLY)
194 logmail(MAILBOX, message);
195 else if (bufifind(to, REMAILERADDR)) {
196 errlog(LOG, "Non-remailer message from %b\n", replyto);
197 sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
198 logmail(MAILUSAGE, message);
199 } else if (bufifind(to, COMPLAINTS)) {
200 errlog(WARNING, "Abuse complaint from %b\n", replyto);
201 sendinfofile(ABUSEFILE, NULL, replyto, subject);
202 logmail(MAILABUSE, message);
203 } else if (ANONADDR[0] && bufifind(to, ANONADDR)) {
204 errlog(LOG, "Reply to anonymous message from %b\n", replyto);
205 sendinfofile(REPLYFILE, NULL, replyto, subject);
206 logmail(MAILANON, message);
207 } else {
208 errlog(DEBUGINFO, "Mail from %b\n", replyto);
209 logmail(MAILBOX, message);
210 }
211 err = 1;
212 }
213 end:
214 buf_free(field);
215 buf_free(content);
216 buf_free(to);
217 buf_free(replyto);
218 buf_free(reply);
219 buf_free(block);
220 buf_free(subject);
221 return (err);
222 }
223
224 int t2_decrypt(BUFFER *in)
225 {
226 int err = 0;
227 BUFFER *msg;
228
229 msg = buf_new();
230 do {
231 err = mix_dearmor(in, msg);
232 if (err != -1) {
233 if (v3_magic(msg->data))
234 err = mix3_decrypt(msg);
235 else
236 err = mix2_decrypt(msg);
237 }
238 }
239 while (in->ptr + 1000 < in->length); /* accept several packets in one message */
240
241 buf_free(msg);
242 return (err);
243 }
244
245 int mix_pool(BUFFER *msg, int type, long latent)
246 {
247 char path[PATHMAX], pathtmp[PATHMAX];
248 FILE *f;
249 int err = -1;
250
251 f = pool_new(latent > 0 ? "lat" : "msg", pathtmp, path);
252 if (f != NULL) {
253 if (latent > 0)
254 fprintf(f, "%d %ld\n", type, latent + time(NULL));
255 else
256 fprintf(f, "%d 0\n", type);
257 err = buf_write(msg, f);
258 fclose(f);
259 }
260 if (err == 0) {
261 rename(pathtmp, path);
262 errlog(DEBUGINFO, "Added message to pool.\n");
263 }
264 return (err);
265 }
266
267 int pool_packetfile(char *fname, BUFFER *mid, int packetnum)
268 /* create a filename */
269 {
270 #ifdef SHORTNAMES
271 sprintf(fname, "%s%cp%02x%02x%02x%01x.%02x", POOLDIR, DIRSEP,
272 mid->data[0], mid->data[1], mid->data[2], mid->data[3] & 15,
273 packetnum);
274 #else
275 sprintf(fname, "%s%cp%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP,
276 packetnum, mid->data[0], mid->data[1], mid->data[2], mid->data[3],
277 mid->data[4], mid->data[5] & 15);
278 #endif
279 return (0);
280 }
281
282 void pool_packetexp(void)
283 {
284 DIR *d;
285 struct dirent *e;
286 struct stat sb;
287
288 d = opendir(POOLDIR);
289 if (d != NULL)
290 for (;;) {
291 e = readdir(d);
292 if (e == NULL)
293 break;
294 if (e->d_name[0] == 'p') {
295 if (stat(e->d_name, &sb) == 0 &&
296 time(NULL) - sb.st_mtime > PACKETEXP) {
297 errlog(NOTICE, "Expiring partial message %s.\n",
298 e->d_name);
299 unlink(e->d_name);
300 }
301 }
302 }
303 closedir(d);
304 }
305
306 void logmail(char *mailbox, BUFFER *message)
307 {
308 time_t t;
309 struct tm *tc;
310 char line[LINELEN];
311
312 /* mailbox is "|program", "user@host", "stdout" or "filename" */
313 buf_rewind(message);
314 if (mailbox[0] == '\0') /* default action */
315 mailbox = MAILBOX;
316 if (strieq(mailbox, "stdout"))
317 buf_write(message, stdout);
318 else if (mailbox[0] == '|') {
319 FILE *p;
320
321 errlog(DEBUGINFO, "Piping message to %s.", mailbox + 1);
322 p = openpipe(mailbox + 1);
323 if (p != NULL) {
324 buf_write(message, p);
325 closepipe(p);
326 }
327 } else if (strchr(mailbox, '@')) {
328 BUFFER *field, *content;
329
330 field = buf_new();
331 content = buf_new();
332 while (buf_getheader(message, field, content) == 0)
333 if (bufieq(field, "x-loop") && bufifind(content, REMAILERADDR)) {
334 errlog(WARNING, "Loop detected! Message not sent to %s.\n", mailbox);
335 goto isloop;
336 }
337 buf_sets(content, mailbox);
338 sendmail(message, NULL, content);
339 isloop:
340 buf_free(field);
341 buf_free(content);
342 } else {
343 FILE *mbox;
344
345 mbox = mix_openfile(mailbox, "a");
346 if (mbox == NULL) {
347 errlog(ERRORMSG, "Can't write to mail folder %s\n", mailbox);
348 return;
349 }
350 lock(mbox);
351 if (!bufileft(message, "From ")) {
352 t = time(NULL);
353 tc = localtime(&t);
354 strftime(line, LINELEN, "From Mixmaster %a %b %d %H:%M:%S %Y\n", tc);
355 fprintf(mbox, line);
356 }
357 buf_write(message, mbox);
358 fprintf(mbox, "\n");
359 unlock(mbox);
360 fclose(mbox);
361 }
362 }
363
364 int blockrequest(BUFFER *message)
365 {
366 int request = 0, domain;
367 BUFFER *from, *line, *field, *content, *addr;
368 FILE *f;
369 char *destblklst = (char *)malloc( strlen(DESTBLOCK)+1 );
370 char *destblk;
371
372 from = buf_new();
373 line = buf_new();
374 field = buf_new();
375 content = buf_new();
376 addr = buf_new();
377
378 buf_rewind(message);
379 while (buf_getheader(message, field, content) == 0)
380 if (bufieq(field, "from"))
381 buf_set(from, content);
382 else if (bufieq(field, "subject"))
383 buf_cat(message, content);
384 /* Append the subject to the message body so destination block requests
385 in the subject line work too (we process the body a few lines down) */
386 while (buf_getline(message, line) != -1)
387 if (bufifind(line, "destination-block")) {
388 buf_clear(addr);
389 request = 1;
390 {
391 int c = 0;
392
393 while (!strileft(line->data + line->ptr, "block"))
394 line->ptr++;
395 while (c != ' ' && c != -1)
396 c = tolower(buf_getc(line));
397 while (c == ' ')
398 c = buf_getc(line);
399 if (c != -1)
400 do {
401 buf_appendc(addr, c);
402 c = buf_getc(line);
403 } while (c > ' ');
404 }
405 if (addr->length == 0) {
406 rfc822_addr (from, addr);
407 buf_chop(addr);
408 }
409 if (addr->length == 0) {
410 return (2);
411 };
412 if (! buffind(addr, "@"))
413 {
414 errlog(LOG, "Ignoring blocking request for %b from %b "
415 "(no @ sign in address).\n", addr, from);
416 return (2);
417 };
418 if (bufieq(addr, REMAILERADDR)) {
419 errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
420 return (2);
421 }
422 if (bufleft(addr, "@")) {
423 errlog(LOG, "Ignoring blocking request: %b from %b: "
424 "We do not block entire domains.\n",
425 addr, from);
426 return (2);
427 }
428 if (bufleft(addr, "/")) {
429 errlog(LOG, "Ignoring blocking request: %b from %b is a regex.\n",
430 addr, from);
431 return (2);
432 }
433 if (buf_ieq(addr, from))
434 errlog(NOTICE, "Blocking request for %b\n", addr);
435 else
436 errlog(NOTICE, "Blocking request for %b from %b\n", addr, from);
437 if (AUTOBLOCK) {
438 domain = 0;
439 if (addr->data[0] == '@') {
440 domain = 1;
441 buf_sets(line, "postmaster");
442 buf_cat(line, addr);
443 buf_move(addr, line);
444 }
445 buf_clear(line);
446 rfc822_addr(addr, line);
447 if (strchr(line->data, '@') && strchr(strchr(line->data, '@'), '.')) {
448 strcpy( destblklst, DESTBLOCK );
449 destblk = strtok( destblklst, " " );
450 f = mix_openfile( destblk, "a" );
451 free( destblklst );
452 if (f != NULL) {
453 lock(f);
454 sendinfofile(BLOCKFILE, NULL, addr, NULL);
455 if (line->length) {
456 if (domain)
457 fprintf(f, "%s", line->data + sizeof("postmaster") - 1);
458 else
459 fprintf(f, "%s", line->data);
460 } else
461 errlog(NOTICE, "%b already blocked.\n", addr);
462 unlock(f);
463 fclose(f);
464 } else
465 errlog(ERRORMSG, "Can't write to %s.\n", DESTBLOCK);
466 } else
467 errlog(WARNING, "Invalid address not added to %s: %b\n", DESTBLOCK,
468 addr);
469 }
470 }
471 return (request);
472 }
473
474
475 int idexp(void)
476 {
477 FILE *f;
478 BUFFER *b;
479 long now, then;
480 char line[LINELEN];
481 LOCK *i;
482
483 if (IDEXP == 0)
484 return (0);
485
486 b = buf_new();
487 f = mix_openfile(IDLOG, "r");
488 if (f == NULL)
489 return (-1);
490 i = lockfile(IDLOG);
491 now = time(NULL);
492 fgets(line, sizeof(line), f); /* replace first line */
493 while (fgets(line, sizeof(line), f) != NULL) {
494 sscanf(line, "%*s %ld", &then);
495 if (now - then < IDEXP)
496 buf_appends(b, line);
497 }
498 fclose(f);
499 f = mix_openfile(IDLOG, "w");
500 if (f != NULL) {
501 fprintf(f, "expired %ld\n", now - IDEXP);
502 buf_write(b, f);
503 fclose(f);
504 }
505 unlockfile(i);
506 return (0);
507 }

  ViewVC Help
Powered by ViewVC 1.1.5