chiark / gitweb /
gpg agent lockup fix: Interrupt main loop when active_connections_value==0
[gnupg2.git] / tools / gpgtar.c
1 /* gpgtar.c - A simple TAR implementation mainly useful for Windows.
2  * Copyright (C) 2010 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20 /* GnuPG comes with a shell script gpg-zip which creates archive files
21    in the same format as PGP Zip, which is actually a USTAR format.
22    That is fine and works nicely on all Unices but for Windows we
23    don't have a compatible shell and the supply of tar programs is
24    limited.  Given that we need just a few tar option and it is an
25    open question how many Unix concepts are to be mapped to Windows,
26    we might as well write our own little tar customized for use with
27    gpg.  So here we go.  */
28
29 #include <config.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36
37 #include "util.h"
38 #include "i18n.h"
39 #include "sysutils.h"
40 #include "../common/openpgpdefs.h"
41 #include "../common/init.h"
42 #include "../common/strlist.h"
43
44 #include "gpgtar.h"
45
46
47 /* Constants to identify the commands and options. */
48 enum cmd_and_opt_values
49   {
50     aNull = 0,
51     aCreate = 600,
52     aExtract,
53     aEncrypt    = 'e',
54     aDecrypt    = 'd',
55     aSign       = 's',
56     aList       = 't',
57
58     oSymmetric  = 'c',
59     oRecipient  = 'r',
60     oUser       = 'u',
61     oOutput     = 'o',
62     oDirectory  = 'C',
63     oQuiet      = 'q',
64     oVerbose    = 'v',
65     oFilesFrom  = 'T',
66     oNoVerbose  = 500,
67
68     aSignEncrypt,
69     oGpgProgram,
70     oSkipCrypto,
71     oOpenPGP,
72     oCMS,
73     oSetFilename,
74     oNull,
75
76     /* Compatibility with gpg-zip.  */
77     oGpgArgs,
78     oTarArgs,
79
80     /* Debugging.  */
81     oDryRun,
82   };
83
84
85 /* The list of commands and options. */
86 static ARGPARSE_OPTS opts[] = {
87   ARGPARSE_group (300, N_("@Commands:\n ")),
88
89   ARGPARSE_c (aCreate,    "create",  N_("create an archive")),
90   ARGPARSE_c (aExtract,   "extract", N_("extract an archive")),
91   ARGPARSE_c (aEncrypt,   "encrypt", N_("create an encrypted archive")),
92   ARGPARSE_c (aDecrypt,   "decrypt", N_("extract an encrypted archive")),
93   ARGPARSE_c (aSign,      "sign",    N_("create a signed archive")),
94   ARGPARSE_c (aList,      "list-archive", N_("list an archive")),
95
96   ARGPARSE_group (301, N_("@\nOptions:\n ")),
97
98   ARGPARSE_s_n (oSymmetric, "symmetric", N_("use symmetric encryption")),
99   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
100   ARGPARSE_s_s (oUser, "local-user",
101                 N_("|USER-ID|use USER-ID to sign or decrypt")),
102   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
103   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
104   ARGPARSE_s_n (oQuiet, "quiet",  N_("be somewhat more quiet")),
105   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
106   ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")),
107   ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
108   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
109   ARGPARSE_s_n (oOpenPGP, "openpgp", "@"),
110   ARGPARSE_s_n (oCMS, "cms", "@"),
111
112   ARGPARSE_group (302, N_("@\nTar options:\n ")),
113
114   ARGPARSE_s_s (oDirectory, "directory",
115                 N_("|DIRECTORY|extract files into DIRECTORY")),
116   ARGPARSE_s_s (oFilesFrom, "files-from",
117                 N_("|FILE|get names to create from FILE")),
118   ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
119
120   ARGPARSE_s_s (oGpgArgs, "gpg-args", "@"),
121   ARGPARSE_s_s (oTarArgs, "tar-args", "@"),
122
123   ARGPARSE_end ()
124 };
125
126
127 /* The list of commands and options for tar that we understand. */
128 static ARGPARSE_OPTS tar_opts[] = {
129   ARGPARSE_s_s (oDirectory, "directory",
130                 N_("|DIRECTORY|extract files into DIRECTORY")),
131   ARGPARSE_s_s (oFilesFrom, "files-from",
132                 N_("|FILE|get names to create from FILE")),
133   ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
134
135   ARGPARSE_end ()
136 };
137
138
139 \f
140 /* Print usage information and and provide strings for help. */
141 static const char *
142 my_strusage( int level )
143 {
144   const char *p;
145
146   switch (level)
147     {
148     case 11: p = "@GPGTAR@ (@GNUPG@)";
149       break;
150     case 13: p = VERSION; break;
151     case 17: p = PRINTABLE_OS_NAME; break;
152     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
153
154     case 1:
155     case 40:
156       p = _("Usage: gpgtar [options] [files] [directories] (-h for help)");
157       break;
158     case 41:
159       p = _("Syntax: gpgtar [options] [files] [directories]\n"
160             "Encrypt or sign files into an archive\n");
161       break;
162
163     default: p = NULL; break;
164     }
165   return p;
166 }
167
168
169 static void
170 set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
171 {
172   enum cmd_and_opt_values cmd = *ret_cmd;
173
174   if (!cmd || cmd == new_cmd)
175     cmd = new_cmd;
176   else if (cmd == aSign && new_cmd == aEncrypt)
177     cmd = aSignEncrypt;
178   else if (cmd == aEncrypt && new_cmd == aSign)
179     cmd = aSignEncrypt;
180   else
181     {
182       log_error (_("conflicting commands\n"));
183       exit (2);
184     }
185
186   *ret_cmd = cmd;
187 }
188 \f
189 /* Shell-like argument splitting.
190
191    For compatibility with gpg-zip we accept arguments for GnuPG and
192    tar given as a string argument to '--gpg-args' and '--tar-args'.
193    gpg-zip was implemented as a Bourne Shell script, and therefore, we
194    need to split the string the same way the shell would.  */
195 static int
196 shell_parse_stringlist (const char *str, strlist_t *r_list)
197 {
198   strlist_t list = NULL;
199   const char *s = str;
200   char quoted = 0;
201   char arg[1024];
202   char *p = arg;
203 #define addchar(c) \
204   do { if (p - arg + 2 < sizeof arg) *p++ = (c); else return 1; } while (0)
205 #define addargument()                           \
206   do {                                          \
207     if (p > arg)                                \
208       {                                         \
209         *p = 0;                                 \
210         append_to_strlist (&list, arg);         \
211         p = arg;                                \
212       }                                         \
213   } while (0)
214
215 #define unquoted        0
216 #define singlequote     '\''
217 #define doublequote     '"'
218
219   for (; *s; s++)
220     {
221       switch (quoted)
222         {
223         case unquoted:
224           if (isspace (*s))
225             addargument ();
226           else if (*s == singlequote || *s == doublequote)
227             quoted = *s;
228           else
229             addchar (*s);
230           break;
231
232         case singlequote:
233           if (*s == singlequote)
234             quoted = unquoted;
235           else
236             addchar (*s);
237           break;
238
239         case doublequote:
240           assert (s > str || !"cannot be quoted at first char");
241           if (*s == doublequote && *(s - 1) != '\\')
242             quoted = unquoted;
243           else
244             addchar (*s);
245           break;
246
247         default:
248           assert (! "reached");
249         }
250     }
251
252   /* Append the last argument.  */
253   addargument ();
254
255 #undef doublequote
256 #undef singlequote
257 #undef unquoted
258 #undef addargument
259 #undef addchar
260   *r_list = list;
261   return 0;
262 }
263
264
265 /* Like shell_parse_stringlist, but returns an argv vector
266    instead of a strlist.  */
267 static int
268 shell_parse_argv (const char *s, int *r_argc, char ***r_argv)
269 {
270   int i;
271   strlist_t list;
272
273   if (shell_parse_stringlist (s, &list))
274     return 1;
275
276   *r_argc = strlist_length (list);
277   *r_argv = xtrycalloc (*r_argc, sizeof **r_argv);
278   if (*r_argv == NULL)
279     return 1;
280
281   for (i = 0; list; i++)
282     {
283       gpgrt_annotate_leaked_object (list);
284       (*r_argv)[i] = list->d;
285       list = list->next;
286     }
287   gpgrt_annotate_leaked_object (*r_argv);
288   return 0;
289 }
290 \f
291 /* Global flags.  */
292 enum cmd_and_opt_values cmd = 0;
293 int skip_crypto = 0;
294 const char *files_from = NULL;
295 int null_names = 0;
296
297
298 /* Command line parsing.  */
299 static void
300 parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
301 {
302   int no_more_options = 0;
303
304   while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
305     {
306       switch (pargs->r_opt)
307         {
308         case oOutput:    opt.outfile = pargs->r.ret_str; break;
309         case oDirectory: opt.directory = pargs->r.ret_str; break;
310         case oSetFilename: opt.filename = pargs->r.ret_str; break;
311         case oQuiet:     opt.quiet = 1; break;
312         case oVerbose:   opt.verbose++; break;
313         case oNoVerbose: opt.verbose = 0; break;
314         case oFilesFrom: files_from = pargs->r.ret_str; break;
315         case oNull: null_names = 1; break;
316
317         case aList:
318         case aDecrypt:
319         case aEncrypt:
320         case aSign:
321           set_cmd (&cmd, pargs->r_opt);
322           break;
323
324         case aCreate:
325           set_cmd (&cmd, aEncrypt);
326           skip_crypto = 1;
327           break;
328
329         case aExtract:
330           set_cmd (&cmd, aDecrypt);
331           skip_crypto = 1;
332           break;
333
334         case oRecipient:
335           add_to_strlist (&opt.recipients, pargs->r.ret_str);
336           break;
337
338         case oUser:
339           opt.user = pargs->r.ret_str;
340           break;
341
342         case oSymmetric:
343           set_cmd (&cmd, aEncrypt);
344           opt.symmetric = 1;
345           break;
346
347         case oGpgProgram:
348           opt.gpg_program = pargs->r.ret_str;
349           break;
350
351         case oSkipCrypto:
352           skip_crypto = 1;
353           break;
354
355         case oOpenPGP: /* Dummy option for now.  */ break;
356         case oCMS:     /* Dummy option for now.  */ break;
357
358         case oGpgArgs:;
359           {
360             strlist_t list;
361             if (shell_parse_stringlist (pargs->r.ret_str, &list))
362               log_error ("failed to parse gpg arguments '%s'\n",
363                          pargs->r.ret_str);
364             else
365               {
366                 if (opt.gpg_arguments)
367                   strlist_last (opt.gpg_arguments)->next = list;
368                 else
369                   opt.gpg_arguments = list;
370               }
371           }
372           break;
373
374         case oTarArgs:;
375           {
376             int tar_argc;
377             char **tar_argv;
378
379             if (shell_parse_argv (pargs->r.ret_str, &tar_argc, &tar_argv))
380               log_error ("failed to parse tar arguments '%s'\n",
381                          pargs->r.ret_str);
382             else
383               {
384                 ARGPARSE_ARGS tar_args;
385                 tar_args.argc = &tar_argc;
386                 tar_args.argv = &tar_argv;
387                 tar_args.flags = ARGPARSE_FLAG_ARG0;
388                 parse_arguments (&tar_args, tar_opts);
389                 if (tar_args.err)
390                   log_error ("unsupported tar arguments '%s'\n",
391                              pargs->r.ret_str);
392                 pargs->err = tar_args.err;
393               }
394           }
395           break;
396
397         case oDryRun:
398           opt.dry_run = 1;
399           break;
400
401         default: pargs->err = 2; break;
402         }
403     }
404 }
405
406 \f
407 /* gpgtar main. */
408 int
409 main (int argc, char **argv)
410 {
411   gpg_error_t err;
412   const char *fname;
413   ARGPARSE_ARGS pargs;
414
415   assert (sizeof (struct ustar_raw_header) == 512);
416
417   gnupg_reopen_std (GPGTAR_NAME);
418   set_strusage (my_strusage);
419   log_set_prefix (GPGTAR_NAME, GPGRT_LOG_WITH_PREFIX);
420
421   /* Make sure that our subsystems are ready.  */
422   i18n_init();
423   init_common_subsystems (&argc, &argv);
424
425   /* Parse the command line. */
426   pargs.argc  = &argc;
427   pargs.argv  = &argv;
428   pargs.flags = ARGPARSE_FLAG_KEEP;
429   parse_arguments (&pargs, opts);
430
431   if ((files_from && !null_names) || (!files_from && null_names))
432     log_error ("--files-from and --null may only be used in conjunction\n");
433   if (files_from && strcmp (files_from, "-"))
434     log_error ("--files-from only supports argument \"-\"\n");
435
436   if (log_get_errorcount (0))
437     exit (2);
438
439   /* Print a warning if an argument looks like an option.  */
440   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
441     {
442       int i;
443
444       for (i=0; i < argc; i++)
445         if (argv[i][0] == '-' && argv[i][1] == '-')
446           log_info (_("NOTE: '%s' is not considered an option\n"), argv[i]);
447     }
448
449   if (! opt.gpg_program)
450     opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
451
452   if (opt.verbose > 1)
453     opt.debug_level = 1024;
454
455   switch (cmd)
456     {
457     case aList:
458       if (argc > 1)
459         usage (1);
460       fname = argc ? *argv : NULL;
461       if (opt.filename)
462         log_info ("note: ignoring option --set-filename\n");
463       if (files_from)
464         log_info ("note: ignoring option --files-from\n");
465       err = gpgtar_list (fname, !skip_crypto);
466       if (err && log_get_errorcount (0) == 0)
467         log_error ("listing archive failed: %s\n", gpg_strerror (err));
468       break;
469
470     case aEncrypt:
471     case aSign:
472     case aSignEncrypt:
473       if ((!argc && !null_names)
474           || (argc && null_names))
475         usage (1);
476       if (opt.filename)
477         log_info ("note: ignoring option --set-filename\n");
478       err = gpgtar_create (null_names? NULL :argv,
479                            !skip_crypto
480                            && (cmd == aEncrypt || cmd == aSignEncrypt),
481                            cmd == aSign || cmd == aSignEncrypt);
482       if (err && log_get_errorcount (0) == 0)
483         log_error ("creating archive failed: %s\n", gpg_strerror (err));
484       break;
485
486     case aDecrypt:
487       if (argc != 1)
488         usage (1);
489       if (opt.outfile)
490         log_info ("note: ignoring option --output\n");
491       if (files_from)
492         log_info ("note: ignoring option --files-from\n");
493       fname = argc ? *argv : NULL;
494       err = gpgtar_extract (fname, !skip_crypto);
495       if (err && log_get_errorcount (0) == 0)
496         log_error ("extracting archive failed: %s\n", gpg_strerror (err));
497       break;
498
499     default:
500       log_error (_("invalid command (there is no implicit command)\n"));
501       break;
502     }
503
504   return log_get_errorcount (0)? 1:0;
505 }
506
507
508 /* Read the next record from STREAM.  RECORD is a buffer provided by
509    the caller and must be at leadt of size RECORDSIZE.  The function
510    return 0 on success and and error code on failure; a diagnostic
511    printed as well.  Note that there is no need for an EOF indicator
512    because a tarball has an explicit EOF record. */
513 gpg_error_t
514 read_record (estream_t stream, void *record)
515 {
516   gpg_error_t err;
517   size_t nread;
518
519   nread = es_fread (record, 1, RECORDSIZE, stream);
520   if (nread != RECORDSIZE)
521     {
522       err = gpg_error_from_syserror ();
523       if (es_ferror (stream))
524         log_error ("error reading '%s': %s\n",
525                    es_fname_get (stream), gpg_strerror (err));
526       else
527         log_error ("error reading '%s': premature EOF "
528                    "(size of last record: %zu)\n",
529                    es_fname_get (stream), nread);
530     }
531   else
532     err = 0;
533
534   return err;
535 }
536
537
538 /* Write the RECORD of size RECORDSIZE to STREAM.  FILENAME is the
539    name of the file used for diagnostics.  */
540 gpg_error_t
541 write_record (estream_t stream, const void *record)
542 {
543   gpg_error_t err;
544   size_t nwritten;
545
546   nwritten = es_fwrite (record, 1, RECORDSIZE, stream);
547   if (nwritten != RECORDSIZE)
548     {
549       err = gpg_error_from_syserror ();
550       log_error ("error writing '%s': %s\n",
551                  es_fname_get (stream), gpg_strerror (err));
552     }
553   else
554     err = 0;
555
556   return err;
557 }
558
559
560 /* Return true if FP is an unarmored OpenPGP message.  Note that this
561    function reads a few bytes from FP but pushes them back.  */
562 #if 0
563 static int
564 openpgp_message_p (estream_t fp)
565 {
566   int ctb;
567
568   ctb = es_getc (fp);
569   if (ctb != EOF)
570     {
571       if (es_ungetc (ctb, fp))
572         log_fatal ("error ungetting first byte: %s\n",
573                    gpg_strerror (gpg_error_from_syserror ()));
574
575       if ((ctb & 0x80))
576         {
577           switch ((ctb & 0x40) ? (ctb & 0x3f) : ((ctb>>2)&0xf))
578             {
579             case PKT_MARKER:
580             case PKT_SYMKEY_ENC:
581             case PKT_ONEPASS_SIG:
582             case PKT_PUBKEY_ENC:
583             case PKT_SIGNATURE:
584             case PKT_COMMENT:
585             case PKT_OLD_COMMENT:
586             case PKT_PLAINTEXT:
587             case PKT_COMPRESSED:
588             case PKT_ENCRYPTED:
589               return 1; /* Yes, this seems to be an OpenPGP message.  */
590             default:
591               break;
592             }
593         }
594     }
595   return 0;
596 }
597 #endif