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