mixmaster

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

nym.c (15627B)


      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    Create nym server messages
      9    $Id: nym.c 934 2006-06-24 13:40:39Z rabbi $ */
     10 
     11 
     12 #ifdef NYMSUPPORT
     13 
     14 #include "mix3.h"
     15 #include "pgp.h"
     16 #include <string.h>
     17 #include <time.h>
     18 #include <assert.h>
     19 
     20 int nym_config(int mode, char *nym, char *nymserver, BUFFER *pseudonym,
     21 	       char *sendchain, int sendnumcopies, BUFFER *chains,
     22 	       BUFFER *options)
     23 {
     24 #ifndef USE_PGP
     25   return (-1);
     26 #else /* end of not USE_PGP */
     27   REMAILER remailer[MAXREM];
     28   int badchains[MAXREM][MAXREM];
     29   KEYRING *r;
     30   int maxrem;
     31   int chain[20];
     32   char rchain[CHAINMAX];
     33   BUFFER *userid, *msg, *req, *k, *line, *ek, *eklist, *key, *pubkey, *out,
     34       *oldchains;
     35   int latency;
     36   int err = -1;
     37   int status;
     38   int desttype = MSG_MAIL;
     39   int rblock = 0;
     40   BUFFER *nymlist, *userpass, *config;
     41   LOCK *nymlock;
     42 
     43   userid = buf_new();
     44   msg = buf_new();
     45   req = buf_new();
     46   k = buf_new();
     47   line = buf_new();
     48   ek = buf_new();
     49   eklist = buf_new();
     50   key = buf_new();
     51   pubkey = buf_new();
     52   out = buf_new();
     53   config = buf_new();
     54   nymlist = buf_new();
     55   userpass = buf_new();
     56   oldchains = buf_new();
     57 
     58   for (;;) {
     59     user_pass(userpass);
     60     if (user_confirmpass(userpass))
     61       break;
     62     user_delpass();
     63   }
     64 
     65   if (nymserver) {
     66     maxrem = t1_rlist(remailer, badchains);
     67     if (maxrem < 1)
     68       return (-1);
     69     if (chain_select(chain, nymserver, maxrem, remailer, 2, NULL) != 1)
     70       return (-1);
     71     if (chain[0] == 0)
     72       chain[0] = chain_randfinal(MSG_MAIL, remailer, badchains, maxrem, 2, NULL, -1);
     73     if (chain[0] == -1)
     74       return (-1);
     75     assert(strchr(nym, '@') == NULL && strchr(remailer[chain[0]].addr, '@'));
     76     strcatn(nym, strchr(remailer[chain[0]].addr, '@'), LINELEN);
     77     buf_appends(config, remailer[chain[0]].addr);
     78   } else
     79     assert(strchr(nym, '@') != NULL);
     80 
     81   status = nymlist_getnym(nym, config->length ? NULL : config, eklist, NULL,
     82 			  NULL, oldchains);
     83   if (mode == NYM_CREATE && status == NYM_OK)
     84     mode = NYM_MODIFY;
     85 
     86   buf_appendc(userid, '<');
     87   buf_appends(userid, nym);
     88   buf_appendc(userid, '>');
     89 
     90   buf_sets(req, "Config:\nFrom: ");
     91   buf_append(req, nym, strchr(nym, '@') - nym);
     92   buf_appends(req, "\nNym-Commands:");
     93   if (mode == NYM_CREATE)
     94     buf_appends(req, " create?");
     95   if (mode == NYM_DELETE)
     96     buf_appends(req, " delete");
     97   else {
     98     if (options && options->length > 0) {
     99       if (!bufleft(options, " "))
    100 	buf_appendc(req, ' ');
    101       buf_cat(req, options);
    102     }
    103     if (pseudonym && pseudonym->length > 0) {
    104       buf_appends(req, " name=\"");
    105       buf_cat(req, pseudonym);
    106       buf_appendc(req, '\"');
    107     }
    108   }
    109   buf_nl(req);
    110   if (mode == NYM_CREATE) {
    111     buf_appends(req, "Public-Key:\n");
    112 
    113   getkey:
    114     r = pgpdb_open(NYMSECRING, userpass, 0, PGP_TYPE_PRIVATE);
    115     if (r == NULL) {
    116       err = -3;
    117       goto end;
    118     }
    119     if (r->filetype == -1)
    120       r->filetype = 0;
    121 
    122     while (pgpdb_getnext(r, key, NULL, userid) != -1)
    123       if (pgp_makepubkey(key, NULL, pubkey, userpass, 0) == 0)
    124 	err = 0;
    125     pgpdb_close(r);
    126     if (err != 0) {
    127       if (err == -2)
    128 	goto end;
    129       err = -2;
    130       if (pseudonym && pseudonym->length) {
    131 	buf_set(userid, pseudonym);
    132 	buf_appendc(userid, ' ');
    133       } else
    134 	buf_clear(userid);
    135       buf_appendf(userid, "<%s>", nym);
    136       pgp_keygen(PGP_ES_RSA, 0, userid, userpass, NULL, NYMSECRING, 2);
    137       goto getkey;
    138     }
    139     pgp_armor(pubkey, PGP_ARMOR_NYMKEY);
    140     buf_cat(req, pubkey);
    141   }
    142   if (mode != NYM_DELETE) {
    143     if (nymlist_read(nymlist) == -1) {
    144       user_delpass();
    145       err = -1;
    146       goto end;
    147     }
    148     if (chains)
    149       for (;;) {
    150 	err = buf_getheader(chains, k, line);
    151 	if (err == -1 && rblock == 0)
    152 	  break;
    153 	if (err != 0 && rblock == 1) {
    154 	  buf_setrnd(ek, 16);
    155 	  if (t1_encrypt(desttype, msg, rchain, latency, ek, NULL) != 0) {
    156 	    err = -2;
    157 	    goto end;
    158 	  }
    159 	  encode(ek, 0);
    160 	  buf_cat(eklist, ek);
    161 	  buf_nl(eklist);
    162 	  buf_appends(req, "Reply-Block:\n");
    163 	  buf_cat(req, msg);
    164 	  buf_clear(msg);
    165 	  rblock = 0;
    166 	  continue;
    167 	}
    168 	if (bufieq(k, "Chain"))
    169 	  strncpy(rchain, line->data, sizeof(rchain));
    170 	else if (bufieq(k, "Latency"))
    171 	  sscanf(line->data, "%d", &latency);
    172 	else if (bufieq(k, "Null"))
    173 	  desttype = MSG_NULL, rblock = 1;
    174 	else {
    175 	  buf_appendheader(msg, k, line);
    176 	  if (bufieq(k, "To"))
    177 	    desttype = MSG_MAIL, rblock = 1;
    178 	  if (bufieq(k, "Newsgroups"))
    179 	    desttype = MSG_POST, rblock = 1;
    180 	}
    181       }
    182   }
    183   nymlock = lockfile(NYMDB);
    184   if (nymlist_read(nymlist) == 0) {
    185     nymlist_del(nymlist, nym);
    186     nymlist_append(nymlist, nym, config, options, pseudonym,
    187 		   chains ? chains : oldchains, eklist,
    188 		   mode == NYM_DELETE ? NYM_DELETED :
    189 		   (status == -1 ? NYM_WAITING : status));
    190     nymlist_write(nymlist);
    191   } else
    192     err = -1;
    193   unlockfile(nymlock);
    194 
    195 #ifdef DEBUG
    196   buf_write(req, stderr);
    197 #endif /* DEBUG */
    198   buf_clear(line);
    199   buf_appendc(line, '<');
    200   buf_cat(line, config);
    201   buf_appendc(line, '>');
    202 
    203   err = pgp_encrypt(PGP_ENCRYPT | PGP_SIGN | PGP_TEXT | PGP_REMAIL,
    204 		    req, line, userid, userpass, NULL, NYMSECRING);
    205   if (err != 0)
    206     goto end;
    207 #ifdef DEBUG
    208   buf_write(req, stderr);
    209 #endif /* DEBUG */
    210   buf_sets(out, "To: ");
    211   buf_cat(out, config);
    212   buf_nl(out);
    213   buf_nl(out);
    214   buf_cat(out, req);
    215 
    216   err = mix_encrypt(desttype, out, sendchain, sendnumcopies, line);
    217   if (err)
    218     mix_status("%s\n", line->data);
    219 
    220 end:
    221   if (strchr(nym, '@')) *strchr(nym, '@') = '\0';
    222   buf_free(userid);
    223   buf_free(msg);
    224   buf_free(req);
    225   buf_free(k);
    226   buf_free(line);
    227   buf_free(ek);
    228   buf_free(eklist);
    229   buf_free(key);
    230   buf_free(pubkey);
    231   buf_free(out);
    232   buf_free(nymlist);
    233   buf_free(userpass);
    234   buf_free(oldchains);
    235   buf_free(config);
    236   return (err);
    237 #endif /* else if USE_PGP */
    238 }
    239 
    240 int nym_encrypt(BUFFER *msg, char *nym, int type)
    241 {
    242 #ifndef USE_PGP
    243   return (-1);
    244 #else /* end of not USE_PGP */
    245   BUFFER *out, *userpass, *sig, *config;
    246   int err = -1;
    247 
    248   out = buf_new();
    249   userpass = buf_new();
    250   sig = buf_new();
    251   config = buf_new();
    252 
    253   if (nymlist_getnym(nym, config, NULL, NULL, NULL, NULL) == NYM_OK) {
    254     buf_appends(out, "From: ");
    255     buf_append(out, nym, strchr(nym, '@') - nym);
    256     buf_nl(out);
    257     if (type == MSG_POST) {
    258       buf_appends(out, "To: ");
    259       buf_appends(out, MAILtoNEWS);
    260       buf_nl(out);
    261     }
    262     buf_cat(out, msg);
    263     mail_encode(out, 0);
    264     buf_appendc(sig, '<');
    265     buf_appends(sig, nym);
    266     buf_appendc(sig, '>');
    267 #ifdef DEBUG
    268     buf_write(out, stderr);
    269 #endif /* DEBUG */
    270     user_pass(userpass);
    271     err = pgp_encrypt(PGP_ENCRYPT | PGP_SIGN | PGP_TEXT | PGP_REMAIL,
    272 		      out, config, sig, userpass, NULL, NYMSECRING);
    273     if (err == 0) {
    274       buf_clear(msg);
    275       buf_appends(msg, "To: send");
    276       buf_appends(msg, strchr(nym, '@'));
    277       buf_nl(msg);
    278       buf_nl(msg);
    279       buf_cat(msg, out);
    280     }
    281   }
    282   buf_free(out);
    283   buf_free(config);
    284   buf_free(userpass);
    285   buf_free(sig);
    286   return (err);
    287 #endif /* else if USE_PGP */
    288 }
    289 
    290 int nym_decrypt(BUFFER *msg, char *thisnym, BUFFER *log)
    291 {
    292 #ifndef USE_PGP
    293   return (-1);
    294 #else /* end of not USE_PGP */
    295   BUFFER *pgpmsg, *out, *line;
    296   BUFFER *nymlist, *userpass;
    297   BUFFER *decr, *sig, *mid;
    298   BUFFER *name, *rblocks, *eklist, *config;
    299   int decrypted = 0;
    300   int err = 1;
    301   long ptr;
    302   char nym[LINELEN];
    303   BUFFER *ek, *opt;
    304   int status;
    305   LOCK *nymlock;
    306   time_t t;
    307   struct tm *tc;
    308   char timeline[LINELEN];
    309 
    310   pgpmsg = buf_new();
    311   out = buf_new();
    312   line = buf_new();
    313   nymlist = buf_new();
    314   userpass = buf_new();
    315   config = buf_new();
    316   ek = buf_new();
    317   decr = buf_new();
    318   sig = buf_new();
    319   mid = buf_new();
    320   opt = buf_new();
    321   name = buf_new();
    322   rblocks = buf_new();
    323   eklist = buf_new();
    324 
    325   if (thisnym)
    326     thisnym[0] = '\0';
    327   while ((ptr = msg->ptr, err = buf_getline(msg, line)) != -1) {
    328     if (bufleft(line, begin_pgpmsg)) {
    329       err = -1;
    330       msg->ptr = ptr;
    331       pgp_dearmor(msg, pgpmsg);
    332       if (pgp_isconventional(pgpmsg)) {
    333 	user_pass(userpass);
    334 	nymlock = lockfile(NYMDB);
    335 	if (nymlist_read(nymlist) == -1)
    336 	  user_delpass();
    337 	while (nymlist_get(nymlist, nym, config, eklist, opt, name,
    338 			   rblocks, &status) >= 0) {
    339 	  while (buf_getline(eklist, ek) == 0) {
    340 	    decode(ek, ek);
    341 	    if (t1_getreply(pgpmsg, ek, 20) == 0) {
    342 	      buf_clear(out);
    343 	      err = pgp_decrypt(pgpmsg, userpass, sig, NULL,
    344 				NYMSECRING);
    345 	      buf_sets(out, "From nymserver ");
    346 	      if (strchr(sig->data, '[') && strchr(sig->data, ']'))
    347 		buf_append(out, strchr(sig->data, '[') + 1,
    348 			   strchr(sig->data, ']') -
    349 			   strchr(sig->data, '[') - 1);
    350 	      else {
    351 		t = time(NULL);
    352 		tc = localtime(&t);
    353 		strftime(timeline, LINELEN, "%a %b %d %H:%M:%S %Y", tc);
    354 		buf_appends(out, timeline);
    355 	      }
    356 	      buf_nl(out);
    357 	      if (err == PGP_SIGOK &&
    358 		  bufifind(sig, config->data)) {
    359 		buf_appends(out, "Nym: ");
    360 		if (status == NYM_WAITING)
    361 		  buf_appends(out, "confirm ");
    362 		buf_appends(out, nym);
    363 		buf_nl(out);
    364 		if (thisnym && status == NYM_OK)
    365 		  strncpy(thisnym, nym, LINELEN);
    366 	      } else
    367 		buf_appends(out, "Warning: Signature verification failed!\n");
    368 	      buf_cat(out, pgpmsg);
    369 	      decrypted = 2;
    370 	      if (log) {
    371 		digest_md5(out, mid);
    372 		encode(mid, 0);
    373 		if (buffind(log, mid->data)) {
    374 		  decrypted = -1;
    375 		  unlockfile(nymlock);
    376 		  goto end;
    377 		} else {
    378 		  buf_cat(log, mid);
    379 		  buf_nl(log);
    380 		}
    381 	      }
    382 	      if (status == NYM_WAITING) {
    383 		nymlist_del(nymlist, nym);
    384 		nymlist_append(nymlist, nym, config, opt,
    385 			       name, rblocks, eklist, NYM_OK);
    386 	      }
    387 	      break;
    388 	    }
    389 	  }
    390 	}
    391 	nymlist_write(nymlist);
    392 	unlockfile(nymlock);
    393       }
    394       if (decrypted == 0) {
    395 	user_pass(userpass);
    396 	err = pgp_decrypt(pgpmsg, userpass, sig, PGPPUBRING, PGPSECRING);
    397 	if (err == PGP_ERR)
    398 	  err = pgp_decrypt(pgpmsg, userpass, sig, PGPPUBRING,
    399 			    NYMSECRING);
    400 #if 0
    401 	if (err == PGP_PASS || err == PGP_ERR)
    402 	  user_delpass();
    403 #endif /* 0 */
    404 	if (err != PGP_ERR && err != PGP_PASS && err != PGP_NOMSG &&
    405 	    err != PGP_NODATA) {
    406 	  buf_appends(out, info_beginpgp);
    407 	  if (err == PGP_SIGOK)
    408 	    buf_appendf(out, " (SIGNED)\n%s%b", info_pgpsig, sig);
    409 	  buf_nl(out);
    410 	  buf_cat(out, pgpmsg);
    411 	  buf_appends(out, info_endpgp);
    412 	  buf_nl(out);
    413 	  decrypted = 1;
    414 	}
    415       }
    416       if (decrypted == 0) {
    417 	buf_cat(out, line);
    418 	buf_nl(out);
    419       }
    420     } else {
    421       if (bufileft(line, info_beginpgp))
    422 	  buf_appendc(out, ' '); /* escape info line in text */
    423       buf_cat(out, line);
    424       buf_nl(out);
    425     }
    426   }
    427 
    428   if (decrypted)
    429     buf_move(msg, out);
    430   else
    431     buf_rewind(msg);
    432   if (decrypted == 2)
    433     nym_decrypt(msg, thisnym, NULL);
    434 end:
    435   buf_free(pgpmsg);
    436   buf_free(out);
    437   buf_free(line);
    438   buf_free(decr);
    439   buf_free(sig);
    440   buf_free(mid);
    441   buf_free(opt);
    442   buf_free(name);
    443   buf_free(config);
    444   buf_free(rblocks);
    445   buf_free(eklist);
    446   buf_free(nymlist);
    447   buf_free(userpass);
    448   buf_free(ek);
    449   return (decrypted);
    450 #endif /* else if USE_PGP */
    451 }
    452 
    453 int nymlist_read(BUFFER *list)
    454 {
    455 #ifdef USE_PGP
    456   BUFFER *key;
    457 
    458 #endif /* USE_PGP */
    459   FILE *f;
    460   int err = 0;
    461 
    462   buf_clear(list);
    463   f = mix_openfile(NYMDB, "rb");
    464   if (f != NULL) {
    465     buf_read(list, f);
    466     fclose(f);
    467 #ifdef USE_PGP
    468     key = buf_new();
    469     user_pass(key);
    470     if (key->length)
    471       if (pgp_decrypt(list, key, NULL, NULL, NULL) < 0) {
    472 	buf_clear(list);
    473 	err = -1;
    474       }
    475     buf_free(key);
    476 #endif /* USE_PGP */
    477   }
    478   return (err);
    479 }
    480 
    481 int nymlist_write(BUFFER *list)
    482 {
    483 #ifdef USE_PGP
    484   BUFFER *key;
    485 
    486 #endif /* USE_PGP */
    487   FILE *f;
    488 
    489   if (list->length == 0)
    490     return (-1);
    491 
    492 #ifdef USE_PGP
    493   key = buf_new();
    494   user_pass(key);
    495   if (key->length)
    496     pgp_encrypt(PGP_NCONVENTIONAL | PGP_NOARMOR, list, key, NULL, NULL, NULL,
    497 		NULL);
    498   buf_free(key);
    499 #endif /* USE_PGP */
    500   f = mix_openfile(NYMDB, "wb");
    501   if (f == NULL)
    502     return (-1);
    503   else {
    504     buf_write(list, f);
    505     fclose(f);
    506   }
    507   return (0);
    508 }
    509 
    510 int nymlist_get(BUFFER *list, char *nym, BUFFER *config, BUFFER *ek,
    511 		BUFFER *opt, BUFFER *name, BUFFER *chains, int *status)
    512 {
    513   BUFFER *line;
    514   int err = -1;
    515 
    516   line = buf_new();
    517   if (ek)
    518     buf_clear(ek);
    519   if (opt)
    520     buf_clear(opt);
    521   if (name)
    522     buf_clear(name);
    523   if (chains)
    524     buf_clear(chains);
    525   if (config)
    526     buf_clear(config);
    527 
    528   for (;;) {
    529     if (buf_getline(list, line) == -1)
    530       goto end;
    531     if (bufleft(line, "nym="))
    532       break;
    533   }
    534   strncpy(nym, line->data + 4, LINELEN);
    535 
    536   for (;;) {
    537     if (buf_getline(list, line) == -1)
    538       break;
    539     if (opt && bufleft(line, "opt="))
    540       line->ptr = 4, buf_rest(opt, line);
    541     if (name && bufleft(line, "name="))
    542       line->ptr = 5, buf_rest(name, line);
    543     if (config && bufleft(line, "config="))
    544       line->ptr = 7, buf_rest(config, line);
    545     if (bufeq(line, "ek=")) {
    546       while (buf_getline(list, line) == 0 && !bufeq(line, "end ek"))
    547 	if (ek) {
    548 	  buf_cat(ek, line);
    549 	  buf_nl(ek);
    550 	}
    551     }
    552     if (bufeq(line, "chains=")) {
    553       while (buf_getline(list, line) == 0 && !bufeq(line, "end chains"))
    554 	if (chains) {
    555 	  buf_cat(chains, line);
    556 	  buf_nl(chains);
    557 	}
    558     }
    559     if (status && bufleft(line, "status="))
    560       *status = line->data[7] - '0';
    561     if (bufeq(line, "end")) {
    562       err = 0;
    563       break;
    564     }
    565   }
    566 end:
    567   buf_free(line);
    568   return (err);
    569 }
    570 
    571 int nymlist_append(BUFFER *list, char *nym, BUFFER *config, BUFFER *opt,
    572 		   BUFFER *name, BUFFER *rblocks, BUFFER *eklist, int status)
    573 {
    574   buf_appends(list, "nym=");
    575   buf_appends(list, nym);
    576   buf_nl(list);
    577   buf_appends(list, "config=");
    578   buf_cat(list, config);
    579   buf_nl(list);
    580   buf_appends(list, "status=");
    581   buf_appendc(list, (byte) (status + '0'));
    582   buf_nl(list);
    583   if (name) {
    584     buf_appends(list, "name=");
    585     buf_cat(list, name);
    586     buf_nl(list);
    587   }
    588   buf_appends(list, "opt=");
    589   buf_cat(list, opt);
    590   buf_nl(list);
    591   buf_appends(list, "chains=\n");
    592   buf_cat(list, rblocks);
    593   buf_appends(list, "end chains\n");
    594   buf_appends(list, "ek=\n");
    595   buf_cat(list, eklist);
    596   buf_appends(list, "end ek\n");
    597   buf_appends(list, "end\n");
    598   return (0);
    599 }
    600 
    601 int nymlist_del(BUFFER *list, char *nym)
    602 {
    603   BUFFER *new;
    604   char thisnym[LINELEN];
    605   BUFFER *config, *ek, *name, *rblocks, *opt;
    606   int thisstatus;
    607 
    608   new = buf_new();
    609   config = buf_new();
    610   ek = buf_new();
    611   name = buf_new();
    612   rblocks = buf_new();
    613   opt = buf_new();
    614 
    615   buf_rewind(list);
    616   while (nymlist_get(list, thisnym, config, ek, opt, name, rblocks,
    617 		     &thisstatus) >= 0)
    618     if (!streq(nym, thisnym))
    619       nymlist_append(new, thisnym, config, opt, name, rblocks, ek,
    620 		     thisstatus);
    621 
    622   buf_move(list, new);
    623   buf_free(new);
    624   buf_free(name);
    625   buf_free(opt);
    626   buf_free(rblocks);
    627   buf_free(config);
    628   buf_free(ek);
    629   return (0);
    630 }
    631 
    632 int nymlist_getnym(char *nym, BUFFER *config, BUFFER *ek, BUFFER *opt,
    633 		   BUFFER *name, BUFFER *rblocks)
    634      /* "nym@nymserver.domain" or "nym@" */
    635 {
    636   BUFFER *nymlist, *userpass;
    637   char n[LINELEN];
    638   int err = -1;
    639   int status;
    640 
    641   nymlist = buf_new();
    642   userpass = buf_new();
    643 
    644   user_pass(userpass);
    645   if (nymlist_read(nymlist) != -1) {
    646     while (nymlist_get(nymlist, n, config, ek, opt, name, rblocks,
    647 		       &status) >= 0)
    648       if (streq(nym, n) || (nym[strlen(nym) - 1] == '@' && strleft(n, nym))) {
    649 	err = status;
    650 	strncpy(nym, n, LINELEN);
    651 	break;
    652       }
    653   }
    654   buf_free(userpass);
    655   buf_free(nymlist);
    656   return (err);
    657 }
    658 
    659 int nymlist_getstatus(char *nym)
    660 {
    661   int status;
    662 
    663   if ((status = nymlist_getnym(nym, NULL, NULL, NULL, NULL, NULL)) == 0)
    664     return (status);
    665   else
    666     return (-1);
    667 }
    668 
    669 #endif /* NYMSUPPORT */