First take on a W32 port
[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, ctrl->server_local->keydesc,
668                             grip, &shadow_info, 1, &s_skey);
669   if (rc)
670     ;
671   else if (!s_skey)
672     {
673       log_error ("changing a smartcard PIN is not yet supported\n");
674       rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
675     }
676   else
677     rc = agent_protect_and_store (ctrl, s_skey);
678
679   xfree (ctrl->server_local->keydesc);
680   ctrl->server_local->keydesc = NULL;
681   gcry_sexp_release (s_skey);
682   xfree (shadow_info);
683   if (rc)
684     log_error ("command passwd failed: %s\n", gpg_strerror (rc));
685   return map_to_assuan_status (rc);
686 }
687
688 \f
689 /* SCD <commands to pass to the scdaemon>
690   
691    This is a general quote command to redirect everything to the
692    SCDAEMON. */
693 static int
694 cmd_scd (ASSUAN_CONTEXT ctx, char *line)
695 {
696   ctrl_t ctrl = assuan_get_pointer (ctx);
697   int rc;
698
699   rc = divert_generic_cmd (ctrl, line, ctx);
700
701   return map_to_assuan_status (rc);
702 }
703
704
705 \f
706 static int
707 option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
708 {
709   ctrl_t ctrl = assuan_get_pointer (ctx);
710
711   if (!strcmp (key, "display"))
712     {
713       if (ctrl->display)
714         free (ctrl->display);
715       ctrl->display = strdup (value);
716       if (!ctrl->display)
717         return ASSUAN_Out_Of_Core;
718     }
719   else if (!strcmp (key, "ttyname"))
720     {
721       if (!opt.keep_tty)
722         {
723           if (ctrl->ttyname)
724             free (ctrl->ttyname);
725           ctrl->ttyname = strdup (value);
726           if (!ctrl->ttyname)
727             return ASSUAN_Out_Of_Core;
728         }
729     }
730   else if (!strcmp (key, "ttytype"))
731     {
732       if (!opt.keep_tty)
733         {
734           if (ctrl->ttytype)
735             free (ctrl->ttytype);
736           ctrl->ttytype = strdup (value);
737           if (!ctrl->ttytype)
738             return ASSUAN_Out_Of_Core;
739         }
740     }
741   else if (!strcmp (key, "lc-ctype"))
742     {
743       if (ctrl->lc_ctype)
744         free (ctrl->lc_ctype);
745       ctrl->lc_ctype = strdup (value);
746       if (!ctrl->lc_ctype)
747         return ASSUAN_Out_Of_Core;
748     }
749   else if (!strcmp (key, "lc-messages"))
750     {
751       if (ctrl->lc_messages)
752         free (ctrl->lc_messages);
753       ctrl->lc_messages = strdup (value);
754       if (!ctrl->lc_messages)
755         return ASSUAN_Out_Of_Core;
756     }
757   else if (!strcmp (key, "use-cache-for-signing"))
758     ctrl->server_local->use_cache_for_signing = *value? atoi (value) : 0;
759   else
760     return ASSUAN_Invalid_Option;
761
762   return 0;
763 }
764
765 \f
766 /* Tell the assuan library about our commands */
767 static int
768 register_commands (ASSUAN_CONTEXT ctx)
769 {
770   static struct {
771     const char *name;
772     int (*handler)(ASSUAN_CONTEXT, char *line);
773   } table[] = {
774     { "ISTRUSTED",      cmd_istrusted },
775     { "HAVEKEY",        cmd_havekey },
776     { "SIGKEY",         cmd_sigkey },
777     { "SETKEY",         cmd_sigkey },
778     { "SETKEYDESC",     cmd_setkeydesc },
779     { "SETHASH",        cmd_sethash },
780     { "PKSIGN",         cmd_pksign },
781     { "PKDECRYPT",      cmd_pkdecrypt },
782     { "GENKEY",         cmd_genkey },
783     { "GET_PASSPHRASE", cmd_get_passphrase },
784     { "CLEAR_PASSPHRASE", cmd_clear_passphrase },
785     { "GET_CONFIRMATION", cmd_get_confirmation },
786     { "LISTTRUSTED",    cmd_listtrusted },
787     { "MARKTRUSTED",    cmd_marktrusted },
788     { "LEARN",          cmd_learn },
789     { "PASSWD",         cmd_passwd },
790     { "INPUT",          NULL }, 
791     { "OUTPUT",         NULL }, 
792     { "SCD",            cmd_scd },
793     { NULL }
794   };
795   int i, rc;
796
797   for (i=0; table[i].name; i++)
798     {
799       rc = assuan_register_command (ctx, table[i].name, table[i].handler);
800       if (rc)
801         return rc;
802     } 
803   assuan_register_reset_notify (ctx, reset_notify);
804   assuan_register_option_handler (ctx, option_handler);
805   return 0;
806 }
807
808
809 /* Startup the server.  If LISTEN_FD and FD is given as -1, this is a simple
810    piper server, otherwise it is a regular server */
811 void
812 start_command_handler (int listen_fd, int fd)
813 {
814   int rc;
815   ASSUAN_CONTEXT ctx;
816   struct server_control_s ctrl;
817
818   memset (&ctrl, 0, sizeof ctrl);
819   agent_init_default_ctrl (&ctrl);
820   
821   if (listen_fd == -1 && fd == -1)
822     {
823       int filedes[2];
824
825       filedes[0] = 0;
826       filedes[1] = 1;
827       rc = assuan_init_pipe_server (&ctx, filedes);
828     }
829   else if (listen_fd != -1)
830     {
831       rc = assuan_init_socket_server (&ctx, listen_fd);
832     }
833   else 
834     {
835       rc = assuan_init_connected_socket_server (&ctx, fd);
836       ctrl.connection_fd = fd;
837     }
838   if (rc)
839     {
840       log_error ("failed to initialize the server: %s\n",
841                  assuan_strerror(rc));
842       agent_exit (2);
843     }
844   rc = register_commands (ctx);
845   if (rc)
846     {
847       log_error ("failed to register commands with Assuan: %s\n",
848                  assuan_strerror(rc));
849       agent_exit (2);
850     }
851
852   assuan_set_pointer (ctx, &ctrl);
853   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
854   ctrl.server_local->assuan_ctx = ctx;
855   ctrl.server_local->message_fd = -1;
856   ctrl.server_local->use_cache_for_signing = 1;
857   ctrl.digest.raw_value = 0;
858
859   if (DBG_ASSUAN)
860     assuan_set_log_stream (ctx, log_get_stream ());
861
862   for (;;)
863     {
864       rc = assuan_accept (ctx);
865       if (rc == -1)
866         {
867           break;
868         }
869       else if (rc)
870         {
871           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
872           break;
873         }
874       
875       rc = assuan_process (ctx);
876       if (rc)
877         {
878           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
879           continue;
880         }
881     }
882
883   /* Reset the SCD if needed. */
884   agent_reset_scd (&ctrl);
885
886   assuan_deinit_server (ctx);
887   if (ctrl.display)
888     free (ctrl.display);
889   if (ctrl.ttyname)
890     free (ctrl.ttyname);
891   if (ctrl.ttytype)
892     free (ctrl.ttytype);
893   if (ctrl.lc_ctype)
894     free (ctrl.lc_ctype);
895   if (ctrl.lc_messages)
896     free (ctrl.lc_messages);
897 }
898