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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1012 - (show annotations) (download)
Fri Dec 11 19:47:17 2009 UTC (3 years, 5 months ago) by zax-guest
File MIME type: text/plain
File size: 15858 byte(s)
Add hsub capability.  One less IDEA dependency!
1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 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 Cypherpunk remailer messages
9 $Id$ */
10
11
12 #include "mix3.h"
13 #include <ctype.h>
14 #include <time.h>
15 #include <string.h>
16 #include <assert.h>
17 #include <stdlib.h>
18
19 static int t1msg(BUFFER *in, int hdr);
20
21 int isline(BUFFER *line, char *text)
22 {
23 int i;
24
25 if (!bufileft(line, text))
26 return (0);
27
28 for (i = strlen(text); i < line->length; i++)
29 if (!isspace(line->data[i]))
30 return(0);
31 return(1);
32 }
33
34 int t1_decrypt(BUFFER *in)
35 {
36 int ret;
37
38 buf_rewind(in);
39 if (TYPE1[0] == '\0')
40 ret = t1msg(in, 1);
41 else {
42 FILE *f;
43
44 f = openpipe(TYPE1);
45 if (f == NULL)
46 return -1;
47 buf_write(in, f);
48 ret = closepipe(f);
49 }
50 if (ret == 0)
51 stats_log(1);
52 return (ret);
53 }
54
55 #ifdef USE_IDEA
56 void t1_esub(BUFFER *esub, BUFFER *subject)
57 {
58 BUFFER *iv, *out;
59 char hex[33];
60
61 iv = buf_new();
62 out = buf_new();
63
64 buf_appendrnd(iv, 8);
65 id_encode(iv->data, hex);
66 buf_append(out, hex, 16);
67
68 digest_md5(esub, esub);
69 digest_md5(subject, subject);
70 buf_ideacrypt(subject, esub, iv, ENCRYPT);
71 id_encode(subject->data, hex);
72 buf_appends(out, hex);
73 buf_move(subject, out);
74 buf_free(iv);
75 buf_free(out);
76 }
77 #endif /* USE_IDEA */
78
79 void t1_hsub(BUFFER *subject)
80 {
81 BUFFER *iv, *out;
82 char hex[33];
83
84 iv = buf_new();
85 out = buf_new();
86
87 buf_appendrnd(iv, 8);
88 id_encode(iv->data, hex);
89 buf_append(out, hex, 16);
90
91 buf_cat(iv, subject);
92 digest_sha256(iv, iv);
93 id_encode(iv->data, hex);
94 buf_append(out, hex, 32);
95
96 buf_move(subject, out);
97 buf_free(iv);
98 buf_free(out);
99 }
100
101 #define N(X) (isdigit(X) ? (X)-'0' : 0)
102
103 static int readnum(BUFFER *b, int f)
104 {
105 int num = 0;
106
107 if (b->length > 0)
108 sscanf(b->data, "%d", &num);
109 num *= f;
110 if (strchr(b->data, 'r'))
111 num = rnd_number(num) + 1;
112 return (num);
113 }
114
115 static int readdate(BUFFER *b)
116 {
117 int num = -1;
118
119 if (b->length > 0)
120 num = parsedate(b->data);
121 return (num);
122 }
123
124 static int reached_maxcount(BUFFER *md, int maxcount)
125 {
126 FILE *f;
127 char temp[LINELEN];
128 int count = 0;
129 int err = 0;
130 long then;
131 time_t now = time(NULL);
132
133 assert(md->length > 0);
134
135 encode(md, 0);
136
137 f = mix_openfile(PGPMAXCOUNT, "a+"); /* create file if it does not exist */
138 fseek(f,0,SEEK_SET);
139 if (f == NULL) {
140 errlog(ERRORMSG, "Can't open %s!\n", PGPMAXCOUNT);
141 return (-1);
142 }
143 lock(f);
144 while (fgets(temp, sizeof(temp), f) != NULL)
145 if (sscanf(temp, "%ld", &then) &&
146 (then >= now - SECONDSPERDAY) &&
147 strstr (temp, md->data))
148 count++;
149
150 if (count > maxcount)
151 err = 1;
152 else
153 fprintf(f, "%ld %s\n", (long) time(NULL), md->data);
154
155 unlock(f);
156 fclose(f);
157 return (err);
158 }
159
160 static int t1msg(BUFFER *in, int hdr)
161 /* hdr = 1: mail header, hdr = 2: pasted header, hdr = 0: ignore */
162 {
163 BUFFER *field, *content, *line;
164 BUFFER *cutmarks, *to, *newsgroups, *ek, *ekdes, *ekcast, *esub, *subject;
165 BUFFER *temp, *header, *out;
166 BUFFER *test, *testto, *remixto;
167 BUFFER *digest;
168 int err = 0;
169 int encrypted = 0;
170 int type = -1;
171 int latent = 0;
172 int remix = 0, repgp = 0;
173 int inflate = 0;
174 int maxsize = -1;
175 int maxcount = -1;
176 int maxdate = -2; /* -2 not used, -1 parse error */
177 int hsub = 0;
178
179 field = buf_new();
180 content = buf_new();
181 line = buf_new();
182 to = buf_new();
183 remixto = buf_new();
184 cutmarks = buf_new();
185 newsgroups = buf_new();
186 ek = buf_new();
187 ekdes = buf_new();
188 ekcast = buf_new();
189 esub = buf_new();
190 subject = buf_new();
191 temp = buf_new();
192 header = buf_new();
193 out = buf_new();
194 test = buf_new();
195 testto = buf_new();
196 digest = buf_new();
197
198 if (REMIX == 1)
199 remix = 2;
200 if (!UNENCRYPTED)
201 encrypted = -1;
202
203 header:
204 while (buf_getheader(in, field, content) == 0) {
205 if (header->length == 0 && bufieq(content, ":")) /* HDRMARK */
206 hdr = 2;
207
208 if (bufieq(field, "test-to"))
209 buf_set(testto, content);
210 else if (PGP && bufieq(field, "encrypted"))
211 encrypted = 1;
212 else if (bufieq(field, "remix-to")) {
213 remix = 1; repgp = 0;
214 buf_set(remixto, content);
215 if (type == -1)
216 type = MSG_MAIL;
217 } else if (bufieq(field, "encrypt-to")) {
218 repgp = remix = 1;
219 buf_set(remixto, content);
220 if (type == -1)
221 type = MSG_MAIL;
222 } else if (bufieq(field, "anon-to") ||
223 bufieq(field, "request-remailing-to") ||
224 bufieq(field, "remail-to") ||
225 bufieq(field, "anon-send-to")) {
226 if (bufieq(field, "remail-to"))
227 repgp = remix = 0;
228 if (to->length > 0)
229 buf_appendc(to, ',');
230 buf_cat(to, content);
231 if (type == -1)
232 type = MSG_MAIL;
233 } else if (bufieq(field, "anon-post-to") || bufieq(field, "post-to")) {
234 if (newsgroups->length > 0)
235 buf_appendc(newsgroups, ',');
236 buf_cat(newsgroups, content);
237 type = MSG_POST;
238 } else if (bufieq(field, "cutmarks"))
239 buf_set(cutmarks, content);
240 else if (bufieq(field, "latent-time")) {
241 byte *q;
242 int l;
243
244 q = content->data;
245 l = strlen(q);
246 latent = 0;
247 if (q[0] == '+')
248 q++;
249 if (l >= 5 && q[2] == ':')
250 latent = 600 * N(q[0]) + 60 * N(q[1]) + 10 * N(q[3]) + N(q[4]);
251 else if (l >= 4 && q[1] == ':')
252 latent = 60 * N(q[0]) + 10 * N(q[2]) + N(q[3]);
253 else if (l >= 3 && q[0] == ':')
254 latent = 10 * N(q[1]) + N(q[2]);
255 if (!bufleft(content, "+")) {
256 time_t now;
257
258 time(&now);
259 latent -= localtime(&now)->tm_hour * 60;
260 if (latent < 0)
261 latent += 24 * 60;
262 }
263 if (q[l - 1] == 'r')
264 latent = rnd_number(latent);
265 } else if (bufieq(field, "null"))
266 type = MSG_NULL;
267 #ifdef USE_IDEA
268 else if (bufieq(field, "encrypt-key") || bufieq(field, "encrypt-idea"))
269 buf_set(ek, content);
270 #else
271 else if (bufieq(field, "encrypt-key") || bufieq(field, "encrypt-idea"))
272 buf_set(ekdes, content);
273 #endif
274 else if (bufieq(field, "encrypt-des") || bufieq(field, "encrypt-3des"))
275 buf_set(ekdes, content);
276 else if (bufieq(field, "encrypt-cast") || bufieq(field, "encrypt-cast5"))
277 buf_set(ekcast, content);
278 else if (bufieq(field, "encrypt-subject"))
279 buf_set(esub, content);
280 else if (bufieq(field, "hash-subject") && bufieq(content, "yes"))
281 hsub = 1;
282 else if (bufieq(field, "inflate")) {
283 inflate = readnum(content, 1024);
284 if (inflate > INFLATEMAX * 1024)
285 inflate = INFLATEMAX * 1024;
286 } else if (bufieq(field, "rand-hop")) {
287 int randhops, i;
288 randhops = readnum(content, 1);
289 if (randhops > MAXRANDHOPS)
290 randhops = MAXRANDHOPS;
291 buf_clear(temp);
292 if (remixto->length)
293 buf_move(temp, remixto);
294 for (i = 0; i < randhops; i++) {
295 if (remixto->length > 0)
296 buf_appendc(remixto, ',');
297 buf_appendc(remixto, '*');
298 }
299 if (temp->length) {
300 buf_appendc(remixto, ',');
301 buf_cat(remixto, temp);
302 }
303 } else if (bufieq(field, "max-size") || bufieq(field, "maxsize"))
304 maxsize = readnum(content, 1024);
305 else if (bufieq(field, "max-count") || bufieq(field, "maxcount"))
306 maxcount = readnum(content, 1);
307 else if (bufieq(field, "max-date") || bufieq(field, "maxdate"))
308 maxdate = readdate(content);
309 #if USE_NSUB
310 else if (bufieq(field, "subject"))
311 buf_set(subject, content);
312 #endif /* USE_NSUB */
313 }
314
315 if (cutmarks->length > 0) {
316 BUFFER *cut;
317
318 cut = buf_new();
319 buf_clear(temp);
320
321 while ((err = buf_getline(in, line)) != -1 && !buf_eq(line, cutmarks)) {
322 buf_cat(temp, line);
323 buf_nl(temp);
324 }
325 while (err != -1) {
326 err = buf_getline(in, line);
327 if (err == -1 || buf_eq(line, cutmarks)) {
328 t1msg(cut, 0);
329 buf_clear(cut);
330 } else {
331 buf_cat(cut, line);
332 buf_nl(cut);
333 }
334 }
335 buf_move(in, temp);
336 buf_clear(cutmarks);
337 }
338 if (encrypted == 1) {
339 #ifdef USE_PGP
340 err = pgp_dearmor(in, temp);
341 if (err == 0) {
342 BUFFER *pass;
343 digest_sha1(temp, digest);
344
345 pass = buf_new();
346 buf_sets(pass, PASSPHRASE);
347 err = pgp_decrypt(temp, pass, NULL, NULL, NULL);
348 buf_free(pass);
349 }
350 if (err != -1 && temp->length == 0) {
351 errlog(ERRORMSG, "Empty PGP message.\n");
352 err = -1;
353 goto end;
354 }
355 if (err != -1) {
356 buf_rest(temp, in); /* dangerous, but required for reply blocks */
357 buf_move(in, temp);
358 encrypted = 0;
359 hdr = 0;
360 goto header;
361 }
362 #endif /* USE_PGP */
363 if (testto->length == 0)
364 errlog(ERRORMSG, "Can't decrypt PGP message.\n");
365 buf_appends(test, "Can't decrypt PGP message.\n");
366 }
367 while ((err = buf_lookahead(in, line)) == 1)
368 buf_getline(in, line);
369 #if 0
370 if (err == -1)
371 goto end;
372 #endif /* 0 */
373
374 if (isline(line, HDRMARK) && (hdr == 0 || hdr == 1)) {
375 buf_getline(in, NULL);
376 hdr = 2;
377 goto header;
378 } else if (isline(line, HASHMARK)) {
379 buf_getline(in, NULL);
380 for (;;) {
381 if (buf_lookahead(in, line) == 0 && bufileft(line, "subject:")) {
382 buf_getheader(in, field, content);
383 buf_set(subject, content);
384 }
385 if (buf_getline(in, line) != 0)
386 break;
387 buf_cat(header, line);
388 buf_nl(header);
389 }
390 }
391 if (encrypted == -1) {
392 if (testto->length == 0)
393 errlog(LOG, "Unencrypted message detected.\n");
394 buf_appends(test, "Unencrypted message detected.\n");
395 err = -2;
396 goto end;
397 }
398 if (maxdate == -1) {
399 if (testto->length == 0)
400 errlog(LOG, "Could not parse Max-Date: header.\n");
401 buf_appends(test, "Could not parse Max-Date: header.\n");
402 err = -2;
403 goto end;
404 } else if (maxdate >= 0 && maxdate <= time(NULL)) {
405 if (testto->length == 0)
406 errlog(LOG, "Message is expired.\n");
407 buf_appends(test, "Message is expired.\n");
408 err = -2;
409 goto end;
410 }
411 if (maxsize >= 0 && in->length >= maxsize) {
412 if (testto->length == 0)
413 errlog(LOG, "Message Size exceeds Max-Size.\n");
414 buf_appends(test, "Message Size exceeds Max-Size.\n");
415 err = -2;
416 goto end;
417 }
418 if (maxcount >= 0) {
419 if (digest->length == 0) {
420 if (testto->length == 0)
421 errlog(LOG, "Max-Count yet not encrypted.\n");
422 buf_appends(test, "Max-Count yet not encrypted.\n");
423 err = -2;
424 goto end;
425 }
426 if (reached_maxcount(digest, maxcount)) {
427 if (testto->length == 0)
428 errlog(LOG, "Max-Count reached - discarding message.\n");
429 buf_appends(test, "Max-Count reached - discarding message.\n");
430 err = -2;
431 goto end;
432 }
433 }
434
435 if (type == MSG_POST && subject->length == 0)
436 buf_sets(subject, "(no subject)");
437
438 if (to->length > 0)
439 buf_appendf(out, "To: %b\n", to);
440 else if (remixto->length > 0)
441 buf_appendf(out, "To: %b\n", remixto);
442 if (newsgroups->length > 0)
443 buf_appendf(out, "Newsgroups: %b\n", newsgroups);
444 if (subject->length > 0) {
445 #ifdef USE_IDEA
446 if (esub->length > 0)
447 t1_esub(esub, subject);
448 #endif /* USE_IDEA */
449 if (hsub == 1)
450 t1_hsub(subject);
451 buf_appendf(out, "Subject: %b\n", subject);
452 }
453 buf_cat(out, header);
454 buf_nl(out);
455
456 #if 0
457 inflate -= in->length;
458 #endif /* 0 */
459 if (inflate > 0) {
460 buf_setrnd(temp, inflate * 3 / 4);
461 encode(temp, 64);
462 buf_appends(in, "\n-----BEGIN GARBAGE-----\n");
463 buf_cat(in, temp);
464 buf_appends(in, "-----END GARBAGE-----\n");
465 }
466
467 if (!(ek->length || ekdes->length || ekcast->length))
468 buf_rest(out, in);
469 else {
470 err = 0;
471 buf_clear(temp);
472 while (buf_getline(in, line) != -1) {
473 if (isline(line, EKMARK)) {
474 buf_cat(out, temp);
475 buf_clear(temp);
476 buf_rest(temp, in);
477 break;
478 }
479 else {
480 buf_cat(temp, line);
481 buf_nl(temp);
482 }
483 }
484 #ifdef USE_PGP
485 if (ekcast->length) {
486 err = pgp_encrypt(PGP_CONVCAST | PGP_TEXT, temp, ekcast, NULL, NULL,
487 NULL, NULL);
488 buf_clear(ekcast);
489 }
490 if (ekdes->length) {
491 err = pgp_encrypt(PGP_CONV3DES | PGP_TEXT, temp, ekdes, NULL, NULL,
492 NULL, NULL);
493 buf_clear(ekdes);
494 }
495 if (ek->length) {
496 err = pgp_encrypt(PGP_CONVENTIONAL | PGP_TEXT, temp, ek, NULL, NULL,
497 NULL, NULL);
498 buf_clear(ek);
499 }
500 buf_appends(out, EKMARK);
501 buf_nl(out);
502 buf_cat(out, temp);
503 #else /* end of USE_PGP */
504 err = -1;
505 #endif /* Else if not USE_PGP */
506 }
507
508 if (type == -1) {
509 buf_appends(test, "No destination.\n");
510 err = -1;
511 }
512
513 end:
514 if (testto->length) {
515 BUFFER *report;
516 int i;
517
518 report = buf_new();
519 buf_sets(report,
520 "Subject: remailer test report\n\nThis is an automated response to the test message you sent to ");
521 buf_appends(report, SHORTNAME);
522 buf_appends(report, ".\nYour test message results follow:\n\n");
523 buf_appends(report, remailer_type);
524 buf_appends(report, VERSION);
525 buf_appends(report, "\n\n");
526 if (err == 0) {
527 err = filtermsg(out);
528 if (err == -1)
529 buf_appends(report, "This remailer cannot deliver the message.\n\n");
530 else {
531 buf_appends(report, "Valid ");
532 buf_appends(report, type == MSG_POST ? "Usenet" : "mail");
533 buf_appends(report, " message.\n");
534 if (remixto->length) {
535 if (remix && MIX)
536 buf_appends(report, "Delivery via Mixmaster: ");
537 else if (remix)
538 buf_appends(report, "Error! Can't remix: ");
539 else
540 buf_appends(report, "Delivery via Cypherpunk remailer: ");
541 buf_cat(report, remixto);
542 buf_nl(report);
543 }
544 else if (type == MSG_POST && strchr(NEWS, '@') && !strchr(NEWS, ' ')) {
545 buf_appendf(report, "News gateway: %s\n", NEWS);
546 }
547 buf_appends(report,
548 "\n=========================================================================\nThe first 20 lines of the message follow:\n");
549 if (err != 1)
550 buf_appendf(report, "From: %s\n", ANONNAME);
551 if (type == MSG_POST && ORGANIZATION[0] != '\0')
552 buf_appendf(report, "Organization: %s\n", ORGANIZATION);
553 }
554 for (i = 0; i < 20 && buf_getline(out, test) != -1; i++)
555 buf_cat(report, test), buf_nl(report);
556 } else {
557 buf_appends(report, "The remailer message is invalid.\n\n");
558 if (test->length) {
559 buf_appends(report, "The following error occurred: ");
560 buf_cat(report, test);
561 buf_nl(report);
562 }
563 }
564 buf_appends(report,
565 "=========================================================================\nThe first 20 lines of your message to the remailer follow:\n");
566 buf_rewind(in);
567 for (i = 0; i < 20 && buf_getline(in, test) != -1; i++)
568 buf_cat(report, test), buf_nl(report);
569
570 sendmail(report, REMAILERNAME, testto);
571 err = 0;
572 buf_free(report);
573 } else if (err == 0 && type != MSG_NULL) {
574 err = 1;
575 if (bufieq(to, REMAILERADDR)) /* don't remix to ourselves */
576 remix = 0;
577 if (remix && remixto->length == 0)
578 buf_set(remixto, to);
579 if (remixto->length > 0) {
580 /* check that the remix-to path isn't too long */
581 int remixcount = 1;
582 char *tmp = remixto->data;
583 while ((tmp = strchr(tmp+1, ','))) {
584 remixcount ++;
585 if (remixcount > MAXRANDHOPS) {
586 *tmp = '\0';
587 break;
588 }
589 };
590 }
591 if (remix && !repgp && remixto->length != 0)
592 err = mix_encrypt(type, out, remixto->data, 1, line);
593 if (err != 0) {
594 if (remix == 1 && !repgp)
595 errlog(NOTICE, "Can't remix -- %b\n", line);
596 else {
597 if (remixto->length)
598 err = t1_encrypt(type, out, remixto->data, 0, 0, line);
599 if (err != 0 && repgp)
600 errlog(NOTICE, "Can't repgp -- %b\n", line);
601 else
602 err = mix_pool(out, type, latent * 60);
603 }
604 }
605 }
606
607 buf_free(field);
608 buf_free(content);
609 buf_free(line);
610 buf_free(to);
611 buf_free(remixto);
612 buf_free(newsgroups);
613 buf_free(subject);
614 buf_free(ek);
615 buf_free(ekcast);
616 buf_free(ekdes);
617 buf_free(esub);
618 buf_free(cutmarks);
619 buf_free(temp);
620 buf_free(out);
621 buf_free(header);
622 buf_free(test);
623 buf_free(testto);
624 buf_free(digest);
625 return (err);
626 }

Properties

Name Value
svn:keywords Id

  ViewVC Help
Powered by ViewVC 1.1.5