Updated.
[gnupg.git] / preset-passphrase.c
1 /* preset-passphrase.c - A tool to preset a passphrase.
2  *      Copyright (C) 2002, 2003, 2004 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 #ifdef HAVE_LOCALE_H
33 #include <locale.h>
34 #endif
35 #ifdef HAVE_LANGINFO_CODESET
36 #include <langinfo.h>
37 #endif
38 #ifdef HAVE_DOSISH_SYSTEM
39 #include <fcntl.h> /* for setmode() */
40 #endif
41
42 #define JNLIB_NEED_LOG_LOGV
43 #include "agent.h"
44 #include "minip12.h"
45 #include "simple-pwquery.h"
46 #include "i18n.h"
47 #include "sysutils.h"
48
49
50 enum cmd_and_opt_values 
51 { aNull = 0,
52   oVerbose        = 'v',
53   oPassphrase     = 'P',
54
55   oPreset         = 'c',
56   oForget         = 'f',
57   
58   oNoVerbose = 500,
59
60   oHomedir,
61
62 aTest };
63
64 struct rsa_secret_key_s 
65   {
66     gcry_mpi_t n;           /* public modulus */
67     gcry_mpi_t e;           /* public exponent */
68     gcry_mpi_t d;           /* exponent */
69     gcry_mpi_t p;           /* prime  p. */
70     gcry_mpi_t q;           /* prime  q. */
71     gcry_mpi_t u;           /* inverse of p mod q. */
72   };
73
74
75 static char *opt_homedir;
76 static const char *opt_passphrase;
77
78 static ARGPARSE_OPTS opts[] = {
79   
80   { 301, NULL, 0, N_("@Options:\n ") },
81
82   { oVerbose, "verbose",   0, "verbose" },
83   { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" },
84   { oPreset,  "preset",   256, "preset passphrase"},
85   { oForget,  "forget",  256, "forget passphrase"},
86
87   { oHomedir, "homedir", 2, "@" }, 
88   {0}
89 };
90
91 static const char *
92 my_strusage (int level)
93 {
94   const char *p;
95   switch (level)
96     {
97     case 11: p = "gpg-preset-passphrase (GnuPG)";
98       break;
99     case 13: p = VERSION; break;
100     case 17: p = PRINTABLE_OS_NAME; break;
101     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
102       break;
103     case 1:
104     case 40: p =  _("Usage: gpg-preset-passphrase [options] KEYID (-h for help)\n");
105       break;
106     case 41: p =  _("Syntax: gpg-preset-passphrase [options] KEYID\n"
107                     "Password cache maintenance\n");
108     break;
109     
110     default: p = NULL;
111     }
112   return p;
113 }
114
115
116
117 static void
118 i18n_init (void)
119 {
120 #ifdef USE_SIMPLE_GETTEXT
121     set_gettext_file( PACKAGE_GT );
122 #else
123 #ifdef ENABLE_NLS
124     setlocale (LC_ALL, "");
125     bindtextdomain (PACKAGE_GT, LOCALEDIR);
126     textdomain (PACKAGE_GT);
127 #endif
128 #endif
129 }
130
131 \f
132 static gpg_error_t
133 map_spwq_error (int err)
134 {
135   switch (err)
136     {
137     case 0:
138       return 0;
139     case SPWQ_OUT_OF_CORE:
140       return gpg_error_from_errno (ENOMEM);
141     case SPWQ_IO_ERROR:
142       return gpg_error_from_errno (EIO);
143     case SPWQ_PROTOCOL_ERROR:
144       return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
145     case SPWQ_ERR_RESPONSE:
146       return gpg_error (GPG_ERR_INV_RESPONSE);
147     case SPWQ_NO_AGENT:
148       return gpg_error (GPG_ERR_NO_AGENT);
149     case SPWQ_SYS_ERROR:
150       return gpg_error_from_errno (errno);
151     case SPWQ_GENERAL_ERROR:
152     default:
153       return gpg_error (GPG_ERR_GENERAL);
154     }
155 }
156
157       
158 static void
159 preset_passphrase (const char *keygrip)
160 {
161   int  rc;
162   char *line;
163   /* FIXME: Use secure memory.  */
164   char passphrase[500];
165
166   rc = read (0, passphrase, sizeof (passphrase) - 1);
167   if (rc < 0)
168     {
169       log_error ("reading passphrase failed %s\n",
170                  gpg_strerror (gpg_error_from_errno (errno)));
171       return;
172     }
173   passphrase[rc] = '\0';
174   line = strchr (passphrase, '\n');
175   if (line)
176     {
177       line--;
178       if (line > passphrase && line[-1] == '\r')
179         line--;
180       *line = '\0';
181     }
182
183   /* FIXME: How to handle empty passwords?  */
184
185   rc = asprintf (&line, "PRESET_PASSPHRASE %s -1 %s\n", keygrip, passphrase);
186   if (rc < 0)
187     {
188       log_error ("caching passphrase failed %s\n",
189                  gpg_strerror (gpg_error_from_errno (errno)));
190       return;
191     }
192   wipememory (passphrase, sizeof (passphrase));
193
194   rc = map_spwq_error (simple_query (line));
195   if (rc)
196     {
197       log_error ("caching passphrase failed %s\n", gpg_strerror (rc));
198       return;
199     }
200
201   wipememory (line, strlen (line));
202   free (line);
203 }
204
205
206 static void
207 forget_passphrase (const char *keygrip)
208 {
209   int rc;
210   char *line;
211
212   rc = asprintf (&line, "CLEAR_PASSPHRASE %s\n", keygrip);
213   if (rc < 0)
214     {
215       log_error ("clearing passphrase failed %s\n",
216                  gpg_strerror (gpg_error_from_errno (errno)));
217       return;
218     }
219   free (line);
220 }
221
222 \f
223 int
224 main (int argc, char **argv)
225 {
226   ARGPARSE_ARGS pargs;
227   int cmd = 0;
228   const char *keygrip = NULL;
229
230   set_strusage (my_strusage);
231   log_set_prefix ("gpg-preset-passphrase", 1); 
232
233   /* Try to auto set the character set.  */
234   set_native_charset (NULL); 
235
236   i18n_init ();
237
238   opt_homedir = getenv ("GNUPGHOME");
239 #ifdef HAVE_W32_SYSTEM
240   if (!opt_homedir || !*opt_homedir)
241     opt_homedir = read_w32_registry_string (NULL,
242                                             "Software\\GNU\\GnuPG", "HomeDir");
243 #endif /*HAVE_W32_SYSTEM*/
244   if (!opt_homedir || !*opt_homedir)
245     opt_homedir = GNUPG_DEFAULT_HOMEDIR;
246
247
248   pargs.argc = &argc;
249   pargs.argv = &argv;
250   pargs.flags=  1;  /* (do not remove the args) */
251   while (arg_parse (&pargs, opts) )
252     {
253       switch (pargs.r_opt)
254         {
255         case oVerbose: opt.verbose++; break;
256         case oHomedir: opt_homedir = pargs.r.ret_str; break;
257
258         case oPreset: cmd = oPreset; break;
259         case oForget: cmd = oForget; break;
260         case oPassphrase: opt_passphrase = pargs.r.ret_str; break;
261           
262         default : pargs.err = 2; break;
263         }
264     }
265   if (log_get_errorcount(0))
266     exit(2);
267
268   if (argc == 1)
269     keygrip = *argv;
270   else
271     usage (1);
272
273   if (cmd == oPreset)
274     preset_passphrase (keygrip);
275   else if (cmd == oForget)
276     forget_passphrase (keygrip);
277   else
278     usage (1);
279
280   agent_exit (0);
281   return 8; /*NOTREACHED*/
282 }
283
284
285 void
286 agent_exit (int rc)
287 {
288   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
289   exit (rc);
290 }