Imported both gpgdir and gpgwrap projects.
[pgp-tools.git] / gpgwrap / src / gpgwrap.c
1 /****************************************************************************
2 ****************************************************************************
3 *
4 * gpgwrap.c
5 *
6 ****************************************************************************
7 ****************************************************************************/
8
9
10
11
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <signal.h>
19 #include <termios.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24
25 #include "version.h"
26
27
28
29 #define PROGRAM_NAME "gpgwrap"
30 #define VERSION_STRING PROGRAM_NAME " " VERSION "-" VERSION_DATE
31 #define EXEC_ARGV_SIZE 1024
32 #define PASSPHRASE_BUFFER_SIZE 0x10000
33 #define LIST_BUFFER_SIZE 0x10000
34 #define CMDLINE_MAX_FILES 1024
35 #define GPGWRAP_MODE_DEFAULT 0
36 #define GPGWRAP_MODE_VERSION 1
37 #define GPGWRAP_MODE_FILE 2
38 #define GPGWRAP_MODE_PRINT 3
39
40
41
42 static char program_name[] = PROGRAM_NAME;
43 static char environ_name[] = "GPGWRAP_PASSPHRASE";
44 static int mode = GPGWRAP_MODE_DEFAULT;
45 static int verbose = 0;
46 static int interactive = 0;
47 static int ask_twice = 0;
48 static int check_exit_code = 0;
49 static char *calling_path = NULL;
50 static char *environ_var = NULL;
51 static char *passphrase_file = NULL;
52 static char *option_name = "--passphrase-fd";
53 static char *files[CMDLINE_MAX_FILES];
54 static int nfiles = 0;
55 static char **gpg_cmd = NULL;
56
57
58
59 /****************************************************************************
60 * do_perror
61 ****************************************************************************/
62 static void
63 do_perror(
64 void)
65
66 {
67 perror(program_name);
68 exit(1);
69 }
70
71
72
73 /****************************************************************************
74 * do_error
75 ****************************************************************************/
76 #define do_error(args...) \
77 do \
78 { \
79 fprintf(stderr, "%s: ", program_name); \
80 fprintf(stderr, args); \
81 fprintf(stderr, "\n"); \
82 exit(1); \
83 } \
84 while (0)
85
86
87
88 /****************************************************************************
89 * do_warning
90 ****************************************************************************/
91 #define do_warning(args...) \
92 do \
93 { \
94 fprintf(stderr, "%s: ", program_name); \
95 fprintf(stderr, args); \
96 fprintf(stderr, "\n"); \
97 } \
98 while (0)
99
100
101
102 /****************************************************************************
103 * do_error_oom
104 ****************************************************************************/
105 static void
106 do_error_oom(
107 void)
108
109 {
110 do_error("could not allocate memory");
111 }
112
113
114
115 /****************************************************************************
116 * do_error_too_long
117 ****************************************************************************/
118 static void
119 do_error_too_long(
120 void)
121
122 {
123 do_error("passphrase too long");
124 }
125
126
127
128 /****************************************************************************
129 * do_verbose
130 ****************************************************************************/
131 #define do_verbose(level, args...) \
132 do \
133 { \
134 if (verbose < level) break; \
135 fprintf(stderr, "%s[%d]: ", program_name, getpid()); \
136 fprintf(stderr, args); \
137 fprintf(stderr, "\n"); \
138 } \
139 while (0)
140
141
142
143 /****************************************************************************
144 * do_verbose_start
145 ****************************************************************************/
146 #define do_verbose_start(level, args...) \
147 do \
148 { \
149 if (verbose < level) break; \
150 fprintf(stderr, "%s[%d] ", program_name, getpid()); \
151 fprintf(stderr, args); \
152 } \
153 while (0)
154
155
156
157 /****************************************************************************
158 * do_verbose_append
159 ****************************************************************************/
160 #define do_verbose_append(level, args...) \
161 do \
162 { \
163 if (verbose < level) break; \
164 fprintf(stderr, args); \
165 } \
166 while (0)
167
168
169
170 /****************************************************************************
171 * do_snprintf
172 ****************************************************************************/
173 #define do_snprintf(string, max, args...) do_snprintf2(snprintf(string, max, args), max)
174
175
176
177 /****************************************************************************
178 * do_snprintf2
179 ****************************************************************************/
180 static int
181 do_snprintf2(
182 int len,
183 int max)
184
185 {
186 if ((len == -1) || (len >= max)) do_error("do_snprintf() size exceeded");
187 return (len);
188 }
189
190
191
192 /****************************************************************************
193 * mangle_passphrase
194 ****************************************************************************/
195 static int
196 mangle_passphrase(
197 char *buffer,
198 int size,
199 char *mbuffer,
200 int msize)
201
202 {
203 char c;
204 int i, j, c1;
205
206 /*
207 * look for "unusual" characters and convert them to
208 * backslash escaped octal numbers
209 */
210
211 for (i = j = 0, msize--; i < size; i++)
212 {
213 c = buffer[i];
214 if (j >= msize) goto error;
215 if ((c < '+') || ((c > ';') && (c < 'A')) ||
216 ((c > 'Z') && (c != '_') && (c < 'a')) ||
217 ((c > 'z') && (c != '~')))
218 {
219 c1 = (unsigned char) c;
220 if (j >= msize - 4) goto error;
221 mbuffer[j++] = '\\';
222 mbuffer[j++] = '0' + (c1 >> 6);
223 mbuffer[j++] = '0' + ((c1 >> 3) & 7);
224 mbuffer[j++] = '0' + (c1 & 7);
225 }
226 else mbuffer[j++] = c;
227 }
228 mbuffer[j] = '\0';
229 return (j);
230 error:
231 do_error("could not mangle passphrase");
232 }
233
234
235
236 /****************************************************************************
237 * unmangle_passphrase
238 ****************************************************************************/
239 static int
240 unmangle_passphrase(
241 char *buffer,
242 int size)
243
244 {
245 char c;
246 int i, j, c1, c2, c3;
247
248 /* replace backslash escaped octal numbers */
249
250 for (i = j = 0; j < size; i++)
251 {
252 c = buffer[j++];
253 if (c == '\\')
254 {
255 if (j > size - 3) goto error;
256 c1 = buffer[j++];
257 c2 = buffer[j++];
258 c3 = buffer[j++];
259 if ((c1 < '0') || (c1 > '3') || (c2 < '0') || (c2 > '7') ||
260 (c3 < '0') || (c3 > '7')) goto error;
261 c1 -= '0';
262 c2 -= '0';
263 c3 -= '0';
264 c = (char) (((c1 << 6) | (c2 << 3) | c3) & 0xff);
265 }
266 buffer[i] = c;
267 }
268 return (i);
269 error:
270 do_error("could not unmangle passphrase");
271 }
272
273
274
275 /****************************************************************************
276 * read_passphrase
277 ****************************************************************************/
278 static int
279 read_passphrase(
280 char *buffer,
281 int size)
282
283 {
284 int fd, len, i;
285
286 do_verbose(2, "reading passphrase from file '%s'", passphrase_file);
287 if (strcmp(passphrase_file, "-") == 0) fd = STDIN_FILENO;
288 else fd = open(passphrase_file, O_RDONLY);
289 if (fd == -1) do_perror();
290 for (len = 0; (i = read(fd, buffer, size)) > 0; len += i)
291 {
292 buffer += i;
293 size -= i;
294 if (size == 0) do_error_too_long();
295 }
296 if (i == -1) do_perror();
297 if (close(fd) == -1) do_perror();
298 return (len);
299 }
300
301
302
303 /****************************************************************************
304 * prompt_passphrase
305 ****************************************************************************/
306 static int
307 prompt_passphrase(
308 char *buffer,
309 int size)
310
311 {
312 int len, len2;
313 int fd;
314 struct termios t, tt;
315 char tty[] = "/dev/tty";
316 char pp[] = "Passphrase: ";
317 char pp2[] = "\nPassphrase (again): ";
318 char *buffer2;
319
320 /*
321 * don't touch stdin, just open the controlling tty and ask for the
322 * passphrase
323 */
324
325 do_verbose(2, "opening '%s' to prompt for passphrase", tty);
326 fd = open(tty, O_RDWR);
327 if (fd == -1) do_perror();
328 write(fd, pp, strlen(pp));
329 tcgetattr(fd, &t);
330 tt = t;
331 tt.c_lflag &= ~ECHO;
332 tcsetattr(fd, TCSAFLUSH, &tt);
333 len = read(fd, buffer, size);
334 if (len == -1) do_perror();
335 if ((ask_twice) && (len < size))
336 {
337 buffer2 = (char *) alloca(sizeof (char) * size);
338 if (buffer2 == NULL) do_error_oom();
339 write(fd, pp2, strlen(pp2));
340 len2 = read(fd, buffer2, size);
341 if (len2 == -1) do_perror();
342 write(fd, "\n", 1);
343 tcsetattr(fd, TCSAFLUSH, &t);
344 if ((len != len2) || (memcmp(buffer, buffer2, len) != 0)) do_error("passphrases are not the same");
345 }
346 else
347 {
348 write(fd, "\n", 1);
349 tcsetattr(fd, TCSAFLUSH, &t);
350
351 /*
352 * if the above read() returns with len == size, we don't
353 * know if there are more bytes, so we assume passphrase is
354 * too long
355 */
356
357 if (len >= size) do_error_too_long();
358 }
359 if (close(fd) == -1) do_perror();
360
361 /* ignore trailing \012 */
362
363 return (len - 1);
364 }
365
366
367
368 /****************************************************************************
369 * environ_or_prompt
370 ****************************************************************************/
371 static int
372 environ_or_prompt(
373 char *buffer,
374 int size)
375
376 {
377 int len, len2;
378 char *env;
379
380 env = getenv(environ_name);
381 if ((env != NULL) && (! interactive))
382 {
383 do_verbose(2, "got passphrase from environment variable: %s=%s", environ_name, env);
384
385 /*
386 * first unmangle the content of the environment
387 * variable inplace, then clear the memory
388 */
389
390 len2 = strlen(env);
391 len = unmangle_passphrase(env, len2);
392 if (len > size) do_error_too_long();
393 memcpy(buffer, env, len);
394 memset(env, 0, len2);
395 }
396 else len = prompt_passphrase(buffer, size);
397 return (len);
398 }
399
400
401
402 /****************************************************************************
403 * do_wait
404 ****************************************************************************/
405 static void
406 do_wait(
407 void)
408
409 {
410 int status, value = 1;
411
412 do_verbose(2, "waiting for child");
413 wait(&status);
414 if (! check_exit_code) return;
415 do_verbose(2, "checking child exit code");
416 if (! WIFEXITED(status)) goto out;
417 value = WEXITSTATUS(status);
418 if (value == 0) return;
419 do_verbose(2, "child process terminated abnormal, exiting");
420 out:
421 exit(value);
422 }
423
424
425
426 /****************************************************************************
427 * do_fork
428 ****************************************************************************/
429 static int
430 do_fork(
431 char *buffer,
432 int size)
433
434 {
435 int fds[2], i;
436
437 /*
438 * parent will write passphrase to the opened pipe, child will
439 * pass the fd to gpg
440 */
441
442 if (pipe(fds) == -1) do_perror();
443 do_verbose(2, "forking");
444 switch (fork())
445 {
446 case -1:
447 do_perror();
448 case 0:
449 /* child */
450
451 if (close(fds[1]) == -1) do_perror();
452 return (fds[0]);
453 default:
454 break;
455 }
456
457 /* parent */
458
459 signal(SIGPIPE, SIG_IGN);
460 if (close(fds[0]) == -1) do_perror();
461 while (size > 0)
462 {
463 i = write(fds[1], buffer, size);
464 if ((i == -1) && (errno == EPIPE)) break;
465 if (i == -1) do_perror();
466 buffer += i;
467 size -= i;
468 }
469 if (size > 0) do_warning("only partial passphrase written");
470 if (close(fds[1]) == -1) do_perror();
471 do_wait();
472 return (-1);
473 }
474
475
476
477 /****************************************************************************
478 * get_passphrase_fd
479 ****************************************************************************/
480 static int
481 get_passphrase_fd(
482 void)
483
484 {
485 int fd, len;
486 char buffer[PASSPHRASE_BUFFER_SIZE];
487
488 if ((passphrase_file == NULL) || (interactive))
489 {
490 len = environ_or_prompt(buffer, sizeof (buffer));
491 fd = do_fork(buffer, len);
492 }
493 else if (strcmp(passphrase_file, "-") == 0)
494 {
495 len = read_passphrase(buffer, sizeof (buffer));
496 fd = do_fork(buffer, len);
497 }
498 else
499 {
500 do_verbose(2, "opening file '%s' to pass fd", passphrase_file);
501 fd = open(passphrase_file, O_RDONLY);
502 if (fd == -1) do_perror();
503 }
504 return (fd);
505 }
506
507
508
509 /****************************************************************************
510 * get_passphrase
511 ****************************************************************************/
512 static int
513 get_passphrase(
514 char *buffer,
515 int size)
516
517 {
518 int len;
519
520 if ((passphrase_file == NULL) || (interactive)) len = environ_or_prompt(buffer, size);
521 else len = read_passphrase(buffer, size);
522 return (len);
523 }
524
525
526
527 /****************************************************************************
528 * do_putenv
529 ****************************************************************************/
530 static void
531 do_putenv(
532 char *buffer,
533 int len)
534
535 {
536 int size, len2;
537 char *old_var;
538
539 /*
540 * putenv() only stores the given pointer in **environ, so we have
541 * to use malloc here
542 */
543
544 size = strlen(environ_name) + (4 * len) + 2;
545 old_var = environ_var;
546 environ_var = (char *) malloc(sizeof (char) * size);
547 if (environ_var == NULL) do_error_oom();
548 len2 = do_snprintf(environ_var, size, "%s=", environ_name);
549 if ((buffer != NULL) && (len > 0)) mangle_passphrase(buffer, len, &environ_var[len2], size - len2);
550 do_verbose(2, "setting environment variable: %s", environ_var);
551 if (putenv(environ_var) == -1) do_perror();
552 if (old_var != NULL) free(old_var);
553 }
554
555
556
557 /****************************************************************************
558 * do_exec
559 ****************************************************************************/
560 static void
561 do_exec(
562 char **argv,
563 int clear)
564
565 {
566 if (clear) do_putenv(NULL, 0);
567 if (verbose > 0)
568 {
569 int i;
570
571 do_verbose_start(1, "executing:");
572 for (i = 0; argv[i] != NULL; i++) do_verbose_append(1, " %s", argv[i]);
573 do_verbose_append(1, "\n");
574 }
575 execvp(argv[0], argv);
576
577 /* only reached if execvp fails */
578
579 do_perror();
580 }
581
582
583
584 /****************************************************************************
585 * exec_gpg
586 ****************************************************************************/
587 static void
588 exec_gpg(
589 void)
590
591 {
592 int fd;
593 int i, j, k;
594 char fd_num[32];
595 char *argv[EXEC_ARGV_SIZE];
596 char homedir_eq[] = "--homedir=";
597 char options_eq[] = "--options=";
598
599 /*
600 * get fd to read passphrase from, parent will return with fd == -1
601 * after fork
602 */
603
604 fd = get_passphrase_fd();
605 if (fd == -1) return;
606
607 /* create argv for execvp */
608
609 do_snprintf(fd_num, sizeof (fd_num), "%d", fd);
610 for (i = 0, j = 0, k = 1; gpg_cmd[i] != NULL; i++, k--)
611 {
612
613 /*
614 * check if there is enough space to store option_name
615 * and fd_num
616 */
617
618 if (i >= (EXEC_ARGV_SIZE - 4)) do_error("too many gpg arguments specified");
619 if (strcmp(gpg_cmd[i], option_name) == 0) do_error("gpg command already has a '%s' option", option_name);
620 if (k == 0)
621 {
622 if ((strncmp(gpg_cmd[i], homedir_eq, sizeof (homedir_eq) - 1) == 0) || (strncmp(gpg_cmd[i], options_eq, sizeof (options_eq) - 1) == 0)) k = 1;
623 else if ((strcmp(gpg_cmd[i], "--homedir") == 0) || (strcmp(gpg_cmd[i], "--options") == 0)) k = 2;
624 else
625 {
626 argv[j++] = option_name;
627 argv[j++] = fd_num;
628 }
629 }
630 argv[j++] = gpg_cmd[i];
631 }
632 if (k >= 0)
633 {
634 argv[j++] = option_name;
635 argv[j++] = fd_num;
636 }
637 argv[j] = NULL;
638 do_exec(argv, 1);
639 }
640
641
642
643 /****************************************************************************
644 * exec_line
645 ****************************************************************************/
646 static void
647 exec_line(
648 char *line)
649
650 {
651 char shell_cmd[LIST_BUFFER_SIZE];
652 char verbose_string[128] = "";
653 char *argv[] = { "sh", "-c", NULL, NULL };
654 int fds[2], i;
655
656 /* fork a child and disallow it to read stdin from parent */
657
658 if (pipe(fds) == -1) do_perror();
659 do_verbose(1, "forking");
660 switch (fork())
661 {
662 case -1:
663 do_perror();
664 case 0:
665 break;
666 default:
667 /* parent */
668
669 if (close(fds[0]) == -1) do_perror();
670 if (close(fds[1]) == -1) do_perror();
671 do_wait();
672 return;
673 }
674
675 /* child */
676
677 if (close(fds[1]) == -1) do_perror();
678 if (fds[0] != STDIN_FILENO) dup2(fds[0], STDIN_FILENO);
679
680 /* create argv for execvp */
681
682 for (i = 0; i < verbose; i++)
683 {
684 if (strlen(verbose_string) >= sizeof (verbose_string) - 4) break;
685 strcat(verbose_string, " -v");
686 }
687 do_snprintf(shell_cmd, sizeof (shell_cmd), "exec %s%s -o %s -- %s",
688 calling_path, verbose_string, option_name, line);
689 argv[2] = shell_cmd;
690 do_exec(argv, 0);
691 }
692
693
694
695 /****************************************************************************
696 * exec_list
697 ****************************************************************************/
698 static void
699 exec_list(
700 char *path,
701 char *buffer,
702 int len)
703
704 {
705 int fd;
706 char lbuffer[LIST_BUFFER_SIZE];
707 int inuse, start, free, nread, llen;
708 char *line, *next_line;
709
710 /* open file */
711
712 do_verbose(1, "reading gpg commands from file: '%s'", path);
713 if (strcmp(path, "-") == 0) fd = STDIN_FILENO;
714 else fd = open(path, O_RDONLY);
715 if (fd == -1) do_perror();
716
717 /* export passphrase to environment */
718
719 do_putenv(buffer, len);
720
721 /* read gpg commands */
722
723 for (inuse = 0, free = LIST_BUFFER_SIZE; (nread = read(fd, &lbuffer[inuse], free)) > 0; )
724 {
725 inuse += nread;
726 for (line = lbuffer; (next_line = memchr(line, '\n', inuse)) != NULL; )
727 {
728 *next_line = '\0';
729 llen = (int) (next_line - line) + 1;
730 if (llen != strlen(line) + 1) do_error("line contains \\0 character");
731 exec_line(line);
732 inuse -= llen;
733 line = next_line + 1;
734 }
735 start = (int) (line - lbuffer);
736 if ((start == 0) && (inuse == LIST_BUFFER_SIZE)) do_error("line too long");
737 if ((start > 0) && (inuse > 0)) memmove(lbuffer, &lbuffer[start], inuse);
738 free = LIST_BUFFER_SIZE - inuse;
739 }
740
741 /* check for error while read() */
742
743 if (nread == -1) do_perror();
744 if (close(fd) == -1) do_perror();
745
746 /* check if there are bytes left */
747
748 if (inuse > 0) do_error("last line incomplete");
749 }
750
751
752
753 /****************************************************************************
754 * cmdline_fill_space
755 ****************************************************************************/
756 static void
757 cmdline_fill_space(
758 char *s)
759
760 {
761 while (*s != '\0') *s++ = ' ';
762 }
763
764
765
766 /****************************************************************************
767 * cmdline_usage
768 ****************************************************************************/
769 static void
770 cmdline_usage(
771 void)
772
773 {
774 char space1[] = VERSION_STRING;
775 char space2[] = PROGRAM_NAME;
776
777 cmdline_fill_space(space1);
778 cmdline_fill_space(space2);
779 printf(VERSION_STRING " | written by Karsten Scheibler\n"
780 "%s | http://unusedino.de/gpgwrap/\n"
781 "%s | gpgwrap@unusedino.de\n\n"
782 "Usage: %s -V\n"
783 "or: %s -P [-v] [-i] [-a] [-p <file>]\n"
784 "or: %s -F [-v] [-i] [-a] [-c] [-p <file>] [-o <name>]\n"
785 " %s [--] <file> [<file> ... ]\n"
786 "or: %s [-v] [-i] [-a] [-p <file>] [-o <name>]\n"
787 " %s [--] gpg [gpg options]\n\n"
788 " -V print out version\n"
789 " -P get the passphrase and print it mangled to stdout\n"
790 " -F read gpg commands from file\n"
791 " -v be more verbose\n"
792 " -i be interactive, always prompt for passphrase\n"
793 " -a ask twice if prompting for passphrase\n"
794 " -c check exit code of child processes\n"
795 " -p <file> read passphrase from <file>\n"
796 " -o <name> specify name of \"--passphrase-fd\" option\n"
797 " -h this help\n",
798 space1, space1, program_name, program_name, program_name,
799 space2, program_name, space2);
800 exit(0);
801 }
802
803
804
805 /****************************************************************************
806 * cmdline_check_arg
807 ****************************************************************************/
808 static char *
809 cmdline_check_arg(
810 char *msg,
811 char *file)
812
813 {
814 if (file == NULL) do_error("%s expects a file name", msg);
815 return (file);
816 }
817
818
819
820 /****************************************************************************
821 * cmdline_check_stdin
822 ****************************************************************************/
823 static char *
824 cmdline_check_stdin(
825 char *msg,
826 char *file)
827
828 {
829 static int stdin_count = 0;
830
831 cmdline_check_arg(msg, file);
832 if (strcmp(file, "-") == 0) stdin_count++;
833 if (stdin_count > 1) do_error("%s used stdin although already used before", msg);
834 return (file);
835 }
836
837
838
839 /****************************************************************************
840 * cmdline_parse
841 ****************************************************************************/
842 static void
843 cmdline_parse(
844 int argc,
845 char **argv)
846
847 {
848 char *arg;
849 int args;
850 int ignore = 0;
851
852 calling_path = argv[0];
853 for (args = 0, argv++; (arg = *argv++) != NULL; args++)
854 {
855 if ((arg[0] != '-') || (ignore))
856 {
857 if (mode == GPGWRAP_MODE_FILE) goto get_file;
858 gpg_cmd = argv - 1;
859 break;
860 }
861 else if ((strcmp(arg, "-") == 0) && (mode == GPGWRAP_MODE_FILE))
862 {
863 get_file:
864 if (nfiles >= CMDLINE_MAX_FILES) do_error("too many files specified");
865 files[nfiles++] = cmdline_check_stdin("-F/--file", arg);
866 }
867 else if (strcmp(arg, "--") == 0)
868 {
869 ignore = 1;
870 }
871 else if ((strcmp(arg, "-h") == 0) || (strcmp(arg, "--help") == 0))
872 {
873 cmdline_usage();
874 }
875 else if (((strcmp(arg, "-V") == 0) || (strcmp(arg, "--version") == 0)) && (args == 0))
876 {
877 mode = GPGWRAP_MODE_VERSION;
878 }
879 else if (((strcmp(arg, "-F") == 0) || (strcmp(arg, "--file") == 0)) && (args == 0))
880 {
881 mode = GPGWRAP_MODE_FILE;
882 }
883 else if (((strcmp(arg, "-P") == 0) || (strcmp(arg, "--print") == 0)) && (args == 0))
884 {
885 mode = GPGWRAP_MODE_PRINT;
886 }
887 else if (mode == GPGWRAP_MODE_VERSION)
888 {
889 goto bad_option;
890 }
891 else if ((strcmp(arg, "-v") == 0) || (strcmp(arg, "--verbose") == 0))
892 {
893 verbose++;
894 }
895 else if ((strcmp(arg, "-i") == 0) || (strcmp(arg, "--interactive") == 0))
896 {
897 interactive = 1;
898 }
899 else if ((strcmp(arg, "-a") == 0) || (strcmp(arg, "--ask-twice") == 0))
900 {
901 ask_twice = 1;
902 }
903 else if ((strcmp(arg, "-p") == 0) || (strcmp(arg, "--passphrase-file") == 0))
904 {
905 if (passphrase_file != NULL) do_error("-p/--passphrase-file specified more than once");
906 passphrase_file = cmdline_check_stdin("-p/--passphrase-file", *argv++);
907 }
908 else if (mode == GPGWRAP_MODE_PRINT)
909 {
910 goto bad_option;
911 }
912 else if ((strcmp(arg, "-o") == 0) || (strcmp(arg, "--option-name") == 0))
913 {
914 option_name = cmdline_check_arg("-o/--option-name", *argv++);
915 }
916 else if (mode != GPGWRAP_MODE_FILE)
917 {
918 goto bad_option;
919 }
920 else if ((strcmp(arg, "-c") == 0) || (strcmp(arg, "--check-exit-code") == 0))
921 {
922 check_exit_code = 1;
923 }
924 else
925 {
926 bad_option:
927 do_error("unrecognized option '%s'", arg);
928 }
929 }
930 if ((mode == GPGWRAP_MODE_DEFAULT) && (nfiles == 0) && (gpg_cmd == NULL)) do_error("no gpg command specified");
931 if ((mode == GPGWRAP_MODE_FILE) && (nfiles == 0)) do_error("no files to process");
932 if ((mode == GPGWRAP_MODE_PRINT) && (nfiles > 0)) do_error("no additional arguments allowed");
933 if (mode != GPGWRAP_MODE_FILE) check_exit_code = 1;
934 }
935
936
937
938 /****************************************************************************
939 * main
940 ****************************************************************************/
941 int
942 main(
943 int argc,
944 char **argv)
945
946 {
947
948 /*
949 * we need setlinebuf(), because otherwise do_verbose() output of
950 * parent and child processes may get mixed in some cases
951 */
952
953 setlinebuf(stderr);
954
955 /* parse cmdline */
956
957 cmdline_parse(argc, argv);
958
959 /* do it */
960
961 if (mode == GPGWRAP_MODE_VERSION)
962 {
963 printf(VERSION_STRING "\n");
964 }
965 else if (mode == GPGWRAP_MODE_FILE)
966 {
967 int i, len;
968 char buffer[PASSPHRASE_BUFFER_SIZE];
969
970 len = get_passphrase(buffer, sizeof (buffer));
971 for (i = 0; i < nfiles; i++) exec_list(files[i], buffer, len);
972 }
973 else if (mode == GPGWRAP_MODE_PRINT)
974 {
975 char buffer[PASSPHRASE_BUFFER_SIZE];
976 char mbuffer[PASSPHRASE_BUFFER_SIZE];
977 int len;
978
979 len = get_passphrase(buffer, sizeof (buffer));
980 mangle_passphrase(buffer, len, mbuffer, sizeof (mbuffer));
981 printf("%s\n", mbuffer);
982 }
983 else exec_gpg();
984
985 /* done */
986
987 return (0);
988 }
989 /******************************************************** Karsten Scheibler */