Imported Upstream version 2.0.19
[platform/upstream/gpg2.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 #ifdef HAVE_STAT
36 # include <sys/stat.h>
37 #endif
38
39 #include "util.h"
40 #include "i18n.h"
41 #include "sysutils.h"
42 #include "../common/openpgpdefs.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     aEncrypt    = 'e',
52     aDecrypt    = 'd',
53     aSign       = 's',
54     aList       = 't',
55
56     oSymmetric  = 'c',
57     oRecipient  = 'r',
58     oUser       = 'u',
59     oOutput     = 'o',
60     oQuiet      = 'q',
61     oVerbose    = 'v',
62     oFilesFrom  = 'T',
63     oNoVerbose  = 500,
64
65     aSignEncrypt,
66     oSkipCrypto,
67     oOpenPGP,
68     oCMS,
69     oSetFilename,
70     oNull
71   };
72
73
74 /* The list of commands and options. */
75 static ARGPARSE_OPTS opts[] = {
76   ARGPARSE_group (300, N_("@Commands:\n ")),
77     
78   ARGPARSE_c (aEncrypt,   "encrypt", N_("create an archive")),
79   ARGPARSE_c (aDecrypt,   "decrypt", N_("extract an archive")),
80   ARGPARSE_c (aSign,      "sign",    N_("create a signed archive")),
81   ARGPARSE_c (aList,      "list-archive", N_("list an archive")),
82
83   ARGPARSE_group (301, N_("@\nOptions:\n ")),
84
85   ARGPARSE_s_n (oSymmetric, "symmetric", N_("use symmetric encryption")),
86   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
87   ARGPARSE_s_s (oUser, "local-user",
88                 N_("|USER-ID|use USER-ID to sign or decrypt")),
89   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
90   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
91   ARGPARSE_s_n (oQuiet, "quiet",  N_("be somewhat more quiet")),
92   ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")),
93   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
94   ARGPARSE_s_s (oFilesFrom, "files-from",
95                 N_("|FILE|get names to create from FILE")),
96   ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
97   ARGPARSE_s_n (oOpenPGP, "openpgp", "@"),
98   ARGPARSE_s_n (oCMS, "cms", "@"),
99
100   ARGPARSE_end ()
101 };
102
103
104 \f
105 static void tar_and_encrypt (char **inpattern);
106 static void decrypt_and_untar (const char *fname);
107 static void decrypt_and_list (const char *fname);
108
109
110
111 \f
112 /* Print usage information and and provide strings for help. */
113 static const char *
114 my_strusage( int level )
115 {
116   const char *p;
117
118   switch (level)
119     {
120     case 11: p = "gpgtar (GnuPG)";
121       break;
122     case 13: p = VERSION; break;
123     case 17: p = PRINTABLE_OS_NAME; break;
124     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
125
126     case 1:
127     case 40:
128       p = _("Usage: gpgtar [options] [files] [directories] (-h for help)");
129       break;
130     case 41:
131       p = _("Syntax: gpgtar [options] [files] [directories]\n"
132             "Encrypt or sign files into an archive\n");
133       break;
134
135     default: p = NULL; break;
136     }
137   return p;
138 }
139
140
141 static void
142 set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
143 {
144   enum cmd_and_opt_values cmd = *ret_cmd;
145
146   if (!cmd || cmd == new_cmd)
147     cmd = new_cmd;
148   else if (cmd == aSign && new_cmd == aEncrypt)
149     cmd = aSignEncrypt;
150   else if (cmd == aEncrypt && new_cmd == aSign)
151     cmd = aSignEncrypt;
152   else 
153     {
154       log_error (_("conflicting commands\n"));
155       exit (2);
156     }
157
158   *ret_cmd = cmd;
159 }
160
161
162 \f
163 /* gpgtar main. */
164 int
165 main (int argc, char **argv)
166 {
167   ARGPARSE_ARGS pargs;
168   const char *fname;
169   int no_more_options = 0;
170   enum cmd_and_opt_values cmd = 0;
171   int skip_crypto = 0;
172   const char *files_from = NULL;
173   int null_names = 0;
174
175   assert (sizeof (struct ustar_raw_header) == 512);
176
177   gnupg_reopen_std ("gpgtar");
178   set_strusage (my_strusage);
179   log_set_prefix ("gpgtar", 1);
180
181   /* Make sure that our subsystems are ready.  */
182   i18n_init();
183   init_common_subsystems ();
184
185   /* Parse the command line. */
186   pargs.argc  = &argc;
187   pargs.argv  = &argv;
188   pargs.flags = ARGPARSE_FLAG_KEEP;
189   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
190     {
191       switch (pargs.r_opt)
192         {
193         case oOutput:    opt.outfile = pargs.r.ret_str; break;
194         case oSetFilename: opt.filename = pargs.r.ret_str; break;
195         case oQuiet:     opt.quiet = 1; break;
196         case oVerbose:   opt.verbose++; break;
197         case oNoVerbose: opt.verbose = 0; break;
198         case oFilesFrom: files_from = pargs.r.ret_str; break;
199         case oNull: null_names = 1; break;
200           
201         case aList:
202         case aDecrypt:
203         case aEncrypt:
204         case aSign:
205           set_cmd (&cmd, pargs.r_opt);
206           break;
207
208         case oSymmetric:
209           set_cmd (&cmd, aEncrypt);
210           opt.symmetric = 1;
211           break;
212
213         case oSkipCrypto:
214           skip_crypto = 1;
215           break;
216
217         case oOpenPGP: /* Dummy option for now.  */ break;
218         case oCMS:     /* Dummy option for now.  */ break;
219
220         default: pargs.err = 2; break;
221         }
222     }
223   
224   if ((files_from && !null_names) || (!files_from && null_names))
225     log_error ("--files-from and --null may only be used in conjunction\n");
226   if (files_from && strcmp (files_from, "-"))
227     log_error ("--files-from only supports argument \"-\"\n");
228
229   if (log_get_errorcount (0))
230     exit (2);
231
232   switch (cmd)
233     {
234     case aList:
235       if (argc > 1)
236         usage (1);
237       fname = argc ? *argv : NULL;
238       if (opt.filename)
239         log_info ("note: ignoring option --set-filename\n");
240       if (files_from)
241         log_info ("note: ignoring option --files-from\n");
242       if (skip_crypto)
243         gpgtar_list (fname);
244       else
245         decrypt_and_list (fname);
246       break;
247
248     case aEncrypt:
249       if ((!argc && !null_names)
250           || (argc && null_names))
251         usage (1);
252       if (opt.filename)
253         log_info ("note: ignoring option --set-filename\n");
254       if (skip_crypto)
255         gpgtar_create (null_names? NULL :argv);
256       else
257         tar_and_encrypt (null_names? NULL : argv);
258       break;
259
260     case aDecrypt:
261       if (argc != 1)
262         usage (1);
263       if (opt.outfile)
264         log_info ("note: ignoring option --output\n");
265       if (files_from)
266         log_info ("note: ignoring option --files-from\n");
267       fname = argc ? *argv : NULL;
268       if (skip_crypto)
269         gpgtar_extract (fname);
270       else
271         decrypt_and_untar (fname);
272       break;
273
274     default:
275       log_error (_("invalid command (there is no implicit command)\n"));
276       break;
277     }
278
279   return log_get_errorcount (0)? 1:0;
280 }
281
282
283 /* Read the next record from STREAM.  RECORD is a buffer provided by
284    the caller and must be at leadt of size RECORDSIZE.  The function
285    return 0 on success and and error code on failure; a diagnostic
286    printed as well.  Note that there is no need for an EOF indicator
287    because a tarball has an explicit EOF record. */
288 gpg_error_t
289 read_record (estream_t stream, void *record)
290 {
291   gpg_error_t err;
292   size_t nread;
293
294   nread = es_fread (record, 1, RECORDSIZE, stream);
295   if (nread != RECORDSIZE)
296     {
297       err = gpg_error_from_syserror ();
298       if (es_ferror (stream))
299         log_error ("error reading `%s': %s\n",
300                    es_fname_get (stream), gpg_strerror (err));
301       else
302         log_error ("error reading `%s': premature EOF "
303                    "(size of last record: %zu)\n",
304                    es_fname_get (stream), nread);
305     }
306   else
307     err = 0;
308
309   return err;
310 }
311
312
313 /* Write the RECORD of size RECORDSIZE to STREAM.  FILENAME is the
314    name of the file used for diagnostics.  */
315 gpg_error_t
316 write_record (estream_t stream, const void *record)
317 {
318   gpg_error_t err;
319   size_t nwritten;
320
321   nwritten = es_fwrite (record, 1, RECORDSIZE, stream);
322   if (nwritten != RECORDSIZE)
323     {
324       err = gpg_error_from_syserror ();
325       log_error ("error writing `%s': %s\n",
326                  es_fname_get (stream), gpg_strerror (err));
327     }
328   else
329     err = 0;
330   
331   return err;
332 }
333
334
335 /* Return true if FP is an unarmored OpenPGP message.  Note that this
336    fucntion reads a few bytes from FP but pushes them back.  */
337 #if 0
338 static int
339 openpgp_message_p (estream_t fp)
340 {
341   int ctb;
342
343   ctb = es_getc (fp);
344   if (ctb != EOF)
345     {
346       if (es_ungetc (ctb, fp))
347         log_fatal ("error ungetting first byte: %s\n", 
348                    gpg_strerror (gpg_error_from_syserror ()));
349       
350       if ((ctb & 0x80))
351         {
352           switch ((ctb & 0x40) ? (ctb & 0x3f) : ((ctb>>2)&0xf))
353             {
354             case PKT_MARKER:
355             case PKT_SYMKEY_ENC:
356             case PKT_ONEPASS_SIG:
357             case PKT_PUBKEY_ENC:
358             case PKT_SIGNATURE:
359             case PKT_COMMENT:
360             case PKT_OLD_COMMENT:
361             case PKT_PLAINTEXT:
362             case PKT_COMPRESSED:
363             case PKT_ENCRYPTED:
364               return 1; /* Yes, this seems to be an OpenPGP message.  */
365             default:
366               break;
367             }
368         }
369     }
370   return 0;
371 }
372 #endif
373
374
375
376 \f
377 static void
378 tar_and_encrypt (char **inpattern)
379 {
380   (void)inpattern;
381   log_error ("tar_and_encrypt has not yet been implemented\n");
382 }
383
384
385 \f
386 static void
387 decrypt_and_untar (const char *fname)
388 {
389   (void)fname;
390   log_error ("decrypt_and_untar has not yet been implemented\n");
391 }
392
393
394 \f
395 static void
396 decrypt_and_list (const char *fname)
397 {
398   (void)fname;
399   log_error ("decrypt_and_list has not yet been implemented\n");
400 }
401
402
403
404
405 /* A wrapper around mkdir which takes a string for the mode argument.
406    This makes it easier to handle the mode argument which is not
407    defined on all systems.  The format of the modestring is
408
409       "-rwxrwxrwx"
410       
411    '-' is a don't care or not set.  'r', 'w', 'x' are read allowed,
412    write allowed, execution allowed with the first group for the user,
413    the second for the group and the third for all others.  If the
414    string is shorter than above the missing mode characters are meant
415    to be not set.  */
416 int
417 gnupg_mkdir (const char *name, const char *modestr)
418 {
419 #ifdef HAVE_W32CE_SYSTEM
420   wchar_t *wname;
421   (void)modestr;
422   
423   wname = utf8_to_wchar (name);
424   if (!wname)
425     return -1;
426   if (!CreateDirectoryW (wname, NULL))
427     {
428       xfree (wname);
429       return -1;  /* ERRNO is automagically provided by gpg-error.h.  */
430     }
431   xfree (wname);
432   return 0;
433 #elif MKDIR_TAKES_ONE_ARG
434   (void)modestr;
435   /* Note: In the case of W32 we better use CreateDirectory and try to
436      set appropriate permissions.  However using mkdir is easier
437      because this sets ERRNO.  */
438   return mkdir (name);
439 #else
440   mode_t mode = 0;
441
442   if (modestr && *modestr)
443     {
444       modestr++;
445       if (*modestr && *modestr++ == 'r')
446         mode |= S_IRUSR;
447       if (*modestr && *modestr++ == 'w')
448         mode |= S_IWUSR;
449       if (*modestr && *modestr++ == 'x')
450         mode |= S_IXUSR;
451       if (*modestr && *modestr++ == 'r')
452         mode |= S_IRGRP;
453       if (*modestr && *modestr++ == 'w')
454         mode |= S_IWGRP;
455       if (*modestr && *modestr++ == 'x')
456         mode |= S_IXGRP;
457       if (*modestr && *modestr++ == 'r')
458         mode |= S_IROTH;
459       if (*modestr && *modestr++ == 'w')
460         mode |= S_IWOTH;
461       if (*modestr && *modestr++ == 'x')
462         mode |= S_IXOTH;
463     }
464   return mkdir (name, mode);
465 #endif
466 }
467
468 #ifdef HAVE_W32_SYSTEM
469 /* Return a malloced string encoded in UTF-8 from the wide char input
470    string STRING.  Caller must free this value.  Returns NULL and sets
471    ERRNO on failure.  Calling this function with STRING set to NULL is
472    not defined.  */
473 char *
474 wchar_to_utf8 (const wchar_t *string)
475 {
476   int n;
477   char *result;
478
479   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
480   if (n < 0)
481     {
482       errno = EINVAL;
483       return NULL;
484     }
485
486   result = xtrymalloc (n+1);
487   if (!result)
488     return NULL;
489
490   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
491   if (n < 0)
492     {
493       xfree (result);
494       errno = EINVAL;
495       result = NULL;
496     }
497   return result;
498 }
499
500
501 /* Return a malloced wide char string from an UTF-8 encoded input
502    string STRING.  Caller must free this value.  Returns NULL and sets
503    ERRNO on failure.  Calling this function with STRING set to NULL is
504    not defined.  */
505 wchar_t *
506 utf8_to_wchar (const char *string)
507 {
508   int n;
509   size_t nbytes;
510   wchar_t *result;
511
512   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
513   if (n < 0)
514     {
515       errno = EINVAL;
516       return NULL;
517     }
518
519   nbytes = (size_t)(n+1) * sizeof(*result);
520   if (nbytes / sizeof(*result) != (n+1)) 
521     {
522       errno = ENOMEM;
523       return NULL;
524     }
525   result = xtrymalloc (nbytes);
526   if (!result)
527     return NULL;
528
529   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
530   if (n < 0)
531     {
532       free (result);
533       errno = EINVAL;
534       result = NULL;
535     }
536   return result;
537 }
538 #endif /*HAVE_W32_SYSTEM*/