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