trem2.c - mixmaster - mixmaster 3.0 patched for libressl
 (HTM) 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 }