* command.c (cmd_get_passphrase): Remove the plus signs.
[gnupg.git] / agent / command.c
1 /* command.c - gpg-agent command handler
2  *      Copyright (C) 2001, 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 /* FIXME: we should not use the default assuan buffering but setup
22    some buffering in secure mempory to protect session keys etc. */
23
24 #include <config.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <unistd.h>
31
32 #include "agent.h"
33 #include "../assuan/assuan.h"
34
35 /* maximum allowed size of the inquired ciphertext */
36 #define MAXLEN_CIPHERTEXT 4096
37 /* maximum allowed size of the key parameters */
38 #define MAXLEN_KEYPARAM 1024
39
40 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
41
42
43 #if MAX_DIGEST_LEN < 20
44 #error MAX_DIGEST_LEN shorter than keygrip
45 #endif
46
47 /* Data used to associate an Assuan context with local server data */
48 struct server_local_s {
49   ASSUAN_CONTEXT assuan_ctx;
50   int message_fd;
51 };
52
53
54
55
56 \f
57 static void
58 reset_notify (ASSUAN_CONTEXT ctx)
59 {
60   CTRL ctrl = assuan_get_pointer (ctx);
61
62   memset (ctrl->keygrip, 0, 20);
63   ctrl->have_keygrip = 0;
64   ctrl->digest.valuelen = 0;
65 }
66
67 /* ISTRUSTED <hexstring_with_fingerprint>
68
69    Return OK when we have an entry with this fingerprint in our
70    trustlist */
71 static int
72 cmd_istrusted (ASSUAN_CONTEXT ctx, char *line)
73 {
74   int rc, n, i;
75   char *p;
76   char fpr[41];
77
78   /* parse the fingerprint value */
79   for (p=line,n=0; hexdigitp (p); p++, n++)
80     ;
81   if (*p || !(n == 40 || n == 32))
82     return set_error (Parameter_Error, "invalid fingerprint");
83   i = 0;
84   if (n==32)
85     {
86       strcpy (fpr, "00000000");
87       i += 8;
88     }
89   for (p=line; i < 40; p++, i++)
90     fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
91   fpr[i] = 0;
92   rc = agent_istrusted (fpr);
93   if (!rc)
94     return 0;
95   else if (rc == -1)
96     return ASSUAN_Not_Trusted;
97   else
98     return map_to_assuan_status (rc);
99 }
100
101 /* LISTTRUSTED 
102
103    List all entries from the trustlist */
104 static int
105 cmd_listtrusted (ASSUAN_CONTEXT ctx, char *line)
106 {
107   return map_to_assuan_status (agent_listtrusted (ctx));
108 }
109
110
111 /* MARKTRUSTED <hexstring_with_fingerprint> <flag>
112
113    Store a new key in into the trustlist*/
114 static int
115 cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line)
116 {
117   return ASSUAN_Not_Implemented;
118 }
119
120
121
122 \f
123 /* SIGKEY <hexstring_with_keygrip>
124    SETKEY <hexstring_with_keygrip>
125   
126    Set the  key used for a sign or decrypt operation */
127 static int
128 cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
129 {
130   int n;
131   char *p;
132   CTRL ctrl = assuan_get_pointer (ctx);
133   unsigned char *buf;
134
135   /* parse the hash value */
136   for (p=line,n=0; hexdigitp (p); p++, n++)
137     ;
138   if (*p)
139     return set_error (Parameter_Error, "invalid hexstring");
140   if ((n&1))
141     return set_error (Parameter_Error, "odd number of digits");
142   n /= 2;
143   if (n != 20)
144     return set_error (Parameter_Error, "invalid length of keygrip");
145
146   buf = ctrl->keygrip;
147   for (p=line, n=0; n < 20; p += 2, n++)
148     buf[n] = xtoi_2 (p);
149   ctrl->have_keygrip = 1;
150   return 0;
151 }
152
153 /* SETHASH <algonumber> <hexstring> 
154
155   The client can use this command to tell the server about the data
156   (which usually is a hash) to be signed. */
157 static int
158 cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
159 {
160   int n;
161   char *p;
162   CTRL ctrl = assuan_get_pointer (ctx);
163   unsigned char *buf;
164   char *endp;
165   int algo;
166
167   /* parse the algo number and check it */
168   algo = (int)strtoul (line, &endp, 10);
169   for (line = endp; *line == ' ' || *line == '\t'; line++)
170     ;
171   if (!algo || gcry_md_test_algo (algo))
172     return set_error (Unsupported_Algorithm, NULL);
173   ctrl->digest.algo = algo;
174
175   /* parse the hash value */
176   for (p=line,n=0; hexdigitp (p); p++, n++)
177     ;
178   if (*p)
179     return set_error (Parameter_Error, "invalid hexstring");
180   if ((n&1))
181     return set_error (Parameter_Error, "odd number of digits");
182   n /= 2;
183   if (n != 16 && n != 20 && n != 24 && n != 32)
184     return set_error (Parameter_Error, "unsupported length of hash");
185   if (n > MAX_DIGEST_LEN)
186     return set_error (Parameter_Error, "hash value to long");
187
188   buf = ctrl->digest.value;
189   ctrl->digest.valuelen = n;
190   for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
191     buf[n] = xtoi_2 (p);
192   for (; n < ctrl->digest.valuelen; n++)
193     buf[n] = 0;
194   return 0;
195 }
196
197
198 /* PKSIGN <options>
199
200    Perform the actual sign operation. Neither input nor output are
201    sensitive to eavesdropping */
202 static int
203 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
204 {
205   int rc;
206   CTRL ctrl = assuan_get_pointer (ctx);
207
208   rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
209   return map_to_assuan_status (rc);
210 }
211
212 /* PKDECRYPT <options>
213
214    Perform the actual decrypt operation.  Input is not 
215    sensitive to eavesdropping */
216 static int
217 cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
218 {
219   int rc;
220   CTRL ctrl = assuan_get_pointer (ctx);
221   char *value;
222   size_t valuelen;
223
224   /* First inquire the data to decrypt */
225   rc = assuan_inquire (ctx, "CIPHERTEXT",
226                        &value, &valuelen, MAXLEN_CIPHERTEXT);
227   if (rc)
228     return rc;
229
230   rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
231   xfree (value);
232   return map_to_assuan_status (rc);
233 }
234
235
236 /* GENKEY
237
238    Generate a new key, store the secret part and return the public
239    part.  Here is an example transaction:
240
241    C: GENKEY
242    S: INQUIRE KEYPARM
243    C: D (genkey (rsa (nbits  1024)))
244    C: END
245    S: D (public-key
246    S: D   (rsa (n 326487324683264) (e 10001)))
247    S  OK key created
248 */
249
250 static int
251 cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
252 {
253   CTRL ctrl = assuan_get_pointer (ctx);
254   int rc;
255   char *value;
256   size_t valuelen;
257
258   /* First inquire the parameters */
259   rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
260   if (rc)
261     return rc;
262
263   rc = agent_genkey (ctrl, value, valuelen, assuan_get_data_fp (ctx));
264   xfree (value);
265   return map_to_assuan_status (rc);
266 }
267
268
269 static void
270 plus_to_blank (char *s)
271 {
272   for (; *s; s++)
273     {
274       if (*s == '+')
275         *s = ' ';
276     }
277 }
278
279 /* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
280
281    This function is usually used to ask for a passphrase to be used
282    for conventional encryption, but may also be used by programs which
283    need specal handling of passphrases.  This command uses a syntax
284    which helps clients to use the agent with minimum effort.  The
285    agent either returns with an error or with a OK followed by the hex
286    encoded passphrase.  Note that the length of the strings is
287    implicitly limited by the maximum length of a command.
288 */
289
290 static int
291 cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
292 {
293   int rc;
294   const char *pw;
295   char *response;
296   char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
297   char *p;
298
299   /* parse the stuff */
300   for (p=line; *p == ' '; p++)
301     ;
302   cacheid = p;
303   p = strchr (cacheid, ' ');
304   if (p)
305     {
306       *p++ = 0;
307       while (*p == ' ')
308         p++;
309       errtext = p;
310       p = strchr (errtext, ' ');
311       if (p)
312         {
313           *p++ = 0;
314           while (*p == ' ')
315             p++;
316           prompt = p;
317           p = strchr (prompt, ' ');
318           if (p)
319             {
320               *p++ = 0;
321               while (*p == ' ')
322                 p++;
323               desc = p;
324               p = strchr (desc, ' ');
325               if (p)
326                 *p = 0; /* ignore garbage */
327             }
328         }
329     }
330   if (!cacheid || !*cacheid || strlen (cacheid) > 50)
331     return set_error (Parameter_Error, "invalid length of cacheID");
332   if (!desc)
333     return set_error (Parameter_Error, "no description given");
334
335   if (!strcmp (cacheid, "X"))
336     cacheid = NULL;
337   if (!strcmp (errtext, "X"))
338     errtext = NULL;
339   if (!strcmp (prompt, "X"))
340     prompt = NULL;
341   if (!strcmp (desc, "X"))
342     desc = NULL;
343
344   /* Note: we store the hexified versions in the cache. */
345   pw = cacheid ? agent_get_cache (cacheid) : NULL;
346   if (pw)
347     {
348       assuan_begin_confidential (ctx);
349       rc = assuan_set_okay_line (ctx, pw);
350     }
351   else
352     {
353       /* Note, that we only need to repalce the + characters and
354          should leave the other escaping in place becuase the escaped
355          sting is send verbatim to the pinentry which does the
356          unescaping (but not the + replacing) */
357       if (errtext)
358         plus_to_blank (errtext);
359       if (prompt)
360         plus_to_blank (prompt);
361       if (desc)
362         plus_to_blank (desc);
363
364       rc = agent_get_passphrase (&response, desc, prompt, errtext);
365       if (!rc)
366         {
367           if (cacheid)
368             agent_put_cache (cacheid, response, 0);
369           assuan_begin_confidential (ctx);
370           rc = assuan_set_okay_line (ctx, response);
371           xfree (response);
372         }
373     }
374
375   return map_to_assuan_status (rc);
376 }
377
378
379 /* CLEAR_PASSPHRASE <cache_id>
380
381    may be used to invalidate the cache entry for a passphrase.  The
382    function returns with OK even when there is no cached passphrase.
383 */
384
385 static int
386 cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
387 {
388   char *cacheid = NULL;
389   char *p;
390
391   /* parse the stuff */
392   for (p=line; *p == ' '; p++)
393     ;
394   cacheid = p;
395   p = strchr (cacheid, ' ');
396   if (p)
397     *p = 0; /* ignore garbage */
398   if (!cacheid || !*cacheid || strlen (cacheid) > 50)
399     return set_error (Parameter_Error, "invalid length of cacheID");
400
401   agent_put_cache (cacheid, NULL, 0);
402   return 0;
403 }
404
405
406 \f
407 /* Tell the assuan library about our commands */
408 static int
409 register_commands (ASSUAN_CONTEXT ctx)
410 {
411   static struct {
412     const char *name;
413     int cmd_id;
414     int (*handler)(ASSUAN_CONTEXT, char *line);
415   } table[] = {
416     { "ISTRUSTED",  0,  cmd_istrusted },
417     { "SIGKEY",     0,  cmd_sigkey },
418     { "SETKEY",     0,  cmd_sigkey },
419     { "SETHASH",    0,  cmd_sethash },
420     { "PKSIGN",     0,  cmd_pksign },
421     { "PKDECRYPT",  0,  cmd_pkdecrypt },
422     { "GENKEY",     0,  cmd_genkey },
423     { "GET_PASSPHRASE",0, cmd_get_passphrase },
424     { "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
425     { "LISTTRUSTED",  0,  cmd_listtrusted },
426     { "MARKTRUSTED",  0,  cmd_marktrusted },
427     { "",     ASSUAN_CMD_INPUT, NULL }, 
428     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
429     { NULL }
430   };
431   int i, j, rc;
432
433   for (i=j=0; table[i].name; i++)
434     {
435       rc = assuan_register_command (ctx,
436                                     table[i].cmd_id? table[i].cmd_id
437                                                    : (ASSUAN_CMD_USER + j++),
438                                     table[i].name, table[i].handler);
439       if (rc)
440         return rc;
441     } 
442   assuan_register_reset_notify (ctx, reset_notify);
443   return 0;
444 }
445
446
447 /* Startup the server.  If LISTEN_FD is given as -1, this is simple
448    piper server, otherwise it is a regular server */
449 void
450 start_command_handler (int listen_fd)
451 {
452   int rc;
453   ASSUAN_CONTEXT ctx;
454   struct server_control_s ctrl;
455
456   memset (&ctrl, 0, sizeof ctrl);
457
458   
459   if (listen_fd == -1)
460     {
461       int filedes[2];
462
463       filedes[0] = 0;
464       filedes[1] = 1;
465       rc = assuan_init_pipe_server (&ctx, filedes);
466     }
467   else
468     {
469       rc = assuan_init_socket_server (&ctx, listen_fd);
470     }
471   if (rc)
472     {
473       log_error ("failed to initialize the server: %s\n",
474                  assuan_strerror(rc));
475       agent_exit (2);
476     }
477   rc = register_commands (ctx);
478   if (rc)
479     {
480       log_error ("failed to register commands with Assuan: %s\n",
481                  assuan_strerror(rc));
482       agent_exit (2);
483     }
484
485   assuan_set_pointer (ctx, &ctrl);
486   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
487   ctrl.server_local->assuan_ctx = ctx;
488   ctrl.server_local->message_fd = -1;
489
490   if (DBG_ASSUAN)
491     assuan_set_log_stream (ctx, log_get_stream ());
492
493   for (;;)
494     {
495       rc = assuan_accept (ctx);
496       if (rc == -1)
497         {
498           break;
499         }
500       else if (rc)
501         {
502           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
503           break;
504         }
505       
506       rc = assuan_process (ctx);
507       if (rc)
508         {
509           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
510           continue;
511         }
512     }
513
514
515   assuan_deinit_server (ctx);
516 }
517
518
519