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