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