mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

rem1.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 }