Updated from latest NewPG project
[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   int use_cache_for_signing;
52 };
53
54
55
56
57 \f
58 static void
59 reset_notify (ASSUAN_CONTEXT ctx)
60 {
61   CTRL ctrl = assuan_get_pointer (ctx);
62
63   memset (ctrl->keygrip, 0, 20);
64   ctrl->have_keygrip = 0;
65   ctrl->digest.valuelen = 0;
66 }
67
68
69 /* Check whether the option NAME appears in LINE */
70 static int
71 has_option (const char *line, const char *name)
72 {
73   const char *s;
74   int n = strlen (name);
75
76   s = strstr (line, name);
77   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
78 }
79
80 /* Parse a hex string.  Return an Assuan error code or 0 on success and the
81    length of the parsed string in LEN. */
82 static int
83 parse_hexstring (ASSUAN_CONTEXT ctx, const char *string, size_t *len)
84 {
85   const char *p;
86   size_t n;
87
88   /* parse the hash value */
89   for (p=string, n=0; hexdigitp (p); p++, n++)
90     ;
91   if (*p)
92     return set_error (Parameter_Error, "invalid hexstring");
93   if ((n&1))
94     return set_error (Parameter_Error, "odd number of digits");
95   *len = n;
96   return 0;
97 }
98
99 /* Parse the keygrip in STRING into the provided buffer BUF.  BUF must
100    provide space for 20 bytes. BUF is not changed if the fucntions
101    returns an error. */
102 static int
103 parse_keygrip (ASSUAN_CONTEXT ctx, const char *string, unsigned char *buf)
104 {
105   int rc;
106   size_t n;
107   const unsigned char *p;
108
109   rc = parse_hexstring (ctx, string, &n);
110   if (rc)
111     return rc;
112   n /= 2;
113   if (n != 20)
114     return set_error (Parameter_Error, "invalid length of keygrip");
115
116   for (p=string, n=0; n < 20; p += 2, n++)
117     buf[n] = xtoi_2 (p);
118
119   return 0;
120 }
121
122
123
124
125 /* ISTRUSTED <hexstring_with_fingerprint>
126
127    Return OK when we have an entry with this fingerprint in our
128    trustlist */
129 static int
130 cmd_istrusted (ASSUAN_CONTEXT ctx, char *line)
131 {
132   int rc, n, i;
133   char *p;
134   char fpr[41];
135
136   /* parse the fingerprint value */
137   for (p=line,n=0; hexdigitp (p); p++, n++)
138     ;
139   if (*p || !(n == 40 || n == 32))
140     return set_error (Parameter_Error, "invalid fingerprint");
141   i = 0;
142   if (n==32)
143     {
144       strcpy (fpr, "00000000");
145       i += 8;
146     }
147   for (p=line; i < 40; p++, i++)
148     fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
149   fpr[i] = 0;
150   rc = agent_istrusted (fpr);
151   if (!rc)
152     return 0;
153   else if (rc == -1)
154     return ASSUAN_Not_Trusted;
155   else
156     {
157       log_error ("command is_trusted failed: %s\n", gnupg_strerror (rc));
158       return map_to_assuan_status (rc);
159     }
160 }
161
162 /* LISTTRUSTED 
163
164    List all entries from the trustlist */
165 static int
166 cmd_listtrusted (ASSUAN_CONTEXT ctx, char *line)
167 {
168   int rc = agent_listtrusted (ctx);
169   if (rc)
170     log_error ("command listtrusted failed: %s\n", gnupg_strerror (rc));
171   return map_to_assuan_status (rc);
172 }
173
174
175 /* MARKTRUSTED <hexstring_with_fingerprint> <flag> <display_name>
176
177    Store a new key in into the trustlist*/
178 static int
179 cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line)
180 {
181   CTRL ctrl = assuan_get_pointer (ctx);
182   int rc, n, i;
183   char *p;
184   char fpr[41];
185   int flag;
186
187   /* parse the fingerprint value */
188   for (p=line,n=0; hexdigitp (p); p++, n++)
189     ;
190   if (!spacep (p) || !(n == 40 || n == 32))
191     return set_error (Parameter_Error, "invalid fingerprint");
192   i = 0;
193   if (n==32)
194     {
195       strcpy (fpr, "00000000");
196       i += 8;
197     }
198   for (p=line; i < 40; p++, i++)
199     fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
200   fpr[i] = 0;
201   
202   while (spacep (p))
203     p++;
204   flag = *p++;
205   if ( (flag != 'S' && flag != 'P') || !spacep (p) )
206     return set_error (Parameter_Error, "invalid flag - must be P or S");
207   while (spacep (p))
208     p++;
209
210   rc = agent_marktrusted (ctrl, p, fpr, flag);
211   if (rc)
212     log_error ("command marktrusted failed: %s\n", gnupg_strerror (rc));
213   return map_to_assuan_status (rc);
214 }
215
216
217
218 \f
219 /* HAVEKEY <hexstring_with_keygrip>
220   
221    Return success when the secret key is available */
222 static int
223 cmd_havekey (ASSUAN_CONTEXT ctx, char *line)
224 {
225   int rc;
226   unsigned char buf[20];
227
228   rc = parse_keygrip (ctx, line, buf);
229   if (rc)
230     return rc;
231
232   if (agent_key_available (buf))
233     return ASSUAN_No_Secret_Key;
234
235   return 0;
236 }
237
238
239 /* SIGKEY <hexstring_with_keygrip>
240    SETKEY <hexstring_with_keygrip>
241   
242    Set the  key used for a sign or decrypt operation */
243 static int
244 cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
245 {
246   int rc;
247   CTRL ctrl = assuan_get_pointer (ctx);
248
249   rc = parse_keygrip (ctx, line, ctrl->keygrip);
250   if (rc)
251     return rc;
252   ctrl->have_keygrip = 1;
253   return 0;
254 }
255
256
257 /* SETHASH <algonumber> <hexstring> 
258
259   The client can use this command to tell the server about the data
260   (which usually is a hash) to be signed. */
261 static int
262 cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
263 {
264   int rc;
265   size_t n;
266   char *p;
267   CTRL ctrl = assuan_get_pointer (ctx);
268   unsigned char *buf;
269   char *endp;
270   int algo;
271
272   /* parse the algo number and check it */
273   algo = (int)strtoul (line, &endp, 10);
274   for (line = endp; *line == ' ' || *line == '\t'; line++)
275     ;
276   if (!algo || gcry_md_test_algo (algo))
277     return set_error (Unsupported_Algorithm, NULL);
278   ctrl->digest.algo = algo;
279
280   /* parse the hash value */
281   rc = parse_hexstring (ctx, line, &n);
282   if (rc)
283     return rc;
284   n /= 2;
285   if (n != 16 && n != 20 && n != 24 && n != 32)
286     return set_error (Parameter_Error, "unsupported length of hash");
287   if (n > MAX_DIGEST_LEN)
288     return set_error (Parameter_Error, "hash value to long");
289
290   buf = ctrl->digest.value;
291   ctrl->digest.valuelen = n;
292   for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
293     buf[n] = xtoi_2 (p);
294   for (; n < ctrl->digest.valuelen; n++)
295     buf[n] = 0;
296   return 0;
297 }
298
299
300 /* PKSIGN <options>
301
302    Perform the actual sign operation. Neither input nor output are
303    sensitive to eavesdropping */
304 static int
305 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
306 {
307   int rc;
308   int ignore_cache = 0;
309   CTRL ctrl = assuan_get_pointer (ctx);
310
311   if (opt.ignore_cache_for_signing)
312     ignore_cache = 1;
313   else if (!ctrl->server_local->use_cache_for_signing)
314     ignore_cache = 1;
315
316   rc = agent_pksign (ctrl, assuan_get_data_fp (ctx), ignore_cache);
317   if (rc)
318     log_error ("command pksign failed: %s\n", gnupg_strerror (rc));
319   return map_to_assuan_status (rc);
320 }
321
322 /* PKDECRYPT <options>
323
324    Perform the actual decrypt operation.  Input is not 
325    sensitive to eavesdropping */
326 static int
327 cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
328 {
329   int rc;
330   CTRL ctrl = assuan_get_pointer (ctx);
331   char *value;
332   size_t valuelen;
333
334   /* First inquire the data to decrypt */
335   rc = assuan_inquire (ctx, "CIPHERTEXT",
336                        &value, &valuelen, MAXLEN_CIPHERTEXT);
337   if (rc)
338     return rc;
339
340   rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
341   xfree (value);
342   if (rc)
343     log_error ("command pkdecrypt failed: %s\n", gnupg_strerror (rc));
344   return map_to_assuan_status (rc);
345 }
346
347
348 /* GENKEY
349
350    Generate a new key, store the secret part and return the public
351    part.  Here is an example transaction:
352
353    C: GENKEY
354    S: INQUIRE KEYPARM
355    C: D (genkey (rsa (nbits  1024)))
356    C: END
357    S: D (public-key
358    S: D   (rsa (n 326487324683264) (e 10001)))
359    S  OK key created
360 */
361
362 static int
363 cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
364 {
365   CTRL ctrl = assuan_get_pointer (ctx);
366   int rc;
367   char *value;
368   size_t valuelen;
369
370   /* First inquire the parameters */
371   rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
372   if (rc)
373     return rc;
374
375   rc = agent_genkey (ctrl, value, valuelen, assuan_get_data_fp (ctx));
376   xfree (value);
377   if (rc)
378     log_error ("command genkey failed: %s\n", gnupg_strerror (rc));
379   return map_to_assuan_status (rc);
380 }
381
382
383 static void
384 plus_to_blank (char *s)
385 {
386   for (; *s; s++)
387     {
388       if (*s == '+')
389         *s = ' ';
390     }
391 }
392
393 /* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
394
395    This function is usually used to ask for a passphrase to be used
396    for conventional encryption, but may also be used by programs which
397    need specal handling of passphrases.  This command uses a syntax
398    which helps clients to use the agent with minimum effort.  The
399    agent either returns with an error or with a OK followed by the hex
400    encoded passphrase.  Note that the length of the strings is
401    implicitly limited by the maximum length of a command.
402 */
403
404 static int
405 cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
406 {
407   CTRL ctrl = assuan_get_pointer (ctx);
408   int rc;
409   const char *pw;
410   char *response;
411   char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
412   char *p;
413   void *cache_marker;
414
415   /* parse the stuff */
416   for (p=line; *p == ' '; p++)
417     ;
418   cacheid = p;
419   p = strchr (cacheid, ' ');
420   if (p)
421     {
422       *p++ = 0;
423       while (*p == ' ')
424         p++;
425       errtext = p;
426       p = strchr (errtext, ' ');
427       if (p)
428         {
429           *p++ = 0;
430           while (*p == ' ')
431             p++;
432           prompt = p;
433           p = strchr (prompt, ' ');
434           if (p)
435             {
436               *p++ = 0;
437               while (*p == ' ')
438                 p++;
439               desc = p;
440               p = strchr (desc, ' ');
441               if (p)
442                 *p = 0; /* ignore garbage */
443             }
444         }
445     }
446   if (!cacheid || !*cacheid || strlen (cacheid) > 50)
447     return set_error (Parameter_Error, "invalid length of cacheID");
448   if (!desc)
449     return set_error (Parameter_Error, "no description given");
450
451   if (!strcmp (cacheid, "X"))
452     cacheid = NULL;
453   if (!strcmp (errtext, "X"))
454     errtext = NULL;
455   if (!strcmp (prompt, "X"))
456     prompt = NULL;
457   if (!strcmp (desc, "X"))
458     desc = NULL;
459
460   /* Note: we store the hexified versions in the cache. */
461   pw = cacheid ? agent_get_cache (cacheid, &cache_marker) : NULL;
462   if (pw)
463     {
464       assuan_begin_confidential (ctx);
465       rc = assuan_set_okay_line (ctx, pw);
466       agent_unlock_cache_entry (&cache_marker);
467     }
468   else
469     {
470       /* Note, that we only need to replace the + characters and
471          should leave the other escaping in place because the escaped
472          string is send verbatim to the pinentry which does the
473          unescaping (but not the + replacing) */
474       if (errtext)
475         plus_to_blank (errtext);
476       if (prompt)
477         plus_to_blank (prompt);
478       if (desc)
479         plus_to_blank (desc);
480
481       rc = agent_get_passphrase (ctrl, &response, desc, prompt, errtext);
482       if (!rc)
483         {
484           if (cacheid)
485             agent_put_cache (cacheid, response, 0);
486           assuan_begin_confidential (ctx);
487           rc = assuan_set_okay_line (ctx, response);
488           xfree (response);
489         }
490     }
491
492   if (rc)
493     log_error ("command get_passphrase failed: %s\n", gnupg_strerror (rc));
494   return map_to_assuan_status (rc);
495 }
496
497
498 /* CLEAR_PASSPHRASE <cache_id>
499
500    may be used to invalidate the cache entry for a passphrase.  The
501    function returns with OK even when there is no cached passphrase.
502 */
503
504 static int
505 cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
506 {
507   char *cacheid = NULL;
508   char *p;
509
510   /* parse the stuff */
511   for (p=line; *p == ' '; p++)
512     ;
513   cacheid = p;
514   p = strchr (cacheid, ' ');
515   if (p)
516     *p = 0; /* ignore garbage */
517   if (!cacheid || !*cacheid || strlen (cacheid) > 50)
518     return set_error (Parameter_Error, "invalid length of cacheID");
519
520   agent_put_cache (cacheid, NULL, 0);
521   return 0;
522 }
523
524 \f
525 /* LEARN [--send]
526
527    Learn something about the currently inserted smartcard.  With
528    --send the new certificates are send back.  */
529 static int
530 cmd_learn (ASSUAN_CONTEXT ctx, char *line)
531 {
532   int rc;
533
534   rc = agent_handle_learn (has_option (line, "--send")? ctx : NULL);
535   if (rc)
536     log_error ("command learn failed: %s\n", gnupg_strerror (rc));
537   return map_to_assuan_status (rc);
538 }
539
540
541 \f
542 /* PASSWD <hexstring_with_keygrip>
543   
544    Change the passphrase/PID for the key identified by keygrip in LINE. */
545 static int
546 cmd_passwd (ASSUAN_CONTEXT ctx, char *line)
547 {
548   CTRL ctrl = assuan_get_pointer (ctx);
549   int rc;
550   unsigned char grip[20];
551   GCRY_SEXP s_skey = NULL;
552   unsigned char *shadow_info = NULL;
553
554   rc = parse_keygrip (ctx, line, grip);
555   if (rc)
556     return rc; /* we can't jump to leave because this is already an
557                   Assuan error code. */
558
559   s_skey = agent_key_from_file (ctrl, grip, &shadow_info, 1);
560   if (!s_skey && !shadow_info)
561     rc = seterr (No_Secret_Key);
562   else if (!s_skey)
563     {
564       log_error ("changing a smartcard PIN is not yet supported\n");
565       rc = seterr (Not_Implemented);
566     }
567   else
568     rc = agent_protect_and_store (ctrl, s_skey);
569
570   gcry_sexp_release (s_skey);
571   xfree (shadow_info);
572   if (rc)
573     log_error ("command passwd failed: %s\n", gnupg_strerror (rc));
574   return map_to_assuan_status (rc);
575 }
576
577
578 \f
579 static int
580 option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
581 {
582    CTRL ctrl = assuan_get_pointer (ctx);
583
584   if (!strcmp (key, "display"))
585     {
586       if (ctrl->display)
587         free (ctrl->display);
588       ctrl->display = strdup (value);
589       if (!ctrl->display)
590         return ASSUAN_Out_Of_Core;
591     }
592   else if (!strcmp (key, "ttyname"))
593     {
594       if (!opt.keep_tty)
595         {
596           if (ctrl->ttyname)
597             free (ctrl->ttyname);
598           ctrl->ttyname = strdup (value);
599           if (!ctrl->ttyname)
600             return ASSUAN_Out_Of_Core;
601         }
602     }
603   else if (!strcmp (key, "ttytype"))
604     {
605       if (!opt.keep_tty)
606         {
607           if (ctrl->ttytype)
608             free (ctrl->ttytype);
609           ctrl->ttytype = strdup (value);
610           if (!ctrl->ttytype)
611             return ASSUAN_Out_Of_Core;
612         }
613     }
614   else if (!strcmp (key, "lc-ctype"))
615     {
616       if (ctrl->lc_ctype)
617         free (ctrl->lc_ctype);
618       ctrl->lc_ctype = strdup (value);
619       if (!ctrl->lc_ctype)
620         return ASSUAN_Out_Of_Core;
621     }
622   else if (!strcmp (key, "lc-messages"))
623     {
624       if (ctrl->lc_messages)
625         free (ctrl->lc_messages);
626       ctrl->lc_messages = strdup (value);
627       if (!ctrl->lc_messages)
628         return ASSUAN_Out_Of_Core;
629     }
630   else if (!strcmp (key, "use-cache-for-signing"))
631     ctrl->server_local->use_cache_for_signing = *value? atoi (value) : 0;
632   else
633     return ASSUAN_Invalid_Option;
634
635   return 0;
636 }
637
638 \f
639 /* Tell the assuan library about our commands */
640 static int
641 register_commands (ASSUAN_CONTEXT ctx)
642 {
643   static struct {
644     const char *name;
645     int cmd_id;
646     int (*handler)(ASSUAN_CONTEXT, char *line);
647   } table[] = {
648     { "ISTRUSTED",  0,  cmd_istrusted },
649     { "HAVEKEY",    0,  cmd_havekey },
650     { "SIGKEY",     0,  cmd_sigkey },
651     { "SETKEY",     0,  cmd_sigkey },
652     { "SETHASH",    0,  cmd_sethash },
653     { "PKSIGN",     0,  cmd_pksign },
654     { "PKDECRYPT",  0,  cmd_pkdecrypt },
655     { "GENKEY",     0,  cmd_genkey },
656     { "GET_PASSPHRASE",0, cmd_get_passphrase },
657     { "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
658     { "LISTTRUSTED",  0,  cmd_listtrusted },
659     { "MARKTRUSTED",  0,  cmd_marktrusted },
660     { "LEARN",        0,  cmd_learn },
661     { "PASSWD",       0,  cmd_passwd },
662     { "",     ASSUAN_CMD_INPUT, NULL }, 
663     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
664     { NULL }
665   };
666   int i, j, rc;
667
668   for (i=j=0; table[i].name; i++)
669     {
670       rc = assuan_register_command (ctx,
671                                     table[i].cmd_id? table[i].cmd_id
672                                                    : (ASSUAN_CMD_USER + j++),
673                                     table[i].name, table[i].handler);
674       if (rc)
675         return rc;
676     } 
677   assuan_register_reset_notify (ctx, reset_notify);
678   assuan_register_option_handler (ctx, option_handler);
679   return 0;
680 }
681
682
683 /* Startup the server.  If LISTEN_FD and FD is given as -1, this is a simple
684    piper server, otherwise it is a regular server */
685 void
686 start_command_handler (int listen_fd, int fd)
687 {
688   int rc;
689   ASSUAN_CONTEXT ctx;
690   struct server_control_s ctrl;
691
692   memset (&ctrl, 0, sizeof ctrl);
693   agent_init_default_ctrl (&ctrl);
694   
695   if (listen_fd == -1 && fd == -1)
696     {
697       int filedes[2];
698
699       filedes[0] = 0;
700       filedes[1] = 1;
701       rc = assuan_init_pipe_server (&ctx, filedes);
702     }
703   else if (listen_fd != -1)
704     {
705       rc = assuan_init_socket_server (&ctx, listen_fd);
706     }
707   else 
708     {
709       rc = assuan_init_connected_socket_server (&ctx, fd);
710     }
711   if (rc)
712     {
713       log_error ("failed to initialize the server: %s\n",
714                  assuan_strerror(rc));
715       agent_exit (2);
716     }
717   rc = register_commands (ctx);
718   if (rc)
719     {
720       log_error ("failed to register commands with Assuan: %s\n",
721                  assuan_strerror(rc));
722       agent_exit (2);
723     }
724
725   assuan_set_pointer (ctx, &ctrl);
726   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
727   ctrl.server_local->assuan_ctx = ctx;
728   ctrl.server_local->message_fd = -1;
729   ctrl.server_local->use_cache_for_signing = 1;
730
731   if (DBG_ASSUAN)
732     assuan_set_log_stream (ctx, log_get_stream ());
733
734   for (;;)
735     {
736       rc = assuan_accept (ctx);
737       if (rc == -1)
738         {
739           break;
740         }
741       else if (rc)
742         {
743           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
744           break;
745         }
746       
747       rc = assuan_process (ctx);
748       if (rc)
749         {
750           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
751           continue;
752         }
753     }
754
755
756   assuan_deinit_server (ctx);
757   if (ctrl.display)
758     free (ctrl.display);
759   if (ctrl.ttyname)
760     free (ctrl.ttyname);
761   if (ctrl.ttytype)
762     free (ctrl.ttytype);
763   if (ctrl.lc_ctype)
764     free (ctrl.lc_ctype);
765   if (ctrl.lc_messages)
766     free (ctrl.lc_messages);
767 }
768