/[pkg-mixmaster]/trunk/Mix/Src/main.c
ViewVC logotype

Contents of /trunk/Mix/Src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 197 - (show annotations) (download)
Wed Aug 28 09:35:25 2002 UTC (10 years, 9 months ago) by weaselp
File MIME type: text/plain
File size: 17911 byte(s)
Write a pid file
1 /* Mixmaster version 3 -- (C) 1999 Anonymizer Inc.
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 Command-line based frontend
9 $Id: main.c,v 1.18 2002/08/28 09:35:25 weaselp Exp $ */
10
11
12 #include "mix3.h"
13 #include "pgp.h"
14 #include <stdio.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <stdlib.h>
18 #ifdef POSIX
19 #include <unistd.h>
20 #else
21 #include <io.h>
22 #endif
23
24 static char *largopt(char *p, char *opt, char *name, int *error);
25 static void noarg(char *name, char p);
26 static int check_get_pass(int force);
27
28 /** main *****************************************************************/
29
30 /* Returns:
31 0 successful operation
32 1 command line error
33 2 client error condition */
34
35 #ifdef WIN32SERVICE
36 int mix_main(int argc, char *argv[])
37 #else
38 int main(int argc, char *argv[])
39 #endif
40 {
41 int error = 0, deflt = 1, help = 0, readmail = 0, send = -1, sendpool = 0,
42 header = 1, maint = 0, keygen = 0, verbose = 2, sign = 0, encrypt = 0;
43 int daemon = 0, type_list = 0, nodetach = 0;
44
45 #ifdef USE_SOCK
46 int pop3 = 0;
47
48 #endif
49 char *filename = NULL;
50 int i;
51 int ret = 0;
52 char *p, *q;
53 char chain[1024] = "";
54 char nym[LINELEN] = "";
55 BUFFER *nymopt, *pseudonym, *attachments;
56 int numcopies = 0; /* default value set in mix.cfg */
57 BUFFER *msg, *chainlist, *field, *content;
58 FILE *f;
59
60 mix_init(NULL);
61
62 msg = buf_new();
63 chainlist = buf_new();
64 nymopt = buf_new();
65 pseudonym = buf_new();
66 attachments = buf_new();
67 field = buf_new();
68 content = buf_new();
69
70 #ifdef USE_NCURSES
71 if (argc == 1) {
72 if (isatty(fileno(stdin)))
73 menu_main();
74 else
75 menu_folder(0, NULL);
76 goto end;
77 }
78 #endif
79 if (argc > 1 && strleft(argv[1], "-f")) {
80 menu_folder(strlen(argv[1]) > 2 ? argv[1][2] : 0,
81 argc < 3 ? NULL : argv[2]);
82 goto end;
83 }
84 for (i = 1; i < argc; i++) {
85 p = argv[i];
86 if (p[0] == '-' && p[1] != '\0') {
87 if (p[1] == '-') {
88 p += 2;
89 if (strieq(p, "help"))
90 help = 1, deflt = 0;
91 else if (streq(p, "verbose"))
92 verbose = 1;
93 else if (streq(p, "type-list"))
94 type_list = 1;
95 else if (streq(p, "dummy"))
96 send = MSG_NULL, deflt = 0;
97 else if (streq(p, "remailer"))
98 maint = 1, deflt = 0;
99 else if (streq(p, "generate-key"))
100 keygen = 2, deflt = 0;
101 else if (streq(p, "update-keys"))
102 keygen = 1, deflt = 0;
103 else if (streq(p, "send"))
104 sendpool = 1, deflt = 0;
105 else if (streq(p, "read-mail"))
106 readmail = 1, deflt = 0;
107 else if (streq(p, "store-mail"))
108 readmail = 2, deflt = 0;
109 #ifdef USE_SOCK
110 else if (streq(p, "pop-mail"))
111 pop3 = 1, deflt = 0;
112 #endif
113 else if (streq(p, "daemon"))
114 daemon = 1, deflt = 0;
115 else if (streq(p, "no-detach"))
116 nodetach = 1;
117 else if (streq(p, "post"))
118 send = MSG_POST;
119 else if (streq(p, "mail"))
120 send = MSG_MAIL;
121 else if (streq(p, "sign"))
122 sign = 1;
123 else if (streq(p, "encrypt"))
124 encrypt = 1;
125 else if ((q = largopt(p, "to", argv[0], &error)) != NULL) {
126 header = 0;
127 buf_appendf(msg, "To: %s\n", q);
128 } else if ((q = largopt(p, "post-to", argv[0], &error)) != NULL) {
129 send = MSG_POST, header = 0;
130 buf_appendf(msg, "Newsgroups: %s\n", q);
131 } else if ((q = largopt(p, "subject", argv[0], &error)) != NULL) {
132 buf_appendf(msg, "Subject: %s\n", q);
133 } else if ((q = largopt(p, "header", argv[0], &error)) != NULL) {
134 buf_appendf(msg, "%s\n", q);
135 } else if ((q = largopt(p, "chain", argv[0], &error)) != NULL) {
136 buf_appendf(msg, "Chain: %s\n", q);
137 }
138 #ifdef USE_PGP
139 else if ((q = largopt(p, "reply-chain", argv[0], &error)) != NULL) {
140 buf_appendf(msg, "Reply-Chain: %s\n", q);
141 } else if ((q = largopt(p, "latency", argv[0], &error)) != NULL) {
142 buf_appendf(msg, "Latency: %s\n", q);
143 } else if ((q = largopt(p, "attachment", argv[0], &error)) != NULL) {
144 buf_appendf(attachments, "%s\n", q);
145 } else if ((q = largopt(p, "nym-config", argv[0], &error)) != NULL) {
146 deflt = 0;
147 strncpy(nym, q, sizeof(nym));
148 if (i > argc && strileft(argv[i + 1], "name="))
149 buf_sets(pseudonym, argv[++i] + 5);
150 else if (i > argc && strileft(argv[i + 1], "opt="))
151 buf_appends(nymopt, argv[++i] + 5);
152 } else if ((q = largopt(p, "nym", argv[0], &error)) != NULL) {
153 buf_appendf(msg, "Nym: %s\n", q);
154 }
155 #endif
156 else if ((q = largopt(p, "copies", argv[0], &error)) != NULL) {
157 sscanf(q, "%d", &numcopies);
158 } else if (error == 0 && mix_configline(p) == 0) {
159 fprintf(stderr, "%s: Invalid option %s\n", argv[0], argv[i]);
160 error = 1;
161 }
162 } else {
163 while (*++p) {
164 switch (*p) {
165 case 'd':
166 send = MSG_NULL, deflt = 0;
167 break;
168 case 'R':
169 readmail = 1, deflt = 0;
170 break;
171 case 'I':
172 readmail = 2, deflt = 0;
173 break;
174 case 'S':
175 sendpool = 1, deflt = 0;
176 break;
177 case 'M':
178 maint = 1, deflt = 0;
179 break;
180 #ifdef USE_SOCK
181 case 'P':
182 pop3 = 1, deflt = 0;
183 break;
184 #endif
185 case 'D':
186 daemon = 1, deflt = 0;
187 break;
188 case 'G':
189 keygen = 2, deflt = 0;
190 break;
191 case 'K':
192 keygen = 1, deflt = 0;
193 break;
194 case 'L': /* backwards compatibility */
195 break;
196 case 'v':
197 verbose = 1;
198 break;
199 case 'h':
200 help = 1, deflt = 0;
201 break;
202 case 'T':
203 type_list = 1;
204 break;
205 case 't':
206 if (*(p + 1) == 'o')
207 p++;
208 header = 0;
209 if (i < argc - 1)
210 buf_appendf(msg, "To: %s\n", argv[++i]);
211 else {
212 fprintf(stderr, "%s: Missing argument for option -to\n",
213 argv[0]);
214 error = 1;
215 }
216 break;
217 case 's':
218 if (i < argc - 1)
219 buf_appendf(msg, "Subject: %s\n", argv[++i]);
220 else {
221 noarg(argv[0], *p);
222 error = 1;
223 }
224 break;
225 case 'l':
226 if (i < argc - 1)
227 buf_appendf(msg, "Chain: %s\n", argv[++i]);
228 else {
229 noarg(argv[0], *p);
230 error = 1;
231 }
232 break;
233 case 'r':
234 if (i < argc - 1)
235 buf_appendf(msg, "Reply-Chain: %s\n", argv[++i]);
236 else {
237 noarg(argv[0], *p);
238 error = 1;
239 }
240 break;
241 #ifdef USE_PGP
242 case 'n':
243 if (i < argc - 1)
244 buf_appendf(msg, "Nym: %s\n", argv[++i]);
245 else {
246 noarg(argv[0], *p);
247 error = 1;
248 }
249 break;
250 #endif
251 case 'c':
252 if (i < argc - 1)
253 sscanf(argv[++i], "%d", &numcopies);
254 else {
255 noarg(argv[0], *p);
256 error = 1;
257 }
258 break;
259 case 'p':
260 send = MSG_POST;
261 break;
262 case 'g':
263 if (i < argc - 1) {
264 send = MSG_POST, header = 0;
265 buf_appendf(msg, "Newsgroups: %s\n", argv[++i]);
266 } else {
267 noarg(argv[0], *p);
268 error = 1;
269 }
270 break;
271 case 'a':
272 if (i < argc - 1)
273 buf_appendf(attachments, "%s\n", argv[++i]);
274 else {
275 noarg(argv[0], *p);
276 error = 1;
277 }
278 break;
279 case 'm':
280 send = MSG_MAIL;
281 break;
282 default:
283 fprintf(stderr, "%s: Invalid option -%c\n", argv[0], *p);
284 error = 1;
285 break;
286 }
287 }
288 }
289 } else {
290 if (strchr(argv[i], '@')) {
291 header = 0;
292 buf_appendf(msg, "To: %s\n", argv[i]);
293 } else {
294 if (filename == NULL)
295 filename = argv[i];
296 else {
297 fprintf(stderr, "%s: Error in command line: %s\n", argv[0], argv[i]);
298 error = 1;
299 }
300 }
301 }
302 }
303
304 if (error) {
305 ret = 1;
306 goto end;
307 }
308 if (type_list) {
309 BUFFER *type2list;
310 type2list = buf_new();
311 if (prepare_type2list(type2list) < 0) {
312 fprintf(stderr, "Cannot print type2.list.\n");
313 ret = 2;
314 } else {
315 printf("%s", type2list->data);
316 };
317 buf_free(type2list);
318 goto end;
319 }
320 if (help || (isatty(fileno(stdin)) && isatty(fileno(stdout))))
321 fprintf(stderr, "Mixmaster %s - %s\n", VERSION, COPYRIGHT);
322
323 if (help) {
324 printf("Usage: %s [options] [user@host] [filename]\n\n", argv[0]);
325 printf("Options:\n\
326 \n\
327 -h, --help summary of command line options\n\
328 -T, --type-list list available remailers\n\
329 -t, --to=user@host the recipient's address(es)\n\
330 -g, --post-to=newsgroup newsgroup(s) to post to\n\
331 -p, --post input is a Usenet article\n\
332 -m, --mail input is a mail message\n\
333 -s, --subject=subject message subject\n\
334 --header='header line' arbitrary message headers\n\
335 -a, --attachment=file attach a file\n"
336 #ifdef USE_PGP
337 "-n, --nym=yournym use pseudonym to send the message\n\
338 --encrypt encrypt the message using the PGP format\n\
339 --sign sign the message using the PGP format\n"
340 #endif
341 "-l, --chain=mix1,mix2,mix3,... specify a remailer chain\n\
342 -c, --copies=num send num copies to increase reliability\n\
343 -d, --dummy generate a dummy message\n\
344 -S, --send send the message(s) in the pool\n"
345 #ifdef USE_PGP
346 " --nym-config=yournym generate a new pseudonym\n\
347 --latency=hours reply chain latency\n\
348 --reply-chain=rem1,rem2,... reply chain for the pseudonym\n"
349 #endif
350 "-v, --verbose output informational messages\n\
351 -f [file] read a mail folder\n"
352 #ifndef USE_NCURSES
353 "\n-fr, -ff, -fg [file] send reply/followup/group reply to a message\n"
354 #endif
355 "\nThe input file is expected to contain mail headers if no address is\n\
356 specified in the command line.\n\
357 \n\
358 Remailer:\n\
359 \n\
360 -R, --read-mail read remailer message from stdin\n\
361 -I, --store-mail read remailer msg from stdin, do not decrypt\n\
362 -M, --remailer process the remailer pool\n\
363 -D, --daemon remailer as background process\n
364 --no-detach do not detach from terminal as daemon\n"
365 #ifdef USE_SOCK
366 "-S, --send force sending messages from the pool\n"
367 #endif
368 "-P, --pop-mail force getting messages from POP3 servers\n\
369 -G, --generate-key generate a new remailer key\n\
370 -K, --update-keys generate remailer keys if necessary\n"
371 #ifdef WIN32SERVICE
372 "\n\
373 WinNT service:\n\
374 \n\
375 --install-svc install the service\n\
376 --remove-svc remove the service\n\
377 --run-svc run as a service\n"
378 #endif
379 );
380
381 ret = 0;
382 goto end;
383 }
384 if (deflt && send == -1)
385 send = MSG_MAIL;
386 if (nym[0] != 0)
387 send = -1;
388 if ((send == MSG_MAIL || send == MSG_POST) && filename == NULL &&
389 header == 1 && isatty(fileno(stdin))) {
390 /* we don't get here if USE_NCURSES is set */
391 printf("Run `%s -h' to view a summary of the command line options.\n\nEnter the message, complete with headers.\n",
392 argv[0]);
393 #ifdef UNIX
394 printf("When done, press ^D.\n\n");
395 #else
396 printf("When done, press ^Z.\n\n");
397 #endif
398 }
399 if (header == 0)
400 buf_nl(msg);
401
402 if (readmail || send == MSG_MAIL || send == MSG_POST) {
403 if (filename == NULL || streq(filename, "-"))
404 f = stdin;
405 else {
406 f = fopen(filename, "r");
407 if (f == NULL)
408 fprintf(stderr, "Can't open %s.\n", filename);
409 }
410
411 if (f && buf_read(msg, f) != -1) {
412 if (readmail == 1) {
413 check_get_pass(1);
414 mix_decrypt(msg);
415 } else if (readmail == 2)
416 pool_add(msg, "inf");
417 if (send == MSG_MAIL || send == MSG_POST) {
418 BUFFER *sendmsg;
419 int numdest = 0;
420
421 sendmsg = buf_new();
422
423 while (buf_getheader(msg, field, content) == 0) {
424 if (bufieq(field, "nym")) {
425 strncpy(nym, content->data, sizeof(nym));
426 } else if (bufieq(field, "chain"))
427 if (strchr(content->data, ';')) {
428 i = strchr(content->data, ';') - (char *)content->data;
429 strncpy(chain, content->data, i);
430 if (strstr(content->data + i, "copies=") != NULL) {
431 sscanf(strstr(content->data + i, "copies=") +
432 sizeof("copies=") - 1, "%d", &numcopies);
433 }
434 } else
435 strncpy(chain, content->data, sizeof(chain));
436 else { /* line goes into message */
437 if ((send == MSG_MAIL && bufieq(field, "to"))
438 || (send == MSG_POST && bufieq(field, "newsgroups")))
439 numdest++;
440 if (bufieq(field, "from"))
441 fprintf(stderr, "Warning: The message has a From: line.\n");
442 buf_appendheader(sendmsg, field, content);
443 }
444 }
445 buf_nl(sendmsg);
446 buf_rest(sendmsg, msg);
447
448 while (buf_getline(attachments, field) != -1)
449 if (attachfile(sendmsg, field) == -1) {
450 errlog(ERRORMSG, "Can't attach %b!\n", field);
451 ret = 2;
452 goto end;
453 }
454
455 #ifdef USE_PGP
456 if (nym[0] != 0 && strchr(nym, '@') == NULL)
457 strcatn(nym, "@", sizeof(nym));
458 if (sign || encrypt) {
459 BUFFER *pass;
460
461 pass = buf_new();
462 user_pass(pass);
463 if (pgp_mailenc((encrypt ? PGP_ENCRYPT : 0) |
464 (nym[0] != 0 && sign ? PGP_SIGN : 0) |
465 PGP_TEXT | PGP_REMAIL, sendmsg, nym,
466 pass, NULL, NYMSECRING) != 0) {
467 fprintf(stderr, "Encryption failed: missing key!");
468 ret = 2;
469 goto end;
470 }
471 buf_free(pass);
472 }
473 if (nym[0] != 0) {
474 if (nym_encrypt(sendmsg, nym, send) == 0)
475 send = MSG_MAIL;
476 else
477 fprintf(stderr, "Nym error, sending message anonymously.\n");
478 }
479 #endif
480 if (numdest == 0) {
481 fprintf(stderr, "No destination address given!\n");
482 ret = 2;
483 } else if (numcopies < 0 || numcopies > 10) {
484 fprintf(stderr, "Invalid number of copies!\n");
485 ret = 2;
486 } else {
487 if (mix_encrypt(send, sendmsg, chain, numcopies,
488 chainlist) == -1) {
489 ret = 2;
490 if (chainlist->length)
491 fprintf(stderr, "%s\n", chainlist->data);
492 else
493 fprintf(stderr, "Failed!\n");
494 } else if (verbose) {
495 fprintf(stderr, "Chain: ");
496 buf_write(chainlist, stderr);
497 }
498 }
499
500 buf_free(sendmsg);
501 }
502 if (filename != NULL)
503 fclose(f);
504 } else
505 ret = 2;
506 }
507 if (send == MSG_NULL) {
508 if (msg->length) {
509 while (buf_getheader(msg, field, content) == 0) {
510 if (bufieq(field, "chain"))
511 strncpy(chain, content->data, sizeof(chain));
512 }
513 }
514 if (mix_encrypt(MSG_NULL, NULL, chain, numcopies, chainlist) == -1) {
515 ret = 2;
516 if (chainlist->length)
517 fprintf(stderr, "%s\n", chainlist->data);
518 else
519 fprintf(stderr, "Failed!\n");
520 } else if (verbose) {
521 fprintf(stderr, "Chain: ");
522 buf_write(chainlist, stderr);
523 }
524 }
525 #ifdef USE_PGP
526 if (nym[0] != 0) {
527 char nymserver[LINELEN] = "*";
528 BUFFER *chains;
529
530 chains = buf_new();
531 if (numcopies < 1 || numcopies > 10)
532 numcopies = 1;
533 while (buf_getheader(msg, field, content) != -1) {
534 if (bufieq(field, "chain"))
535 strncpy(chain, content->data, sizeof(chain));
536 else if (bufieq(field, "reply-chain"))
537 buf_appendf(chains, "Chain: %b\n", content);
538 else if (field->length)
539 buf_appendheader(chains, field, content);
540 else
541 buf_nl(chains);
542 }
543 if (strrchr(nym, '@')) {
544 strncpy(nymserver, strrchr(nym, '@'), sizeof(nymserver));
545 *strrchr(nym, '@') = '\0';
546 }
547 if (nym_config(NYM_CREATE, nym, nymserver, pseudonym,
548 chain, numcopies, chains, nymopt) < 0) {
549 ret = 2;
550 fprintf(stderr, "Failed!\n");
551 }
552 user_delpass();
553 buf_free(chains);
554 }
555 #endif
556
557 if (keygen) {
558 check_get_pass(0);
559 keymgt(keygen);
560 }
561 if (sendpool)
562 mix_send();
563 #ifdef USE_SOCK
564 if (pop3)
565 pop3get();
566 #endif
567 if (maint) {
568 check_get_pass(1);
569 mix_regular(0);
570 }
571
572 end:
573 buf_free(field);
574 buf_free(content);
575 buf_free(chainlist);
576 buf_free(msg);
577 buf_free(nymopt);
578 buf_free(pseudonym);
579 buf_free(attachments);
580
581 if (daemon) {
582 check_get_pass(1);
583 #ifdef UNIX
584 if (! nodetach) {
585 int pid;
586
587 fprintf(stderr, "Detaching.\n");
588 /* Detach as suggested by the Unix Programming FAQ */
589 pid = fork();
590 if (pid > 0)
591 exit(0);
592 if (setsid() < 0) {
593 /* This should never happen. */
594 fprintf(stderr, "setsid() failed.\n");
595 exit(1);
596 };
597 pid = fork();
598 if (pid > 0)
599 exit(0);
600 if (chdir(MIXDIR) < 0) {
601 if (chdir("/") < 0) {
602 fprintf(stderr, "Cannot chdir to mixdir or /.\n");
603 exit(1);
604 };
605 };
606 if (write_pidfile(PIDFILE)) {
607 fprintf(stderr, "Aborting.\n");
608 exit(1);
609 }
610 freopen ("/dev/null", "r", stdin);
611 freopen ("/dev/null", "w", stdout);
612 freopen ("/dev/null", "w", stderr);
613 }
614 #endif
615 mix_daemon();
616 clear_pidfile(PIDFILE);
617 }
618 mix_exit();
619 return (ret);
620 }
621
622 static char *largopt(char *p, char *opt, char *name, int *error)
623 {
624 if (streq(p, opt)) {
625 fprintf(stderr, "%s: Missing argument for option --%s\n", name, p);
626 *error = 1;
627 } else if (strleft(p, opt) && p[strlen(opt)] == '=') {
628 return (p + strlen(opt) + 1);
629 }
630 return (NULL);
631 }
632
633 static void noarg(char *name, char p)
634 {
635 fprintf(stderr, "%s: Missing argument for option -%c\n", name, p);
636 }
637
638 static int check_get_pass(int force)
639 /* get a passphrase and check against keys
640 * if force != 0 passphrase must much with some key */
641 {
642 BUFFER *pass, *pass2, *key;
643 int n = 0;
644
645 if (PASSPHRASE[0] == '\0' && isatty(fileno(stdin))) {
646 pass = buf_new();
647 pass2 = buf_new();
648 key = buf_new();
649 buf_sets(pass, PASSPHRASE);
650 while (pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL,
651 NULL, NULL, NULL, pass) < 0 &&
652 pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL,
653 NULL, NULL, NULL, pass) < 0 &&
654 getv2seckey(NULL, key) < 0)
655 {
656 user_delpass();
657 if (n)
658 fprintf(stderr, "re-");
659 user_pass(pass);
660 strncpy(PASSPHRASE, pass->data, LINELEN);
661 PASSPHRASE[LINELEN-1] = 0;
662 if (!force) {
663 if (n && buf_eq(pass, pass2))
664 break;
665 buf_set(pass2, pass);
666 }
667 n=1;
668 }
669 user_delpass();
670 buf_free(pass);
671 buf_free(pass2);
672 buf_free(key);
673
674 strncpy(ENTEREDPASSPHRASE, PASSPHRASE, LINELEN);
675 ENTEREDPASSPHRASE[LINELEN-1] = 0;
676 }
677 return 1;
678 }

  ViewVC Help
Powered by ViewVC 1.1.5