trem2.c - mixmaster - mixmaster 3.0 patched for libressl
HTML git clone git://parazyd.org/mixmaster.git
DIR Log
DIR Files
DIR Refs
DIR README
---
trem2.c (10743B)
---
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 Mixmaster remailer messages
9 $Id: rem2.c 934 2006-06-24 13:40:39Z rabbi $ */
10
11
12 #include "mix3.h"
13 #include <string.h>
14 #include <time.h>
15 #include <ctype.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #ifdef POSIX
19 #include <unistd.h>
20 #else /* end of POSIX */
21 #include <io.h>
22 #endif /* else if not POSIX */
23 #ifndef _MSC
24 #include <dirent.h>
25 #endif /* not _MSC */
26 #include <assert.h>
27
28 int mix_dearmor(BUFFER *in, BUFFER *out)
29 {
30 BUFFER *line, *md;
31 int tempbuf = 0;
32 int err = 0;
33
34 line = buf_new();
35 md = buf_new();
36
37 if (in == out) {
38 tempbuf = 1;
39 out = buf_new();
40 }
41 do {
42 err = buf_getline(in, line);
43 if (err == -1)
44 goto end;
45 }
46 while (!bufeq(line, begin_remailer));
47
48 do {
49 /* skip lines before message digest */
50 if (buf_getline(in, md) == -1)
51 break;
52 } while (strlen(md->data) != 24);
53
54 decode(in, out);
55
56 err = buf_getline(in, line);
57 if (err != 0 || !bufeq(line, end_remailer))
58 err = -1;
59 else {
60 digest_md5(out, line);
61 encode(line, 0);
62 if (!buf_eq(md, line))
63 err = -1;
64 if (out->length != 20480)
65 err = -1;
66 }
67
68 end:
69 if (err == -1)
70 errlog(NOTICE, "Malformatted message.\n");
71
72 if (tempbuf) {
73 buf_move(in, out);
74 buf_free(out);
75 }
76 buf_free(line);
77 buf_free(md);
78 return (err);
79 }
80
81 static int isnewid(BUFFER *id, long timestamp)
82 /* return values:
83 * 0: ignore message, no error
84 * 1: ok, process message
85 * -1: bad message, send reply
86 */
87 {
88 FILE *f;
89 int ret = 1;
90 long now, old = 0;
91 LOCK *i = NULL;
92 idlog_t idbuf;
93
94 if (REMAIL == 0)
95 return (1); /* don't keep statistics for the client */
96
97 now = time(NULL);
98
99 if ((f = mix_openfile(IDLOG, "rb+")) != NULL) {
100 fread(&idbuf,1,sizeof(idlog_t),f);
101 old = idbuf.time;
102 } else {
103 if (IDEXP == 0) {
104 if (timestamp > 0 && timestamp <= now - 7 * SECONDSPERDAY) {
105 errlog(LOG, "Ignoring old message.\n");
106 return (0);
107 }
108 } else {
109 if ((f = mix_openfile(IDLOG, "wb")) != NULL) {
110 memset(idbuf.id,0,sizeof(idbuf.id));
111 idbuf.time = now;
112 fwrite(&idbuf,1,sizeof(idlog_t),f);
113 memcpy(idbuf.id,id->data,sizeof(idbuf.id));
114 idbuf.time = now;
115 fwrite(&idbuf,1,sizeof(idlog_t),f);
116 fclose(f);
117 errlog(NOTICE, "Creating %s\n", IDLOG);
118 } else {
119 errlog(ERRORMSG, "Can't create %s\n", IDLOG);
120 }
121 return (1);
122 }
123 }
124
125 if (now - old < 5 * SECONDSPERDAY) /* never reject messages less than */
126 old = now - 5 * SECONDSPERDAY; /* 5 days old (== minimum IDEXP) */
127
128 if (timestamp > 0 && timestamp <= old) {
129 errlog(LOG, "Ignoring old message.\n");
130 ret = 0;
131 goto end;
132 }
133 i = lockfile(IDLOG);
134 while (fread(&idbuf, 1, sizeof(idlog_t), f) == sizeof(idlog_t)) {
135 if (!memcmp(idbuf.id, id->data, sizeof(idbuf.id))) {
136 char idstr[33];
137 id_encode(id->data, idstr);
138 errlog(LOG, "Ignoring redundant message: %s.\n", idstr);
139 ret = 0;
140 goto end;
141 }
142 }
143 if (timestamp > now) {
144 errlog(LOG, "Ignoring message with future timestamp.\n");
145 ret = -1;
146 goto end;
147 }
148 if (ftell(f)%sizeof(idlog_t)) fseek(f,0-(ftell(f)%sizeof(idlog_t)),SEEK_CUR); /* make sure that we're on sizeof(idlog_t) byte boundary */
149 memcpy(idbuf.id,id->data,sizeof(idbuf.id));
150 idbuf.time = now;
151 fwrite(&idbuf,1,sizeof(idlog_t),f);
152 end:
153 if (i)
154 unlockfile(i);
155 fclose(f);
156 return (ret);
157 }
158
159 int mix2_decrypt(BUFFER *m)
160 /* 0: ok
161 * -1: error
162 * -2: old message */
163 {
164 int err = 0;
165 int i;
166 BUFFER *privkey;
167 BUFFER *keyid;
168 BUFFER *dec, *deskey;
169 BUFFER *packetid, *mid, *digest, *addr, *temp, *iv, *ivvec;
170 int type, packet = 0, numpackets = 0, timestamp = 0;
171 BUFFER *body;
172 BUFFER *header, *out;
173
174 privkey = buf_new();
175 keyid = buf_new();
176 dec = buf_new();
177 deskey = buf_new();
178 packetid = buf_new();
179 mid = buf_new();
180 digest = buf_new();
181 addr = buf_new();
182 temp = buf_new();
183 iv = buf_new();
184 ivvec = buf_new();
185 body = buf_new();
186 header = buf_new();
187 out = buf_new();
188
189 buf_get(m, keyid, 16);
190 err = db_getseckey(keyid->data, privkey);
191 if (err == -1)
192 goto end;
193 buf_get(m, deskey, buf_getc(m));
194 err = pk_decrypt(deskey, privkey);
195 if (err == -1 || deskey->length != 24) {
196 err = -1;
197 errlog(NOTICE, "Cannot decrypt message.\n");
198 goto end;
199 }
200 buf_get(m, iv, 8);
201 buf_get(m, dec, 328);
202 buf_crypt(dec, deskey, iv, DECRYPT);
203 buf_get(dec, packetid, 16);
204 buf_get(dec, deskey, 24);
205 type = buf_getc(dec);
206 switch (type) {
207 case 0:
208 buf_get(dec, ivvec, 152);
209 buf_get(dec, addr, 80);
210 break;
211 case 1:
212 buf_get(dec, mid, 16);
213 buf_get(dec, iv, 8);
214 break;
215 case 2:
216 packet = buf_getc(dec);
217 numpackets = buf_getc(dec);
218 buf_get(dec, mid, 16);
219 buf_get(dec, iv, 8);
220 break;
221 default:
222 errlog(WARNING, "Unknown message type.\n");
223 err = -1;
224 goto end;
225 }
226 if (dec->data[dec->ptr] == '0' && dec->data[dec->ptr + 1] == '0' &&
227 dec->data[dec->ptr + 2] == '0' && dec->data[dec->ptr + 3] == '0' &&
228 dec->data[dec->ptr + 4] == '\0') {
229 dec->ptr += 5;
230 timestamp = buf_geti_lo(dec);
231 } else {
232 errlog(LOG, "Ignoring message without timestamp.\n");
233 err = -1;
234 goto end;
235 }
236 buf_get(dec, digest, 16);
237
238 dec->length = dec->ptr - 16; /* ignore digest */
239 dec->ptr = dec->length;
240
241 if (!isdigest_md5(dec, digest)) {
242 errlog(NOTICE, "Message digest does not match.\n");
243 err = -1;
244 goto end;
245 }
246 switch (isnewid(packetid, timestamp * SECONDSPERDAY)) {
247 case 0: err = -2; /* redundant message */
248 goto end;
249 case -1: err = -1; /* future timestamp */
250 goto end;
251 }
252 buf_append(body, m->data + 20 * 512, 10240);
253
254 switch (type) {
255 case 0:
256 buf_chop(addr);
257 buf_cat(out, addr);
258 buf_nl(out);
259 for (i = 0; i < 19; i++) {
260 buf_reset(header);
261 buf_append(header, m->data + (i + 1) * 512, 512);
262 buf_reset(iv);
263 buf_append(iv, ivvec->data + i * 8, 8);
264 buf_crypt(header, deskey, iv, DECRYPT);
265 buf_cat(out, header);
266 }
267 buf_reset(header);
268 buf_pad(header, 512);
269 buf_cat(out, header);
270 buf_reset(iv);
271 buf_append(iv, ivvec->data + 144, 8);
272 buf_crypt(body, deskey, iv, DECRYPT);
273 buf_cat(out, body);
274 mix_pool(out, INTERMEDIATE, -1);
275 break;
276 case 1:
277 buf_crypt(body, deskey, iv, DECRYPT);
278 err = v2body_setlen(body);
279 if (err == -1)
280 goto end;
281 assert(body->ptr == 4);
282 v2body(body);
283 break;
284 case 2:
285 buf_crypt(body, deskey, iv, DECRYPT);
286 v2partial(body, mid, packet, numpackets);
287 break;
288 }
289 end:
290 buf_free(privkey);
291 buf_free(keyid);
292 buf_free(dec);
293 buf_free(deskey);
294 buf_free(packetid);
295 buf_free(mid);
296 buf_free(digest);
297 buf_free(addr);
298 buf_free(temp);
299 buf_free(iv);
300 buf_free(ivvec);
301 buf_free(body);
302 buf_free(header);
303 buf_free(out);
304
305 return (err);
306 }
307
308 int v2body_setlen(BUFFER *body)
309 {
310 long length;
311
312 length = buf_getl_lo(body);
313 if (length < 0 || length > body->length)
314 return (-1);
315 body->length = length + 4;
316 return (0);
317 }
318
319 int v2body(BUFFER *body)
320 {
321 int i, n;
322 BUFFER *to, *newsgroups;
323 BUFFER *temp, *out;
324 BUFFER *line;
325 int type = MSG_MAIL;
326 int subject = 0;
327
328 line = buf_new();
329 to = buf_new();
330 newsgroups = buf_new();
331 temp = buf_new();
332 out = buf_new();
333
334 n = buf_getc(body);
335 for (i = 0; i < n; i++) {
336 buf_get(body, line, 80);
337 buf_chop(line);
338 if (bufileft(line, "null:"))
339 goto end;
340 if (bufileft(line, "post:")) {
341 type = MSG_POST;
342 if (line->length > 5) {
343 int j = 5;
344
345 while (j < line->length && isspace(line->data[j]))
346 j++;
347 if (newsgroups->length > 0)
348 buf_appends(newsgroups, ",");
349 buf_append(newsgroups, line->data + j, line->length - j);
350 }
351 } else {
352 if (to->length > 0)
353 buf_appends(to, ",");
354 buf_cat(to, line);
355 }
356 }
357 if (to->length > 0) {
358 buf_appends(out, "To: ");
359 buf_cat(out, to);
360 buf_nl(out);
361 }
362 if (newsgroups->length > 0) {
363 buf_appends(out, "Newsgroups: ");
364 buf_cat(out, newsgroups);
365 buf_nl(out);
366 }
367 n = buf_getc(body);
368 for (i = 0; i < n; i++) {
369 buf_get(body, line, 80);
370 buf_chop(line);
371 if (bufileft(line, "Subject:"))
372 subject = 1;
373 buf_cat(out, line);
374 buf_nl(out);
375 }
376
377 buf_rest(temp, body);
378 buf_uncompress(temp);
379 buf_set(body, temp);
380 buf_reset(temp);
381
382 if (buf_lookahead(body, line) == 0 && isline(line, HASHMARK)) {
383 buf_getline(body, line);
384 while (buf_getline(body, line) == 0) {
385 if (bufileft(line, "subject:"))
386 subject = 1;
387 buf_cat(out, line);
388 buf_nl(out);
389 }
390 }
391 if (type == MSG_POST && !subject)
392 buf_appends(out, "Subject: (no subject)\n");
393
394 buf_nl(out);
395 buf_rest(out, body);
396 buf_reset(body);
397 mix_pool(out, type, -1);
398
399 end:
400 buf_free(line);
401 buf_free(to);
402 buf_free(newsgroups);
403 buf_free(temp);
404 buf_free(out);
405 return (0);
406 }
407
408 int v2_merge(BUFFER *mid)
409 {
410 char fname[PATHMAX], line[LINELEN];
411 BUFFER *temp, *msg;
412 FILE *l, *f;
413 int i, numpackets;
414 struct stat sb;
415 long d;
416 int n;
417 int err = -1;
418
419 temp = buf_new();
420 msg = buf_new();
421 pool_packetfile(fname, mid, 0);
422 l = fopen(fname, "a+");
423 if (l != NULL)
424 lock(l);
425
426 pool_packetfile(fname, mid, 1);
427 f = fopen(fname, "rb");
428 if (f == NULL)
429 goto end;
430 fscanf(f, "%32s %ld %d %d\n", line, &d, &i, &numpackets);
431 fclose(f);
432
433 /* do we have all packets? */
434 for (i = 1; i <= numpackets; i++) {
435 pool_packetfile(fname, mid, i);
436 if (stat(fname, &sb) != 0)
437 goto end;
438 }
439 errlog(LOG, "Reassembling multipart message.\n");
440 for (i = 1; i <= numpackets; i++) {
441 pool_packetfile(fname, mid, i);
442 f = fopen(fname, "rb");
443 if (f == NULL)
444 goto end;
445 fscanf(f, "%32s %ld %d %d\n", line, &d, &n, &n);
446 buf_clear(temp);
447 buf_read(temp, f);
448 v2body_setlen(temp);
449 buf_append(msg, temp->data + 4, temp->length - 4);
450 fclose(f);
451 unlink(fname);
452 }
453 err = v2body(msg);
454
455 end:
456 if (l != NULL)
457 fclose(l);
458 pool_packetfile(fname, mid, 0);
459 unlink(fname);
460 buf_free(temp);
461 buf_free(msg);
462 return (err);
463 }
464
465 int v2partial(BUFFER *m, BUFFER *mid, int packet, int numpackets)
466 {
467 char fname[PATHMAX], idstr[33];
468 FILE *f;
469 int err = 1;
470
471 pool_packetfile(fname, mid, packet);
472 f = fopen(fname, "wb");
473 if (f == NULL) {
474 err = -1;
475 goto end;
476 }
477 id_encode(mid->data, idstr);
478 fprintf(f, "%s %ld %d %d\n", idstr, (long) time(NULL), packet,
479 numpackets);
480 buf_write(m, f);
481 buf_reset(m);
482 fclose(f);
483 v2_merge(mid);
484 end:
485 return (err);
486 }