~ubuntu-branches/ubuntu/wily/signing-party/wily

« back to all changes in this revision

Viewing changes to gpgwrap/src/gpgwrap.c

  • Committer: Bazaar Package Importer
  • Author(s): Thijs Kinkhorst
  • Date: 2009-02-23 21:37:20 UTC
  • mfrom: (4.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20090223213720-98hkq51ynr3oaic7
Tags: 1.1-2
Fix build error when only building the binary package
by fixing the build-arch target (Closes: #516804).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 */