tools/gpgtar: Handle '--gpg' argument.
[gnupg.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 <http://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 <assuan.h>
31 #include <errno.h>
32 #include <npth.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <assert.h>
37
38 #include "util.h"
39 #include "i18n.h"
40 #include "sysutils.h"
41 #include "../common/asshelp.h"
42 #include "../common/openpgpdefs.h"
43 #include "../common/init.h"
44
45 #include "gpgtar.h"
46
47
48 /* Constants to identify the commands and options. */
49 enum cmd_and_opt_values
50   {
51     aNull = 0,
52     aEncrypt    = 'e',
53     aDecrypt    = 'd',
54     aSign       = 's',
55     aList       = 't',
56
57     oSymmetric  = 'c',
58     oRecipient  = 'r',
59     oUser       = 'u',
60     oOutput     = 'o',
61     oQuiet      = 'q',
62     oVerbose    = 'v',
63     oFilesFrom  = 'T',
64     oNoVerbose  = 500,
65
66     aSignEncrypt,
67     oGpgProgram,
68     oSkipCrypto,
69     oOpenPGP,
70     oCMS,
71     oSetFilename,
72     oNull
73   };
74
75
76 /* The list of commands and options. */
77 static ARGPARSE_OPTS opts[] = {
78   ARGPARSE_group (300, N_("@Commands:\n ")),
79
80   ARGPARSE_c (aEncrypt,   "encrypt", N_("create an archive")),
81   ARGPARSE_c (aDecrypt,   "decrypt", N_("extract an archive")),
82   ARGPARSE_c (aSign,      "sign",    N_("create a signed archive")),
83   ARGPARSE_c (aList,      "list-archive", N_("list an archive")),
84
85   ARGPARSE_group (301, N_("@\nOptions:\n ")),
86
87   ARGPARSE_s_n (oSymmetric, "symmetric", N_("use symmetric encryption")),
88   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
89   ARGPARSE_s_s (oUser, "local-user",
90                 N_("|USER-ID|use USER-ID to sign or decrypt")),
91   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
92   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
93   ARGPARSE_s_n (oQuiet, "quiet",  N_("be somewhat more quiet")),
94   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
95   ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")),
96   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
97   ARGPARSE_s_s (oFilesFrom, "files-from",
98                 N_("|FILE|get names to create from FILE")),
99   ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
100   ARGPARSE_s_n (oOpenPGP, "openpgp", "@"),
101   ARGPARSE_s_n (oCMS, "cms", "@"),
102
103   ARGPARSE_end ()
104 };
105
106
107 \f
108 /* Print usage information and and provide strings for help. */
109 static const char *
110 my_strusage( int level )
111 {
112   const char *p;
113
114   switch (level)
115     {
116     case 11: p = "@GPGTAR@ (@GNUPG@)";
117       break;
118     case 13: p = VERSION; break;
119     case 17: p = PRINTABLE_OS_NAME; break;
120     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
121
122     case 1:
123     case 40:
124       p = _("Usage: gpgtar [options] [files] [directories] (-h for help)");
125       break;
126     case 41:
127       p = _("Syntax: gpgtar [options] [files] [directories]\n"
128             "Encrypt or sign files into an archive\n");
129       break;
130
131     default: p = NULL; break;
132     }
133   return p;
134 }
135
136
137 static void
138 set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
139 {
140   enum cmd_and_opt_values cmd = *ret_cmd;
141
142   if (!cmd || cmd == new_cmd)
143     cmd = new_cmd;
144   else if (cmd == aSign && new_cmd == aEncrypt)
145     cmd = aSignEncrypt;
146   else if (cmd == aEncrypt && new_cmd == aSign)
147     cmd = aSignEncrypt;
148   else
149     {
150       log_error (_("conflicting commands\n"));
151       exit (2);
152     }
153
154   *ret_cmd = cmd;
155 }
156
157 ASSUAN_SYSTEM_NPTH_IMPL;
158
159 \f
160 /* gpgtar main. */
161 int
162 main (int argc, char **argv)
163 {
164   gpg_error_t err;
165   ARGPARSE_ARGS pargs;
166   const char *fname;
167   int no_more_options = 0;
168   enum cmd_and_opt_values cmd = 0;
169   int skip_crypto = 0;
170   const char *files_from = NULL;
171   int null_names = 0;
172
173   assert (sizeof (struct ustar_raw_header) == 512);
174
175   gnupg_reopen_std (GPGTAR_NAME);
176   set_strusage (my_strusage);
177   log_set_prefix (GPGTAR_NAME, 1);
178
179   /* Make sure that our subsystems are ready.  */
180   i18n_init();
181   init_common_subsystems (&argc, &argv);
182   npth_init ();
183   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
184   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
185   assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
186   assuan_sock_init ();
187
188   /* Parse the command line. */
189   pargs.argc  = &argc;
190   pargs.argv  = &argv;
191   pargs.flags = ARGPARSE_FLAG_KEEP;
192   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
193     {
194       switch (pargs.r_opt)
195         {
196         case oOutput:    opt.outfile = pargs.r.ret_str; break;
197         case oSetFilename: opt.filename = pargs.r.ret_str; break;
198         case oQuiet:     opt.quiet = 1; break;
199         case oVerbose:   opt.verbose++; break;
200         case oNoVerbose: opt.verbose = 0; break;
201         case oFilesFrom: files_from = pargs.r.ret_str; break;
202         case oNull: null_names = 1; break;
203
204         case aList:
205         case aDecrypt:
206         case aEncrypt:
207         case aSign:
208           set_cmd (&cmd, pargs.r_opt);
209           break;
210
211         case oRecipient:
212           add_to_strlist (&opt.recipients, pargs.r.ret_str);
213           break;
214
215         case oUser:
216           log_info ("note: ignoring option --user\n");
217           opt.user = pargs.r.ret_str;
218           break;
219
220         case oSymmetric:
221           log_info ("note: ignoring option --symmetric\n");
222           set_cmd (&cmd, aEncrypt);
223           opt.symmetric = 1;
224           break;
225
226         case oGpgProgram:
227           opt.gpg_program = pargs.r.ret_str;
228           break;
229
230         case oSkipCrypto:
231           skip_crypto = 1;
232           break;
233
234         case oOpenPGP: /* Dummy option for now.  */ break;
235         case oCMS:     /* Dummy option for now.  */ break;
236
237         default: pargs.err = 2; break;
238         }
239     }
240
241   if ((files_from && !null_names) || (!files_from && null_names))
242     log_error ("--files-from and --null may only be used in conjunction\n");
243   if (files_from && strcmp (files_from, "-"))
244     log_error ("--files-from only supports argument \"-\"\n");
245
246   if (log_get_errorcount (0))
247     exit (2);
248
249   /* Print a warning if an argument looks like an option.  */
250   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
251     {
252       int i;
253
254       for (i=0; i < argc; i++)
255         if (argv[i][0] == '-' && argv[i][1] == '-')
256           log_info (_("NOTE: '%s' is not considered an option\n"), argv[i]);
257     }
258
259   if (opt.verbose > 1)
260     opt.debug_level = 1024;
261   setup_libassuan_logging (&opt.debug_level);
262
263   switch (cmd)
264     {
265     case aList:
266       if (argc > 1)
267         usage (1);
268       fname = argc ? *argv : NULL;
269       if (opt.filename)
270         log_info ("note: ignoring option --set-filename\n");
271       if (files_from)
272         log_info ("note: ignoring option --files-from\n");
273       err = gpgtar_list (fname, !skip_crypto);
274       if (err && log_get_errorcount (0) == 0)
275         log_error ("listing archive failed: %s\n", gpg_strerror (err));
276       break;
277
278     case aEncrypt:
279       if ((!argc && !null_names)
280           || (argc && null_names))
281         usage (1);
282       if (opt.filename)
283         log_info ("note: ignoring option --set-filename\n");
284       err = gpgtar_create (null_names? NULL :argv, !skip_crypto);
285       if (err && log_get_errorcount (0) == 0)
286         log_error ("creating archive failed: %s\n", gpg_strerror (err));
287       break;
288
289     case aDecrypt:
290       if (argc != 1)
291         usage (1);
292       if (opt.outfile)
293         log_info ("note: ignoring option --output\n");
294       if (files_from)
295         log_info ("note: ignoring option --files-from\n");
296       fname = argc ? *argv : NULL;
297       err = gpgtar_extract (fname, !skip_crypto);
298       if (err && log_get_errorcount (0) == 0)
299         log_error ("extracting archive failed: %s\n", gpg_strerror (err));
300       break;
301
302     default:
303       log_error (_("invalid command (there is no implicit command)\n"));
304       break;
305     }
306
307   return log_get_errorcount (0)? 1:0;
308 }
309
310
311 /* Read the next record from STREAM.  RECORD is a buffer provided by
312    the caller and must be at leadt of size RECORDSIZE.  The function
313    return 0 on success and and error code on failure; a diagnostic
314    printed as well.  Note that there is no need for an EOF indicator
315    because a tarball has an explicit EOF record. */
316 gpg_error_t
317 read_record (estream_t stream, void *record)
318 {
319   gpg_error_t err;
320   size_t nread;
321
322   nread = es_fread (record, 1, RECORDSIZE, stream);
323   if (nread != RECORDSIZE)
324     {
325       err = gpg_error_from_syserror ();
326       if (es_ferror (stream))
327         log_error ("error reading '%s': %s\n",
328                    es_fname_get (stream), gpg_strerror (err));
329       else
330         log_error ("error reading '%s': premature EOF "
331                    "(size of last record: %zu)\n",
332                    es_fname_get (stream), nread);
333     }
334   else
335     err = 0;
336
337   return err;
338 }
339
340
341 /* Write the RECORD of size RECORDSIZE to STREAM.  FILENAME is the
342    name of the file used for diagnostics.  */
343 gpg_error_t
344 write_record (estream_t stream, const void *record)
345 {
346   gpg_error_t err;
347   size_t nwritten;
348
349   nwritten = es_fwrite (record, 1, RECORDSIZE, stream);
350   if (nwritten != RECORDSIZE)
351     {
352       err = gpg_error_from_syserror ();
353       log_error ("error writing '%s': %s\n",
354                  es_fname_get (stream), gpg_strerror (err));
355     }
356   else
357     err = 0;
358
359   return err;
360 }
361
362
363 /* Return true if FP is an unarmored OpenPGP message.  Note that this
364    function reads a few bytes from FP but pushes them back.  */
365 #if 0
366 static int
367 openpgp_message_p (estream_t fp)
368 {
369   int ctb;
370
371   ctb = es_getc (fp);
372   if (ctb != EOF)
373     {
374       if (es_ungetc (ctb, fp))
375         log_fatal ("error ungetting first byte: %s\n",
376                    gpg_strerror (gpg_error_from_syserror ()));
377
378       if ((ctb & 0x80))
379         {
380           switch ((ctb & 0x40) ? (ctb & 0x3f) : ((ctb>>2)&0xf))
381             {
382             case PKT_MARKER:
383             case PKT_SYMKEY_ENC:
384             case PKT_ONEPASS_SIG:
385             case PKT_PUBKEY_ENC:
386             case PKT_SIGNATURE:
387             case PKT_COMMENT:
388             case PKT_OLD_COMMENT:
389             case PKT_PLAINTEXT:
390             case PKT_COMPRESSED:
391             case PKT_ENCRYPTED:
392               return 1; /* Yes, this seems to be an OpenPGP message.  */
393             default:
394               break;
395             }
396         }
397     }
398   return 0;
399 }
400 #endif