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