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