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