tnym.c - mixmaster - mixmaster 3.0 patched for libressl
HTML git clone git://parazyd.org/mixmaster.git
DIR Log
DIR Files
DIR Refs
DIR README
---
tnym.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 */