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