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