/[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 41 - (hide annotations) (download)
Wed Dec 12 19:29:52 2001 UTC (11 years, 5 months ago) by rabbi
File MIME type: text/plain
File size: 12571 byte(s)
Added quoted-printable decoding of non-multipart mime messages (cf. bug
#478380) by Scott Renfro.
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 rabbi 41 $Id: rem.c,v 1.5 2001/12/12 19:29:52 rabbi 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     #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 rabbi 41 int quoted_printable = 0; /* is this message quoted printable encoded */
51 rabbi 1
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 rabbi 41 else if (bufieq(field, "content-transfer-encoding")
124     && bufieq(content, "quoted-printable")) {
125     quoted_printable = 1;
126     }
127    
128 rabbi 1 }
129     hdrend:
130 rabbi 41 if (quoted_printable)
131     qp_decode_message(message);
132    
133 rabbi 1 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 rabbi 11 sprintf(fname, "%s%cp%02x%02x%02x%01x.%02x", POOLDIR, DIRSEP,
272 rabbi 1 mid->data[0], mid->data[1], mid->data[2], mid->data[3] & 15,
273     packetnum);
274     #else
275 rabbi 11 sprintf(fname, "%s%cp%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP,
276 rabbi 1 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 rabbi 6 time_t t;
309     struct tm *tc;
310     char line[LINELEN];
311    
312 rabbi 1 /* 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 rabbi 6 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 rabbi 1 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 rabbi 30 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 rabbi 1 while (buf_getline(message, line) != -1)
387     if (bufifind(line, "destination-block")) {
388     buf_clear(addr);
389     request = 1;
390     if (buffind(line, "@")) {
391     int c = 0;
392    
393     while (!strileft(line->data + line->ptr, "block"))
394     line->ptr++;
395     while (c != ' ')
396     c = tolower(buf_getc(line));
397     while (c == ' ')
398     c = buf_getc(line);
399     do {
400     buf_appendc(addr, c);
401     c = buf_getc(line);
402     } while (c > ' ');
403     } else
404     buf_set(addr, from);
405     if (bufieq(addr, REMAILERADDR)) {
406     errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
407     return (2);
408     }
409     if (buf_ieq(addr, from))
410     errlog(NOTICE, "Blocking request for %b\n", addr);
411     else
412     errlog(NOTICE, "Blocking request for %b from %b\n", addr, from);
413     if (AUTOBLOCK) {
414     domain = 0;
415     if (addr->data[0] == '@') {
416     domain = 1;
417     buf_sets(line, "postmaster");
418     buf_cat(line, addr);
419     buf_move(addr, line);
420     }
421     buf_clear(line);
422     rfc822_addr(addr, line);
423     if (strchr(line->data, '@') && strchr(strchr(line->data, '@'), '.')) {
424     strcpy( destblklst, DESTBLOCK );
425     destblk = strtok( destblklst, " " );
426     f = mix_openfile( destblk, "a" );
427     free( destblklst );
428     if (f != NULL) {
429     lock(f);
430     sendinfofile(BLOCKFILE, NULL, line, NULL);
431     if (line->length) {
432     if (domain)
433     fprintf(f, "%s", line->data + sizeof("postmaster") - 1);
434     else
435     fprintf(f, "%s", line->data);
436     } else
437     errlog(NOTICE, "%b already blocked.\n", addr);
438     unlock(f);
439     fclose(f);
440     } else
441     errlog(ERRORMSG, "Can't write to %s.\n", DESTBLOCK);
442     } else
443     errlog(WARNING, "Invalid address not added to %s: %b\n", DESTBLOCK,
444     addr);
445     }
446     }
447     return (request);
448     }
449    
450    
451     int idexp(void)
452     {
453     FILE *f;
454     BUFFER *b;
455     long now, then;
456     char line[LINELEN];
457     LOCK *i;
458    
459     if (IDEXP == 0)
460     return (0);
461    
462     b = buf_new();
463     f = mix_openfile(IDLOG, "r");
464     if (f == NULL)
465     return (-1);
466     i = lockfile(IDLOG);
467     now = time(NULL);
468     fgets(line, sizeof(line), f); /* replace first line */
469     while (fgets(line, sizeof(line), f) != NULL) {
470     sscanf(line, "%*s %ld", &then);
471     if (now - then < IDEXP)
472     buf_appends(b, line);
473     }
474     fclose(f);
475     f = mix_openfile(IDLOG, "w");
476     if (f != NULL) {
477     fprintf(f, "expired %ld\n", now - IDEXP);
478     buf_write(b, f);
479     fclose(f);
480     }
481     unlockfile(i);
482     return (0);
483     }

  ViewVC Help
Powered by ViewVC 1.1.5