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 }