* protect-tool.c (show_file): New. Used as default action.
[gnupg.git] / agent / protect-tool.c
1 /* protect-tool.c - A tool to text the secret key protection
2  *      Copyright (C) 2002 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #include <gcrypt.h>
34
35 #define JNLIB_NEED_LOG_LOGV
36 #include "agent.h"
37
38 #define N_(a) a
39 #define _(a) a
40
41
42 enum cmd_and_opt_values 
43 { aNull = 0,
44   oVerbose        = 'v',
45   oArmor          = 'a',
46   oPassphrase     = 'P',
47
48   oProtect        = 'p',
49   oUnprotect      = 'u',
50   
51   oNoVerbose = 500,
52   oShadow,
53   oShowShadowInfo,
54
55 aTest };
56
57
58 static int opt_armor;
59 static const char *passphrase = "abc";
60
61 static ARGPARSE_OPTS opts[] = {
62   
63   { 301, NULL, 0, N_("@Options:\n ") },
64
65   { oVerbose, "verbose",   0, "verbose" },
66   { oArmor,   "armor",     0, "write output in advanced format" },
67   { oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" },
68   { oProtect, "protect",     256, "protect a private key"},
69   { oUnprotect, "unprotect", 256, "unprotect a private key"},
70   { oShadow,  "shadow", 256, "create a shadow entry for a priblic key"},
71   { oShowShadowInfo,  "show-shadow-info", 256, "return the shadow info"},
72
73   {0}
74 };
75
76 static const char *
77 my_strusage (int level)
78 {
79   const char *p;
80   switch (level)
81     {
82     case 11: p = "protect-tool (GnuPG)";
83       break;
84     case 13: p = VERSION; break;
85     case 17: p = PRINTABLE_OS_NAME; break;
86     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
87       break;
88     case 1:
89     case 40: p =  _("Usage: protect-tool [options] (-h for help)\n");
90       break;
91     case 41: p =  _("Syntax: protect-tool [options] [args]]\n"
92                     "INTERNAL USE ONLY!\n");
93     break;
94     
95     default: p = NULL;
96     }
97   return p;
98 }
99
100
101
102 static void
103 i18n_init (void)
104 {
105 #ifdef USE_SIMPLE_GETTEXT
106     set_gettext_file( PACKAGE );
107 #else
108 #ifdef ENABLE_NLS
109     /* gtk_set_locale (); HMMM: We have not yet called gtk_init */
110     bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
111     textdomain( PACKAGE );
112 #endif
113 #endif
114 }
115
116
117
118 /* Used by gcry for logging */
119 static void
120 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
121 {
122   /* translate the log levels */
123   switch (level)
124     {
125     case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
126     case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
127     case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
128     case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
129     case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
130     case GCRY_LOG_BUG:  level = JNLIB_LOG_BUG; break;
131     case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
132     default:            level = JNLIB_LOG_ERROR; break;      }
133   log_logv (level, fmt, arg_ptr);
134 }
135
136 \f
137 static unsigned char *
138 make_canonical (const char *fname, const char *buf, size_t buflen)
139 {
140   int rc;
141   size_t erroff, len;
142   GCRY_SEXP sexp;
143   unsigned char *result;
144
145   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
146   if (rc)
147     {
148       log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
149                  fname, (unsigned int)erroff, gcry_strerror (rc));
150       return NULL;
151     }
152   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
153   assert (len);
154   result = xmalloc (len);
155   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
156   assert (len);
157   gcry_sexp_release (sexp);
158   return result;
159 }
160
161 static char *
162 make_advanced (const unsigned char *buf, size_t buflen)
163 {
164   int rc;
165   size_t erroff, len;
166   GCRY_SEXP sexp;
167   unsigned char *result;
168
169   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
170   if (rc)
171     {
172       log_error ("invalid canonical S-Expression (off=%u): %s\n",
173                  (unsigned int)erroff, gcry_strerror (rc));
174       return NULL;
175     }
176   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
177   assert (len);
178   result = xmalloc (len);
179   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
180   assert (len);
181   gcry_sexp_release (sexp);
182   return result;
183 }
184
185
186 static unsigned char *
187 read_key (const char *fname)
188 {
189   FILE *fp;
190   struct stat st;
191   char *buf;
192   size_t buflen;
193   unsigned char *key;
194   
195   fp = fopen (fname, "rb");
196   if (!fp)
197     {
198       log_error ("can't open `%s': %s\n", fname, strerror (errno));
199       return NULL;
200     }
201   
202   if (fstat (fileno(fp), &st))
203     {
204       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
205       fclose (fp);
206       return NULL;
207     }
208
209   buflen = st.st_size;
210   buf = xmalloc (buflen+1);
211   if (fread (buf, buflen, 1, fp) != 1)
212     {
213       log_error ("error reading `%s': %s\n", fname, strerror (errno));
214       fclose (fp);
215       xfree (buf);
216       return NULL;
217     }
218   fclose (fp);
219
220   key = make_canonical (fname, buf, buflen);
221   xfree (buf);
222   return key;
223 }
224
225
226 \f
227 static void
228 read_and_protect (const char *fname)
229 {
230   int  rc;
231   unsigned char *key;
232   unsigned char *result;
233   size_t resultlen;
234   
235   key = read_key (fname);
236   if (!key)
237     return;
238
239   rc = agent_protect (key, passphrase, &result, &resultlen);
240   xfree (key);
241   if (rc)
242     {
243       log_error ("protecting the key failed: %s\n", gnupg_strerror (rc));
244       return;
245     }
246   
247   if (opt_armor)
248     {
249       char *p = make_advanced (result, resultlen);
250       xfree (result);
251       if (!p)
252         return;
253       result = p;
254       resultlen = strlen (p);
255     }
256
257   fwrite (result, resultlen, 1, stdout);
258   xfree (result);
259 }
260
261
262 static void
263 read_and_unprotect (const char *fname)
264 {
265   int  rc;
266   unsigned char *key;
267   unsigned char *result;
268   size_t resultlen;
269   
270   key = read_key (fname);
271   if (!key)
272     return;
273
274   rc = agent_unprotect (key, passphrase, &result, &resultlen);
275   xfree (key);
276   if (rc)
277     {
278       log_error ("unprotecting the key failed: %s\n", gnupg_strerror (rc));
279       return;
280     }
281   
282   if (opt_armor)
283     {
284       char *p = make_advanced (result, resultlen);
285       xfree (result);
286       if (!p)
287         return;
288       result = p;
289       resultlen = strlen (p);
290     }
291
292   fwrite (result, resultlen, 1, stdout);
293   xfree (result);
294 }
295
296
297 \f
298 static void
299 read_and_shadow (const char *fname)
300 {
301   int  rc;
302   unsigned char *key;
303   unsigned char *result;
304   size_t resultlen;
305   
306   key = read_key (fname);
307   if (!key)
308     return;
309
310   rc = agent_shadow_key (key, "(8:313233342:43)", &result);
311   xfree (key);
312   if (rc)
313     {
314       log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc));
315       return;
316     }
317   resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
318   assert (resultlen);
319   
320   if (opt_armor)
321     {
322       char *p = make_advanced (result, resultlen);
323       xfree (result);
324       if (!p)
325         return;
326       result = p;
327       resultlen = strlen (p);
328     }
329
330   fwrite (result, resultlen, 1, stdout);
331   xfree (result);
332 }
333
334 static void
335 show_shadow_info (const char *fname)
336 {
337   int  rc;
338   unsigned char *key;
339   const unsigned char *info;
340   size_t infolen;
341   
342   key = read_key (fname);
343   if (!key)
344     return;
345
346   rc = agent_get_shadow_info (key, &info);
347   xfree (key);
348   if (rc)
349     {
350       log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
351       return;
352     }
353   infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
354   assert (infolen);
355   
356   if (opt_armor)
357     {
358       char *p = make_advanced (info, infolen);
359       if (!p)
360         return;
361       fwrite (p, strlen (p), 1, stdout);
362       xfree (p);
363     }
364   else
365     fwrite (info, infolen, 1, stdout);
366 }
367
368
369 static void
370 show_file (const char *fname)
371 {
372   unsigned char *key;
373   size_t keylen;
374   char *p;
375   
376   key = read_key (fname);
377   if (!key)
378     return;
379   keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
380   assert (keylen);
381
382   p = make_advanced (key, keylen);
383   xfree (key);
384   if (p)
385     {
386       fwrite (p, strlen (p), 1, stdout);
387       xfree (p);
388     }
389 }
390
391
392
393
394 int
395 main (int argc, char **argv )
396 {
397   ARGPARSE_ARGS pargs;
398   int cmd = 0;
399
400   set_strusage (my_strusage);
401   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
402   log_set_prefix ("protect-tool", 1); 
403   i18n_init ();
404
405   if (!gcry_check_version ( "1.1.5" ) )
406     {
407       log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
408                  "1.1.5", gcry_check_version (NULL) );
409     }
410
411   gcry_set_log_handler (my_gcry_logger, NULL);
412   
413   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
414
415   pargs.argc = &argc;
416   pargs.argv = &argv;
417   pargs.flags=  1;  /* do not remove the args */
418   while (arg_parse (&pargs, opts) )
419     {
420       switch (pargs.r_opt)
421         {
422         case oVerbose: opt.verbose++; break;
423         case oArmor:   opt_armor=1; break;
424
425         case oProtect: cmd = oProtect; break;
426         case oUnprotect: cmd = oUnprotect; break;
427         case oShadow: cmd = oShadow; break;
428         case oShowShadowInfo: cmd = oShowShadowInfo; break;
429
430         case oPassphrase: passphrase = pargs.r.ret_str; break;
431
432         default : pargs.err = 2; break;
433         }
434     }
435   if (log_get_errorcount(0))
436     exit(2);
437
438   if (argc != 1)
439     usage (1);
440
441   if (cmd == oProtect)
442     read_and_protect (*argv);
443   else if (cmd == oUnprotect)
444     read_and_unprotect (*argv);
445   else if (cmd == oShadow)
446     read_and_shadow (*argv);
447   else if (cmd == oShowShadowInfo)
448     show_shadow_info (*argv);
449   else
450     show_file (*argv);
451
452   return 0;
453 }
454
455 void
456 agent_exit (int rc)
457 {
458   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
459   exit (rc);
460 }