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

  ViewVC Help
Powered by ViewVC 1.1.5