* options.h, g10.c, keyedit.c, keylist.c, mainproc.c: Clarify the
[gnupg.git] / scd / command.c
1 /* command.c - SCdaemon command handler
2  *      Copyright (C) 2001, 2002, 2003 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 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <unistd.h>
28 #include <ksba.h>
29
30 #include <assuan.h>
31
32 #include "scdaemon.h"
33 #include "app-common.h"
34
35 /* maximum length aloowed as a PIN; used for INQUIRE NEEDPIN */
36 #define MAXLEN_PIN 100
37
38 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
39
40 /* Data used to associate an Assuan context with local server data */
41 struct server_local_s {
42   ASSUAN_CONTEXT assuan_ctx;
43 };
44
45
46 /* Check whether the option NAME appears in LINE */
47 static int
48 has_option (const char *line, const char *name)
49 {
50   const char *s;
51   int n = strlen (name);
52
53   s = strstr (line, name);
54   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
55 }
56
57
58
59 \f
60 /* Note, that this reset_notify is also used for cleanup purposes. */
61 static void
62 reset_notify (ASSUAN_CONTEXT ctx)
63 {
64   CTRL ctrl = assuan_get_pointer (ctx); 
65
66   if (ctrl->card_ctx)
67     {
68       card_close (ctrl->card_ctx);
69       ctrl->card_ctx = NULL;
70       xfree (ctrl->in_data.value);
71       ctrl->in_data.value = NULL;
72     }
73   if (ctrl->app_ctx)
74     {
75       /* FIXME: close the application. */
76       xfree (ctrl->app_ctx);
77       ctrl->app_ctx = NULL;
78     }
79 }
80
81
82 static int
83 option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
84 {
85   return 0;
86 }
87
88
89 /* If the card has not yet been opened, do it.  Note that this
90    function returns an Assuan error, so don't map the error a second
91    time */
92 static AssuanError
93 open_card (CTRL ctrl)
94 {
95   if (ctrl->app_ctx)
96     return 0; /* Already initialized for one specific application. */
97   if (ctrl->card_ctx)
98     return 0; /* Already initialized using a card context. */
99
100   ctrl->app_ctx = select_application ();
101   if (!ctrl->app_ctx)
102     { /* No application found - fall back to old mode. */
103       int rc = card_open (&ctrl->card_ctx);
104       if (rc)
105         return map_to_assuan_status (rc);
106     }
107   return 0;
108 }
109
110
111 /* Do the percent and plus/space unescaping in place and return tghe
112    length of the valid buffer. */
113 static size_t
114 percent_plus_unescape (unsigned char *string)
115 {
116   unsigned char *p = string;
117   size_t n = 0;
118
119   while (*string)
120     {
121       if (*string == '%' && string[1] && string[2])
122         { 
123           string++;
124           *p++ = xtoi_2 (string);
125           n++;
126           string+= 2;
127         }
128       else if (*string == '+')
129         {
130           *p++ = ' ';
131           n++;
132           string++;
133         }
134       else
135         {
136           *p++ = *string++;
137           n++;
138         }
139     }
140
141   return n;
142 }
143
144
145
146 /* SERIALNO 
147
148    Return the serial number of the card using a status reponse.  This
149    functon should be used to check for the presence of a card.
150
151    This function is special in that it can be used to reset the card.
152    Most other functions will return an error when a card change has
153    been detected and the use of this function is therefore required.
154
155    Background: We want to keep the client clear of handling card
156    changes between operations; i.e. the client can assume that all
157    operations are done on the same card unless he calls this function.
158  */
159 static int
160 cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
161 {
162   CTRL ctrl = assuan_get_pointer (ctx);
163   int rc = 0;
164   char *serial_and_stamp;
165   char *serial;
166   time_t stamp;
167
168   if ((rc = open_card (ctrl)))
169     return rc;
170
171   if (ctrl->app_ctx)
172     rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
173   else
174     rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
175   if (rc)
176     return map_to_assuan_status (rc);
177   rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
178   xfree (serial);
179   if (rc < 0)
180     return ASSUAN_Out_Of_Core;
181   rc = 0;
182   assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
183   free (serial_and_stamp);
184   return 0;
185 }
186
187
188
189
190 /* LEARN [--force]
191
192    Learn all useful information of the currently inserted card.  When
193    used without the force options, the command might do an INQUIRE
194    like this:
195
196       INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
197
198    The client should just send an "END" if the processing should go on
199    or a "CANCEL" to force the function to terminate with a Cancel
200    error message.  The response of this command is a list of status
201    lines formatted as this:
202
203      S APPTYPE <apptype>
204
205    This returns the type of the application, currently the strings:
206
207        P15     = PKCS-15 structure used
208        DINSIG  = DIN SIG
209        OPENPGP = OpenPGP card
210  
211    are implemented.  These strings are aliases for the AID
212
213      S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
214
215    If there is no certificate yet stored on the card a single "X" is
216    returned as the keygrip.  In addition to the keypair info, information
217    about all certificates stored on the card is also returned:
218
219      S CERTINFO <certtype> <hexstring_with_id>
220
221    Where CERTTYPE is a number indicating the type of certificate:
222       0   := Unknown
223       100 := Regular X.509 cert
224       101 := Trusted X.509 cert
225       102 := Useful X.509 cert
226
227    For certain cards, more information will be returned:
228
229      S KEY-FPR <no> <hexstring>
230
231    For OpenPGP cards this returns the stored fingerprints of the
232    keys. This can be used check whether a key is available on the
233    card.  NO may be 1, 2 or 3.
234
235      S CA-FPR <no> <hexstring>
236
237    Similar to above, these are the fingerprints of keys assumed to be
238    ultimately trusted.
239
240      S DISP-NAME <name_of_card_holder>
241
242    The name of the card holder as stored on the card; percent
243    aescaping takes place, spaces are encoded as '+'
244
245      S PUBKEY-URL <url>
246
247    The URL to be used for locating the entire public key.
248      
249 */
250 static int
251 cmd_learn (ASSUAN_CONTEXT ctx, char *line)
252 {
253   CTRL ctrl = assuan_get_pointer (ctx);
254   int rc = 0;
255   int idx;
256
257   if ((rc = open_card (ctrl)))
258     return rc;
259
260   /* Unless the force option is used we try a shortcut by identifying
261      the card using a serial number and inquiring the client with
262      that. The client may choose to cancel the operation if he already
263      knows about this card */
264   {
265     char *serial_and_stamp;
266     char *serial;
267     time_t stamp;
268
269     if (ctrl->app_ctx)
270       rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
271     else
272       rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
273     if (rc)
274       return map_to_assuan_status (rc);
275     rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
276     xfree (serial);
277     if (rc < 0)
278       return ASSUAN_Out_Of_Core;
279     rc = 0;
280     assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
281
282     if (!has_option (line, "--force"))
283       {
284         char *command;
285
286         rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
287         if (rc < 0)
288           {
289             free (serial_and_stamp);
290             return ASSUAN_Out_Of_Core;
291           }
292         rc = 0;
293         rc = assuan_inquire (ctx, command, NULL, NULL, 0); 
294         free (command);  /* (must use standard free here) */
295         if (rc)
296           {
297             if (rc != ASSUAN_Canceled)
298               log_error ("inquire KNOWNCARDP failed: %s\n",
299                          assuan_strerror (rc));
300             free (serial_and_stamp);
301             return rc; 
302           }
303         /* not canceled, so we have to proceeed */
304       }
305     free (serial_and_stamp);
306   }
307
308   /* Return information about the certificates. */
309   if (ctrl->app_ctx)
310     rc = -1; /* This information is not yet available for applications. */
311   for (idx=0; !rc; idx++)
312     {
313       char *certid;
314       int certtype;
315
316       rc = card_enum_certs (ctrl->card_ctx, idx, &certid, &certtype);
317       if (!rc)
318         {
319           char *buf;
320
321           buf = xtrymalloc (40 + 1 + strlen (certid) + 1);
322           if (!buf)
323             rc = out_of_core ();
324           else
325             {
326               sprintf (buf, "%d %s", certtype, certid);
327               assuan_write_status (ctx, "CERTINFO", buf);
328               xfree (buf);
329             }
330         }
331       xfree (certid);
332     }
333   if (rc == -1)
334     rc = 0;
335
336
337   /* Return information about the keys. */
338   if (ctrl->app_ctx)
339     rc = -1; /* This information is not yet available for applications. */
340   for (idx=0; !rc; idx++)
341     {
342       unsigned char keygrip[20];
343       char *keyid;
344       int no_cert = 0;
345
346       rc = card_enum_keypairs (ctrl->card_ctx, idx, keygrip, &keyid);
347       if (gpg_err_code (rc) == GPG_ERR_MISSING_CERT && keyid)
348         {
349           /* this does happen with an incomplete personalized
350              card; i.e. during the time we have stored the key on the
351              card but not stored the certificate; probably becuase it
352              has not yet been received back from the CA.  Note that we
353              must release KEYID in this case. */
354           rc = 0; 
355           no_cert = 1;
356         }
357       if (!rc)
358         {
359           char *buf, *p;
360
361           buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1);
362           if (!buf)
363             rc = out_of_core ();
364           else
365             {
366               int i;
367               
368               if (no_cert)
369                 *p++ = 'X';
370               else
371                 {
372                   for (i=0; i < 20; i++, p += 2)
373                     sprintf (p, "%02X", keygrip[i]);
374                 }
375               *p++ = ' ';
376               strcpy (p, keyid);
377               assuan_write_status (ctx, "KEYPAIRINFO", buf);
378               xfree (buf);
379             }
380         }
381       xfree (keyid);
382     }
383   if (rc == -1)
384     rc = 0;
385
386   if (!rc && ctrl->app_ctx)
387     rc = app_write_learn_status (ctrl->app_ctx, ctrl);
388
389
390   return map_to_assuan_status (rc);
391 }
392
393
394 \f
395 /* READCERT <hexified_certid>
396
397  */
398 static int
399 cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
400 {
401   CTRL ctrl = assuan_get_pointer (ctx);
402   int rc;
403   unsigned char *cert;
404   size_t ncert;
405
406   if ((rc = open_card (ctrl)))
407     return rc;
408
409   if (ctrl->app_ctx)
410     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
411
412   rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
413   if (rc)
414     {
415       log_error ("card_read_cert failed: %s\n", gpg_strerror (rc));
416     }
417   if (!rc)
418     {
419       rc = assuan_send_data (ctx, cert, ncert);
420       xfree (cert);
421       if (rc)
422         return rc;
423     }
424
425   return map_to_assuan_status (rc);
426 }
427
428
429 /* READKEY <hexified_certid>
430
431    Return the public key for the given cert or key ID as an standard
432    S-Expression.  */
433 static int
434 cmd_readkey (ASSUAN_CONTEXT ctx, char *line)
435 {
436   CTRL ctrl = assuan_get_pointer (ctx);
437   int rc;
438   unsigned char *cert = NULL;
439   size_t ncert, n;
440   KsbaCert kc = NULL;
441   KsbaSexp p;
442
443   if ((rc = open_card (ctrl)))
444     return rc;
445
446   if (ctrl->app_ctx)
447     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
448
449   rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
450   if (rc)
451     {
452       log_error ("card_read_cert failed: %s\n", gpg_strerror (rc));
453       goto leave;
454     }
455       
456   kc = ksba_cert_new ();
457   if (!kc)
458     {
459       rc = out_of_core ();
460       xfree (cert);
461       goto leave;
462     }
463   rc = ksba_cert_init_from_mem (kc, cert, ncert);
464   if (rc)
465     {
466       log_error ("failed to parse the certificate: %s\n", ksba_strerror (rc));
467       rc = map_ksba_err (rc);
468       goto leave;
469     }
470
471   p = ksba_cert_get_public_key (kc);
472   if (!p)
473     {
474       rc = gpg_error (GPG_ERR_NO_PUBKEY);
475       goto leave;
476     }
477
478   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
479   rc = assuan_send_data (ctx, p, n);
480   rc = map_assuan_err (rc);
481   xfree (p);
482
483
484  leave:
485   ksba_cert_release (kc);
486   xfree (cert);
487   return map_to_assuan_status (rc);
488 }
489
490
491 \f
492
493 /* SETDATA <hexstring> 
494
495    The client should use this command to tell us the data he want to
496    sign.  */
497 static int
498 cmd_setdata (ASSUAN_CONTEXT ctx, char *line)
499 {
500   CTRL ctrl = assuan_get_pointer (ctx);
501   int n;
502   char *p;
503   unsigned char *buf;
504
505   /* parse the hexstring */
506   for (p=line,n=0; hexdigitp (p); p++, n++)
507     ;
508   if (*p)
509     return set_error (Parameter_Error, "invalid hexstring");
510   if (!n)
511     return set_error (Parameter_Error, "no data given");
512   if ((n&1))
513     return set_error (Parameter_Error, "odd number of digits");
514   n /= 2;
515   buf = xtrymalloc (n);
516   if (!buf)
517     return ASSUAN_Out_Of_Core;
518
519   ctrl->in_data.value = buf;
520   ctrl->in_data.valuelen = n;
521   for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
522     buf[n] = xtoi_2 (p);
523   return 0;
524 }
525
526
527
528 static int 
529 pin_cb (void *opaque, const char *info, char **retstr)
530 {
531   ASSUAN_CONTEXT ctx = opaque;
532   char *command;
533   int rc;
534   char *value;
535   size_t valuelen;
536
537   *retstr = NULL;
538   log_debug ("asking for PIN '%s'\n", info);
539
540   rc = asprintf (&command, "NEEDPIN %s", info);
541   if (rc < 0)
542     return out_of_core ();
543
544   /* FIXME: Write an inquire function which returns the result in
545      secure memory */
546   rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
547   free (command);  
548   if (rc)
549     return map_assuan_err (rc);
550
551   if (!valuelen || value[valuelen-1])
552     {
553       /* We require that the returned value is an UTF-8 string */
554       xfree (value);
555       return gpg_error (GPG_ERR_INV_RESPONSE);
556     }
557   *retstr = value;
558   return 0;
559 }
560
561
562 /* PKSIGN <hexified_id>
563
564  */
565 static int
566 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
567 {
568   CTRL ctrl = assuan_get_pointer (ctx);
569   int rc;
570   unsigned char *outdata;
571   size_t outdatalen;
572   char *keyidstr;
573
574   if ((rc = open_card (ctrl)))
575     return rc;
576
577   /* We have to use a copy of the key ID because the function may use
578      the pin_cb which in turn uses the assuan line buffer and thus
579      overwriting the original line with the keyid */
580   keyidstr = strdup (line);
581   if (!keyidstr)
582     return ASSUAN_Out_Of_Core;
583   
584   if (ctrl->app_ctx)
585     rc = app_sign (ctrl->app_ctx,
586                     keyidstr, GCRY_MD_SHA1,
587                     pin_cb, ctx,
588                     ctrl->in_data.value, ctrl->in_data.valuelen,
589                     &outdata, &outdatalen);
590   else  
591     rc = card_sign (ctrl->card_ctx,
592                     keyidstr, GCRY_MD_SHA1,
593                     pin_cb, ctx,
594                     ctrl->in_data.value, ctrl->in_data.valuelen,
595                     &outdata, &outdatalen);
596   free (keyidstr);
597   if (rc)
598     {
599       log_error ("card_sign failed: %s\n", gpg_strerror (rc));
600     }
601   else
602     {
603       rc = assuan_send_data (ctx, outdata, outdatalen);
604       xfree (outdata);
605       if (rc)
606         return rc; /* that is already an assuan error code */
607     }
608
609   return map_to_assuan_status (rc);
610 }
611
612 /* PKAUTH <hexified_id>
613
614  */
615 static int
616 cmd_pkauth (ASSUAN_CONTEXT ctx, char *line)
617 {
618   CTRL ctrl = assuan_get_pointer (ctx);
619   int rc;
620   unsigned char *outdata;
621   size_t outdatalen;
622   char *keyidstr;
623
624   if ((rc = open_card (ctrl)))
625     return rc;
626
627   if (!ctrl->app_ctx)
628     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
629
630   /* We have to use a copy of the key ID because the function may use
631      the pin_cb which in turn uses the assuan line buffer and thus
632      overwriting the original line with the keyid */
633   keyidstr = strdup (line);
634   if (!keyidstr)
635     return ASSUAN_Out_Of_Core;
636   
637   rc = app_auth (ctrl->app_ctx,
638                  keyidstr,
639                  pin_cb, ctx,
640                  ctrl->in_data.value, ctrl->in_data.valuelen,
641                  &outdata, &outdatalen);
642   free (keyidstr);
643   if (rc)
644     {
645       log_error ("app_auth_sign failed: %s\n", gpg_strerror (rc));
646     }
647   else
648     {
649       rc = assuan_send_data (ctx, outdata, outdatalen);
650       xfree (outdata);
651       if (rc)
652         return rc; /* that is already an assuan error code */
653     }
654
655   return map_to_assuan_status (rc);
656 }
657
658 /* PKDECRYPT <hexified_id>
659
660  */
661 static int
662 cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
663 {
664   CTRL ctrl = assuan_get_pointer (ctx);
665   int rc;
666   unsigned char *outdata;
667   size_t outdatalen;
668   char *keyidstr;
669
670   if ((rc = open_card (ctrl)))
671     return rc;
672
673   keyidstr = strdup (line);
674   if (!keyidstr)
675     return ASSUAN_Out_Of_Core;
676   if (ctrl->app_ctx)
677     rc = app_decipher (ctrl->app_ctx,
678                         keyidstr, 
679                         pin_cb, ctx,
680                         ctrl->in_data.value, ctrl->in_data.valuelen,
681                         &outdata, &outdatalen);
682   else
683     rc = card_decipher (ctrl->card_ctx,
684                         keyidstr, 
685                         pin_cb, ctx,
686                         ctrl->in_data.value, ctrl->in_data.valuelen,
687                         &outdata, &outdatalen);
688   free (keyidstr);
689   if (rc)
690     {
691       log_error ("card_create_signature failed: %s\n", gpg_strerror (rc));
692     }
693   else
694     {
695       rc = assuan_send_data (ctx, outdata, outdatalen);
696       xfree (outdata);
697       if (rc)
698         return rc; /* that is already an assuan error code */
699     }
700
701   return map_to_assuan_status (rc);
702 }
703
704
705 /* SETATTR <name> <value> 
706
707    This command is used to store data on a a smartcard.  The allowed
708    names and values are depend on the currently selected smartcard
709    application.  NAME and VALUE must be percent and '+' escaped.
710
711    However, the curent implementation assumes that Name is not escaped;
712    this works as long as noone uses arbitrary escaping. 
713  
714    A PIN will be requested for most NAMEs.  See the corresponding
715    setattr function of the actually used application (app-*.c) for
716    details.  */
717 static int
718 cmd_setattr (ASSUAN_CONTEXT ctx, char *line)
719 {
720   CTRL ctrl = assuan_get_pointer (ctx);
721   int rc;
722   char *keyword;
723   int keywordlen;
724   size_t nbytes;
725
726   if ((rc = open_card (ctrl)))
727     return rc;
728
729   keyword = line;
730   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
731     ;
732   if (*line)
733       *line++ = 0;
734   while (spacep (line))
735     line++;
736   nbytes = percent_plus_unescape (line);
737
738   rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx, line, nbytes);
739
740   return map_to_assuan_status (rc);
741 }
742
743 /* GENKEY [--force] <no>
744
745    Generate a key on-card identified by NO, which is application
746    specific.  Return values are application specific.  For OpenPGP
747    cards 2 status lines are returned:
748
749      S KEY-FPR  <hexstring>
750      S KEY-CREATED-AT <seconds_since_epoch>
751      S KEY-DATA [p|n] <hexdata>
752      
753
754    --force is required to overwriet an already existing key.  The
755    KEY-CREATED-AT is required for further processing because it is
756    part of the hashed key material for the fingerprint.
757
758    The public part of the key can also later be retrieved using the
759    READKEY command.
760
761  */
762 static int
763 cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
764 {
765   CTRL ctrl = assuan_get_pointer (ctx);
766   int rc;
767   char *keyno;
768   int force = has_option (line, "--force");
769
770   /* Skip over options. */
771   while ( *line == '-' && line[1] == '-' )
772     {
773       while (!spacep (line))
774         line++;
775       while (spacep (line))
776         line++;
777     }
778   if (!*line)
779     return set_error (Parameter_Error, "no key number given");
780   keyno = line;
781   while (!spacep (line))
782     line++;
783   *line = 0;
784
785   if ((rc = open_card (ctrl)))
786     return rc;
787
788   if (!ctrl->app_ctx)
789     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
790
791   rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx);
792
793   return map_to_assuan_status (rc);
794 }
795
796
797 /* RANDOM <nbytes>
798
799    Get NBYTES of random from the card and send them back as data. 
800 */
801 static int
802 cmd_random (ASSUAN_CONTEXT ctx, char *line)
803 {
804   CTRL ctrl = assuan_get_pointer (ctx);
805   int rc;
806   size_t nbytes;
807   unsigned char *buffer;
808
809   if (!*line)
810     return set_error (Parameter_Error, "number of requested bytes missing");
811   nbytes = strtoul (line, NULL, 0);
812
813   if ((rc = open_card (ctrl)))
814     return rc;
815
816   if (!ctrl->app_ctx)
817     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
818
819   buffer = xtrymalloc (nbytes);
820   if (!buffer)
821     return ASSUAN_Out_Of_Core;
822
823   rc = app_get_challenge (ctrl->app_ctx, nbytes, buffer);
824   if (!rc)
825     {
826       rc = assuan_send_data (ctx, buffer, nbytes);
827       xfree (buffer);
828       return rc; /* that is already an assuan error code */
829     }
830   xfree (buffer);
831
832   return map_to_assuan_status (rc);
833 }
834
835 \f
836 /* PASSWD [--reset] <chvno>
837   
838    Change the PIN or reset thye retry counter of the card holder
839    verfication vector CHVNO. */
840 static int
841 cmd_passwd (ASSUAN_CONTEXT ctx, char *line)
842 {
843   CTRL ctrl = assuan_get_pointer (ctx);
844   int rc;
845   char *chvnostr;
846   int reset_mode = has_option (line, "--reset");
847
848   /* Skip over options. */
849   while (*line == '-' && line[1] == '-')
850     {
851       while (!spacep (line))
852         line++;
853       while (spacep (line))
854         line++;
855     }
856   if (!*line)
857     return set_error (Parameter_Error, "no CHV number given");
858   chvnostr = line;
859   while (!spacep (line))
860     line++;
861   *line = 0;
862
863   if ((rc = open_card (ctrl)))
864     return rc;
865
866   if (!ctrl->app_ctx)
867     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
868
869   rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, reset_mode, pin_cb, ctx
870 );
871   if (rc)
872     log_error ("command passwd failed: %s\n", gpg_strerror (rc));
873   return map_to_assuan_status (rc);
874 }
875
876
877
878 \f
879 /* Tell the assuan library about our commands */
880 static int
881 register_commands (ASSUAN_CONTEXT ctx)
882 {
883   static struct {
884     const char *name;
885     int (*handler)(ASSUAN_CONTEXT, char *line);
886   } table[] = {
887     { "SERIALNO",     cmd_serialno },
888     { "LEARN",        cmd_learn },
889     { "READCERT",     cmd_readcert },
890     { "READKEY",      cmd_readkey },
891     { "SETDATA",      cmd_setdata },
892     { "PKSIGN",       cmd_pksign },
893     { "PKAUTH",       cmd_pkauth },
894     { "PKDECRYPT",    cmd_pkdecrypt },
895     { "INPUT",        NULL }, 
896     { "OUTPUT",       NULL }, 
897     { "SETATTR",      cmd_setattr },
898     { "GENKEY",       cmd_genkey },
899     { "RANDOM",       cmd_random },
900     { "PASSWD",       cmd_passwd },
901     { NULL }
902   };
903   int i, rc;
904
905   for (i=0; table[i].name; i++)
906     {
907       rc = assuan_register_command (ctx, table[i].name, table[i].handler);
908       if (rc)
909         return rc;
910     } 
911   assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
912
913   assuan_register_reset_notify (ctx, reset_notify);
914   assuan_register_option_handler (ctx, option_handler);
915   return 0;
916 }
917
918
919 /* Startup the server.  If LISTEN_FD is given as -1, this is simple
920    piper server, otherwise it is a regular server */
921 void
922 scd_command_handler (int listen_fd)
923 {
924   int rc;
925   ASSUAN_CONTEXT ctx;
926   struct server_control_s ctrl;
927
928   memset (&ctrl, 0, sizeof ctrl);
929   scd_init_default_ctrl (&ctrl);
930   
931   if (listen_fd == -1)
932     {
933       int filedes[2];
934
935       filedes[0] = 0;
936       filedes[1] = 1;
937       rc = assuan_init_pipe_server (&ctx, filedes);
938     }
939   else
940     {
941       rc = assuan_init_socket_server (&ctx, listen_fd);
942     }
943   if (rc)
944     {
945       log_error ("failed to initialize the server: %s\n",
946                  assuan_strerror(rc));
947       scd_exit (2);
948     }
949   rc = register_commands (ctx);
950   if (rc)
951     {
952       log_error ("failed to register commands with Assuan: %s\n",
953                  assuan_strerror(rc));
954       scd_exit (2);
955     }
956   assuan_set_pointer (ctx, &ctrl);
957   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
958   ctrl.server_local->assuan_ctx = ctx;
959
960   if (DBG_ASSUAN)
961     assuan_set_log_stream (ctx, log_get_stream ());
962
963   for (;;)
964     {
965       rc = assuan_accept (ctx);
966       if (rc == -1)
967         {
968           break;
969         }
970       else if (rc)
971         {
972           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
973           break;
974         }
975       
976       rc = assuan_process (ctx);
977       if (rc)
978         {
979           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
980           continue;
981         }
982     }
983   reset_notify (ctx); /* used for cleanup */
984
985   assuan_deinit_server (ctx);
986 }
987
988
989 /* Send a line with status information via assuan and escape all given
990    buffers. The variable elements are pairs of (char *, size_t),
991    terminated with a (NULL, 0). */
992 void
993 send_status_info (CTRL ctrl, const char *keyword, ...)
994 {
995   va_list arg_ptr;
996   const unsigned char *value;
997   size_t valuelen;
998   char buf[950], *p;
999   size_t n;
1000   ASSUAN_CONTEXT ctx = ctrl->server_local->assuan_ctx;
1001   
1002   va_start (arg_ptr, keyword);
1003
1004   p = buf; 
1005   n = 0;
1006   while ( (value = va_arg (arg_ptr, const unsigned char *)) )
1007     {
1008       valuelen = va_arg (arg_ptr, size_t);
1009       if (!valuelen)
1010         continue; /* empty buffer */
1011       if (n)
1012         {
1013           *p++ = ' ';
1014           n++;
1015         }
1016       for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
1017         {
1018           if (*value < ' ' || *value == '+')
1019             {
1020               sprintf (p, "%%%02X", *value);
1021               p += 3;
1022             }
1023           else if (*value == ' ')
1024             *p++ = '+';
1025           else
1026             *p++ = *value;
1027         }
1028     }
1029   *p = 0;
1030   assuan_write_status (ctx, keyword, buf);
1031
1032   va_end (arg_ptr);
1033 }
1034