fa1d46ce1bac916357330a97cd6fe0fde7d8f73b
[gnupg.git] / scd / command.c
1 /* command.c - SCdaemon command handler
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005,
3  *               2007, 2008, 2009  Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
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 <signal.h>
29 #ifdef USE_GNU_PTH
30 # include <pth.h>
31 #endif
32
33 #include "scdaemon.h"
34 #include <assuan.h>
35 #include <ksba.h>
36 #include "app-common.h"
37 #include "apdu.h" /* Required for apdu_*_reader (). */
38 #include "exechelp.h"
39 #ifdef HAVE_LIBUSB
40 #include "ccid-driver.h"
41 #endif
42
43 /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
44 #define MAXLEN_PIN 100
45
46 /* Maximum allowed size of key data as used in inquiries. */
47 #define MAXLEN_KEYDATA 4096
48
49 /* Maximum allowed size of certificate data as used in inquiries. */
50 #define MAXLEN_CERTDATA 16384
51
52
53 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
54
55
56 /* Macro to flag a removed card.  ENODEV is also tested to catch teh
57    case of a removed reader.  */
58 #define TEST_CARD_REMOVAL(c,r)                              \
59        do {                                                 \
60           int _r = (r);                                     \
61           if (gpg_err_code (_r) == GPG_ERR_CARD_NOT_PRESENT \
62               || gpg_err_code (_r) == GPG_ERR_CARD_REMOVED  \
63               || gpg_err_code (_r) == GPG_ERR_ENODEV )      \
64             update_card_removed ((c)->reader_slot, 1);      \
65        } while (0)
66
67 #define IS_LOCKED(c)                                                     \
68      (locked_session && locked_session != (c)->server_local              \
69       && (c)->reader_slot != -1 && locked_session->ctrl_backlink         \
70       && (c)->reader_slot == locked_session->ctrl_backlink->reader_slot)
71
72
73 /* This structure is used to keep track of open readers (slots). */
74 struct slot_status_s 
75 {
76   int valid;  /* True if the other objects are valid. */
77   int slot;   /* Slot number of the reader or -1 if not open. */
78
79   int reset_failed; /* A reset failed. */
80
81   int any;    /* Flag indicating whether any status check has been
82                  done.  This is set once to indicate that the status
83                  tracking for the slot has been initialized.  */
84   unsigned int status;  /* Last status of the slot. */
85   unsigned int changed; /* Last change counter of the slot. */
86 };
87
88
89 /* Data used to associate an Assuan context with local server data.
90    This object describes the local properties of one session.  */
91 struct server_local_s 
92 {
93   /* We keep a list of all active sessions with the anchor at
94      SESSION_LIST (see below).  This field is used for linking. */
95   struct server_local_s *next_session; 
96
97   /* This object is usually assigned to a CTRL object (which is
98      globally visible).  While enumerating all sessions we sometimes
99      need to access data of the CTRL object; thus we keep a
100      backpointer here. */
101   ctrl_t ctrl_backlink;
102
103   /* The Assuan context used by this session/server. */
104   assuan_context_t assuan_ctx;
105
106 #ifdef HAVE_W32_SYSTEM
107   unsigned long event_signal;   /* Or 0 if not used. */
108 #else
109   int event_signal;             /* Or 0 if not used. */
110 #endif
111   
112   /* True if the card has been removed and a reset is required to
113      continue operation. */
114   int card_removed;        
115
116   /* Flag indicating that the application context needs to be released
117      at the next opportunity.  */
118   int app_ctx_marked_for_release;
119
120   /* A disconnect command has been sent.  */
121   int disconnect_allowed;
122
123   /* If set to true we will be terminate ourself at the end of the
124      this session.  */
125   int stopme;  
126
127 };
128
129
130 /* The table with information on all used slots.  FIXME: This is a
131    different slot number than the one used by the APDU layer, and
132    should be renamed.  */
133 static struct slot_status_s slot_table[10];
134
135
136 /* To keep track of all running sessions, we link all active server
137    contexts and the anchor in this variable.  */
138 static struct server_local_s *session_list;
139
140 /* If a session has been locked we store a link to its server object
141    in this variable. */
142 static struct server_local_s *locked_session;
143
144 /* While doing a reset we need to make sure that the ticker does not
145    call scd_update_reader_status_file while we are using it. */
146 static pth_mutex_t status_file_update_lock;
147
148 \f
149 /*-- Local prototypes --*/
150 static void update_reader_status_file (int set_card_removed_flag);
151
152
153 \f
154
155 /* This function must be called once to initialize this module.  This
156    has to be done before a second thread is spawned.  We can't do the
157    static initialization because Pth emulation code might not be able
158    to do a static init; in particular, it is not possible for W32. */
159 void
160 initialize_module_command (void)
161 {
162   static int initialized;
163
164   if (!initialized)
165     {
166       if (pth_mutex_init (&status_file_update_lock))
167         initialized = 1;
168     }
169 }
170
171
172 /* Update the CARD_REMOVED element of all sessions using the reader
173    given by SLOT to VALUE.  */
174 static void
175 update_card_removed (int slot, int value)
176 {
177   struct server_local_s *sl;
178
179   for (sl=session_list; sl; sl = sl->next_session)
180     if (sl->ctrl_backlink
181         && sl->ctrl_backlink->reader_slot == slot)
182       {
183         sl->card_removed = value;
184       }
185   /* Let the card application layer know about the removal.  */
186   if (value)
187     application_notify_card_reset (slot);
188 }
189
190
191
192 /* Check whether the option NAME appears in LINE.  Returns 1 or 0. */
193 static int
194 has_option (const char *line, const char *name)
195 {
196   const char *s;
197   int n = strlen (name);
198
199   s = strstr (line, name);
200   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
201 }
202
203 /* Same as has_option but does only test for the name of the option
204    and ignores an argument, i.e. with NAME being "--hash" it would
205    return a pointer for "--hash" as well as for "--hash=foo".  If
206    there is no such option NULL is returned.  The pointer returned
207    points right behind the option name, this may be an equal sign, Nul
208    or a space.  */
209 static const char *
210 has_option_name (const char *line, const char *name)
211 {
212   const char *s;
213   int n = strlen (name);
214
215   s = strstr (line, name);
216   return (s && (s == line || spacep (s-1))
217           && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL;
218 }
219
220
221 /* Skip over options.  It is assumed that leading spaces have been
222    removed (this is the case for lines passed to a handler from
223    assuan).  Blanks after the options are also removed. */
224 static char *
225 skip_options (char *line)
226 {
227   while ( *line == '-' && line[1] == '-' )
228     {
229       while (*line && !spacep (line))
230         line++;
231       while (spacep (line))
232         line++;
233     }
234   return line;
235 }
236
237
238
239 /* Convert the STRING into a newly allocated buffer while translating
240    the hex numbers.  Stops at the first invalid character.  Blanks and
241    colons are allowed to separate the hex digits.  Returns NULL on
242    error or a newly malloced buffer and its length in LENGTH.  */
243 static unsigned char *
244 hex_to_buffer (const char *string, size_t *r_length)
245 {
246   unsigned char *buffer;
247   const char *s;
248   size_t n;
249
250   buffer = xtrymalloc (strlen (string)+1);
251   if (!buffer)
252     return NULL;
253   for (s=string, n=0; *s; s++)
254     {
255       if (spacep (s) || *s == ':') 
256         continue;
257       if (hexdigitp (s) && hexdigitp (s+1))
258         {
259           buffer[n++] = xtoi_2 (s);
260           s++;
261         }
262       else
263         break;
264     }
265   *r_length = n;
266   return buffer;
267 }
268
269
270
271 /* Reset the card and free the application context.  With SEND_RESET
272    set to true actually send a RESET to the reader; this is the normal
273    way of calling the function.  */
274 static void
275 do_reset (ctrl_t ctrl, int send_reset)
276 {
277   int slot = ctrl->reader_slot;
278
279   if (!(slot == -1 || (slot >= 0 && slot < DIM(slot_table))))
280     BUG ();
281
282   /* If there is an active application, release it.  Tell all other
283      sessions using the same application to release the
284      application.  */
285   if (ctrl->app_ctx)
286     {
287       release_application (ctrl->app_ctx);
288       ctrl->app_ctx = NULL;
289       if (send_reset)
290         {
291           struct server_local_s *sl;
292           
293           for (sl=session_list; sl; sl = sl->next_session)
294             if (sl->ctrl_backlink
295                 && sl->ctrl_backlink->reader_slot == slot)
296               {
297                 sl->app_ctx_marked_for_release = 1;
298               }
299         }
300     }
301
302   /* If we want a real reset for the card, send the reset APDU and
303      tell the application layer about it.  */
304   if (slot != -1 && send_reset && !IS_LOCKED (ctrl) )
305     {
306       if (apdu_reset (slot)) 
307         {
308           slot_table[slot].reset_failed = 1;
309         }
310       application_notify_card_reset (slot);
311     }
312
313   /* If we hold a lock, unlock now. */
314   if (locked_session && ctrl->server_local == locked_session)
315     {
316       locked_session = NULL;
317       log_info ("implicitly unlocking due to RESET\n");
318     }
319
320   /* Reset the card removed flag for the current reader.  We need to
321      take the lock here so that the ticker thread won't concurrently
322      try to update the file.  Calling update_reader_status_file is
323      required to get hold of the new status of the card in the slot
324      table.  */
325   if (!pth_mutex_acquire (&status_file_update_lock, 0, NULL))
326     {
327       log_error ("failed to acquire status_fle_update lock\n");
328       ctrl->reader_slot = -1;
329       return;
330     }
331   update_reader_status_file (0);  /* Update slot status table.  */
332   update_card_removed (slot, 0);  /* Clear card_removed flag.  */
333   if (!pth_mutex_release (&status_file_update_lock))
334     log_error ("failed to release status_file_update lock\n");
335
336   /* Do this last, so that the update_card_removed above does its job.  */
337   ctrl->reader_slot = -1;
338 }
339
340 \f
341 static gpg_error_t
342 reset_notify (assuan_context_t ctx, char *line)
343 {
344   ctrl_t ctrl = assuan_get_pointer (ctx); 
345
346   (void) line;
347
348   do_reset (ctrl, 1);
349   return 0;
350 }
351
352
353 static gpg_error_t
354 option_handler (assuan_context_t ctx, const char *key, const char *value)
355 {
356   ctrl_t ctrl = assuan_get_pointer (ctx);
357
358   if (!strcmp (key, "event-signal"))
359     {
360       /* A value of 0 is allowed to reset the event signal. */
361 #ifdef HAVE_W32_SYSTEM
362       if (!*value)
363         return gpg_error (GPG_ERR_ASS_PARAMETER);
364       ctrl->server_local->event_signal = strtoul (value, NULL, 16);
365 #else
366       int i = *value? atoi (value) : -1;
367       if (i < 0)
368         return gpg_error (GPG_ERR_ASS_PARAMETER);
369       ctrl->server_local->event_signal = i;
370 #endif
371     }
372
373  return 0;
374 }
375
376
377 /* Return the slot of the current reader or open the reader if no
378    other sessions are using a reader.  Note, that we currently support
379    only one reader but most of the code (except for this function)
380    should be able to cope with several readers.  */
381 static int
382 get_reader_slot (void)
383 {
384   struct slot_status_s *ss;
385
386   ss = &slot_table[0]; /* One reader for now. */
387
388   /* Initialize the item if needed. */
389   if (!ss->valid)
390     {
391       ss->slot = -1;
392       ss->valid = 1;
393     }
394
395   /* Try to open the reader. */
396   if (ss->slot == -1)
397     ss->slot = apdu_open_reader (opt.reader_port);
398
399   /* Return the slot_table index.  */
400   return 0;
401 }
402
403 /* If the card has not yet been opened, do it.  Note that this
404    function returns an Assuan error, so don't map the error a second
405    time.  */
406 static gpg_error_t
407 open_card (ctrl_t ctrl, const char *apptype)
408 {
409   gpg_error_t err;
410   int slot;
411
412   /* If we ever got a card not present error code, return that.  Only
413      the SERIALNO command and a reset are able to clear from that
414      state. */
415   if (ctrl->server_local->card_removed)
416     return gpg_error (GPG_ERR_CARD_REMOVED);
417
418   if ( IS_LOCKED (ctrl) )
419     return gpg_error (GPG_ERR_LOCKED);
420
421   /* If the application has been marked for release do it now.  We
422      can't do it immediately in do_reset because the application may
423      still be in use.  */
424   if (ctrl->server_local->app_ctx_marked_for_release)
425     {
426       ctrl->server_local->app_ctx_marked_for_release = 0;
427       release_application (ctrl->app_ctx);
428       ctrl->app_ctx = NULL;
429     }
430
431   /* If we are already initialized for one specific application we
432      need to check that the client didn't requested a specific
433      application different from the one in use before we continue. */
434   if (ctrl->app_ctx)
435     return check_application_conflict (ctrl, apptype);
436
437   /* Setup the slot and select the application.  */
438   if (ctrl->reader_slot != -1)
439     slot = ctrl->reader_slot;
440   else
441     slot = get_reader_slot ();
442   ctrl->reader_slot = slot;
443   if (slot == -1)
444     err = gpg_error (GPG_ERR_CARD);
445   else
446     {
447       /* Fixme: We should move the apdu_connect call to
448          select_application.  */
449       int sw;
450
451       ctrl->server_local->disconnect_allowed = 0;
452       sw = apdu_connect (slot);
453       if (sw && sw != SW_HOST_ALREADY_CONNECTED)
454         {
455           if (sw == SW_HOST_NO_CARD)
456             err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
457           else
458             err = gpg_error (GPG_ERR_CARD);
459         }
460       else
461         err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
462     }
463
464   TEST_CARD_REMOVAL (ctrl, err);
465   return err;
466 }
467
468
469 static const char hlp_serialno[] = 
470   "SERIALNO [<apptype>]\n"
471   "\n"
472   "Return the serial number of the card using a status reponse.  This\n"
473   "function should be used to check for the presence of a card.\n"
474   "\n"
475   "If APPTYPE is given, an application of that type is selected and an\n"
476   "error is returned if the application is not supported or available.\n"
477   "The default is to auto-select the application using a hardwired\n"
478   "preference system.  Note, that a future extension to this function\n"
479   "may allow to specify a list and order of applications to try.\n"
480   "\n"
481   "This function is special in that it can be used to reset the card.\n"
482   "Most other functions will return an error when a card change has\n"
483   "been detected and the use of this function is therefore required.\n"
484   "\n"
485   "Background: We want to keep the client clear of handling card\n"
486   "changes between operations; i.e. the client can assume that all\n"
487   "operations are done on the same card unless he calls this function.";
488 static gpg_error_t
489 cmd_serialno (assuan_context_t ctx, char *line)
490 {
491   ctrl_t ctrl = assuan_get_pointer (ctx);
492   int rc = 0;
493   char *serial_and_stamp;
494   char *serial;
495   time_t stamp;
496
497   /* Clear the remove flag so that the open_card is able to reread it.  */
498   if (ctrl->server_local->card_removed)
499     {
500       if ( IS_LOCKED (ctrl) )
501         return gpg_error (GPG_ERR_LOCKED);
502       do_reset (ctrl, 1);
503     }
504
505   if ((rc = open_card (ctrl, *line? line:NULL)))
506     return rc;
507
508   rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
509   if (rc)
510     return rc;
511
512   rc = estream_asprintf (&serial_and_stamp, "%s %lu",
513                          serial, (unsigned long)stamp);
514   xfree (serial);
515   if (rc < 0)
516     return out_of_core ();
517   rc = 0;
518   assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
519   xfree (serial_and_stamp);
520   return 0;
521 }
522
523
524 static const char hlp_learn[] = 
525   "LEARN [--force] [--keypairinfo]\n"
526   "\n"
527   "Learn all useful information of the currently inserted card.  When\n"
528   "used without the force options, the command might do an INQUIRE\n"
529   "like this:\n"
530   "\n"
531   "   INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>\n"
532   "\n"
533   "The client should just send an \"END\" if the processing should go on\n"
534   "or a \"CANCEL\" to force the function to terminate with a Cancel\n"
535   "error message.\n"
536   "\n"
537   "With the option --keypairinfo only KEYPARIINFO lstatus lines are\n"
538   "returned.\n"
539   "\n"
540   "The response of this command is a list of status lines formatted as\n"
541   "this:\n"
542   "\n"
543   "  S APPTYPE <apptype>\n"
544   "\n"
545   "This returns the type of the application, currently the strings:\n"
546   "\n"
547   "    P15     = PKCS-15 structure used\n"
548   "    DINSIG  = DIN SIG\n"
549   "    OPENPGP = OpenPGP card\n"
550   "    NKS     = NetKey card\n"
551   "\n"
552   "are implemented.  These strings are aliases for the AID\n"
553   "\n"
554   "  S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>\n"
555   "\n"
556   "If there is no certificate yet stored on the card a single 'X' is\n"
557   "returned as the keygrip.  In addition to the keypair info, information\n"
558   "about all certificates stored on the card is also returned:\n"
559   "\n"
560   "  S CERTINFO <certtype> <hexstring_with_id>\n"
561   "\n"
562   "Where CERTTYPE is a number indicating the type of certificate:\n"
563   "   0   := Unknown\n"
564   "   100 := Regular X.509 cert\n"
565   "   101 := Trusted X.509 cert\n"
566   "   102 := Useful X.509 cert\n"
567   "   110 := Root CA cert in a special format (e.g. DINSIG)\n"
568   "   111 := Root CA cert as standard X509 cert.\n"
569   "\n"
570   "For certain cards, more information will be returned:\n"
571   "\n"
572   "  S KEY-FPR <no> <hexstring>\n"
573   "\n"
574   "For OpenPGP cards this returns the stored fingerprints of the\n"
575   "keys. This can be used check whether a key is available on the\n"
576   "card.  NO may be 1, 2 or 3.\n"
577   "\n"
578   "  S CA-FPR <no> <hexstring>\n"
579   "\n"
580   "Similar to above, these are the fingerprints of keys assumed to be\n"
581   "ultimately trusted.\n"
582   "\n"
583   "  S DISP-NAME <name_of_card_holder>\n"
584   "\n"
585   "The name of the card holder as stored on the card; percent\n"
586   "escaping takes place, spaces are encoded as '+'\n"
587   "\n"
588   "  S PUBKEY-URL <url>\n"
589   "\n"
590   "The URL to be used for locating the entire public key.\n"
591   "  \n"
592   "Note, that this function may even be used on a locked card.";
593 static gpg_error_t
594 cmd_learn (assuan_context_t ctx, char *line)
595 {
596   ctrl_t ctrl = assuan_get_pointer (ctx);
597   int rc = 0;
598   int only_keypairinfo = has_option (line, "--keypairinfo");
599
600   if ((rc = open_card (ctrl, NULL)))
601     return rc;
602
603   /* Unless the force option is used we try a shortcut by identifying
604      the card using a serial number and inquiring the client with
605      that. The client may choose to cancel the operation if he already
606      knows about this card */
607   if (!only_keypairinfo)
608     {
609       char *serial_and_stamp;
610       char *serial;
611       time_t stamp;
612       
613       rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
614       if (rc)
615         return rc;
616       rc = estream_asprintf (&serial_and_stamp, "%s %lu",
617                              serial, (unsigned long)stamp);
618       xfree (serial);
619       if (rc < 0)
620         return out_of_core ();
621       rc = 0;
622       assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
623       
624       if (!has_option (line, "--force"))
625         {
626           char *command;
627           
628           rc = estream_asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
629           if (rc < 0)
630             {
631               xfree (serial_and_stamp);
632               return out_of_core ();
633             }
634           rc = 0;
635           rc = assuan_inquire (ctx, command, NULL, NULL, 0); 
636           xfree (command);
637           if (rc)
638             {
639               if (gpg_err_code (rc) != GPG_ERR_ASS_CANCELED)
640                 log_error ("inquire KNOWNCARDP failed: %s\n",
641                            gpg_strerror (rc));
642               xfree (serial_and_stamp);
643               return rc; 
644             }
645           /* Not canceled, so we have to proceeed.  */
646         }
647       xfree (serial_and_stamp);
648     }
649   
650   /* Let the application print out its collection of useful status
651      information. */
652   if (!rc)
653     rc = app_write_learn_status (ctrl->app_ctx, ctrl, only_keypairinfo);
654
655   TEST_CARD_REMOVAL (ctrl, rc);
656   return rc;
657 }
658
659
660 \f
661 static const char hlp_readcert[] =
662   "READCERT <hexified_certid>|<keyid>\n"
663   "\n"
664   "Note, that this function may even be used on a locked card.";
665 static gpg_error_t
666 cmd_readcert (assuan_context_t ctx, char *line)
667 {
668   ctrl_t ctrl = assuan_get_pointer (ctx);
669   int rc;
670   unsigned char *cert;
671   size_t ncert;
672
673   if ((rc = open_card (ctrl, NULL)))
674     return rc;
675
676   line = xstrdup (line); /* Need a copy of the line. */
677   rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
678   if (rc)
679     log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
680   xfree (line);
681   line = NULL;
682   if (!rc)
683     {
684       rc = assuan_send_data (ctx, cert, ncert);
685       xfree (cert);
686       if (rc)
687         return rc;
688     }
689
690   TEST_CARD_REMOVAL (ctrl, rc);
691   return rc;
692 }
693
694
695 static const char hlp_readkey[] = 
696   "READKEY <keyid>\n"
697   "\n"
698   "Return the public key for the given cert or key ID as a standard\n"
699   "S-expression.\n"
700   "\n"
701   "Note, that this function may even be used on a locked card.";
702 static gpg_error_t
703 cmd_readkey (assuan_context_t ctx, char *line)
704 {
705   ctrl_t ctrl = assuan_get_pointer (ctx);
706   int rc;
707   unsigned char *cert = NULL;
708   size_t ncert, n;
709   ksba_cert_t kc = NULL;
710   ksba_sexp_t p;
711   unsigned char *pk;
712   size_t pklen;
713
714   if ((rc = open_card (ctrl, NULL)))
715     return rc;
716
717   line = xstrdup (line); /* Need a copy of the line. */
718   /* If the application supports the READKEY function we use that.
719      Otherwise we use the old way by extracting it from the
720      certificate.  */
721   rc = app_readkey (ctrl->app_ctx, line, &pk, &pklen);
722   if (!rc)
723     { /* Yeah, got that key - send it back.  */
724       rc = assuan_send_data (ctx, pk, pklen);
725       xfree (pk);
726       xfree (line);
727       line = NULL;
728       goto leave;
729     }
730
731   if (gpg_err_code (rc) != GPG_ERR_UNSUPPORTED_OPERATION)
732     log_error ("app_readkey failed: %s\n", gpg_strerror (rc));
733   else  
734     {
735       rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
736       if (rc)
737         log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
738     }
739   xfree (line);
740   line = NULL;
741   if (rc)
742     goto leave;
743       
744   rc = ksba_cert_new (&kc);
745   if (rc)
746     {
747       xfree (cert);
748       goto leave;
749     }
750   rc = ksba_cert_init_from_mem (kc, cert, ncert);
751   if (rc)
752     {
753       log_error ("failed to parse the certificate: %s\n", gpg_strerror (rc));
754       goto leave;
755     }
756
757   p = ksba_cert_get_public_key (kc);
758   if (!p)
759     {
760       rc = gpg_error (GPG_ERR_NO_PUBKEY);
761       goto leave;
762     }
763
764   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
765   rc = assuan_send_data (ctx, p, n);
766   xfree (p);
767
768
769  leave:
770   ksba_cert_release (kc);
771   xfree (cert);
772   TEST_CARD_REMOVAL (ctrl, rc);
773   return rc;
774 }
775
776
777 \f
778 static const char hlp_setdata[] = 
779   "SETDATA <hexstring> \n"
780   "\n"
781   "The client should use this command to tell us the data he want to sign.";
782 static gpg_error_t
783 cmd_setdata (assuan_context_t ctx, char *line)
784 {
785   ctrl_t ctrl = assuan_get_pointer (ctx);
786   int n;
787   char *p;
788   unsigned char *buf;
789
790   if (locked_session && locked_session != ctrl->server_local)
791     return gpg_error (GPG_ERR_LOCKED);
792
793   /* Parse the hexstring. */
794   for (p=line,n=0; hexdigitp (p); p++, n++)
795     ;
796   if (*p)
797     return set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
798   if (!n)
799     return set_error (GPG_ERR_ASS_PARAMETER, "no data given");
800   if ((n&1))
801     return set_error (GPG_ERR_ASS_PARAMETER, "odd number of digits");
802   n /= 2;
803   buf = xtrymalloc (n);
804   if (!buf)
805     return out_of_core ();
806
807   xfree (ctrl->in_data.value);
808   ctrl->in_data.value = buf;
809   ctrl->in_data.valuelen = n;
810   for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
811     buf[n] = xtoi_2 (p);
812   return 0;
813 }
814
815
816
817 static gpg_error_t 
818 pin_cb (void *opaque, const char *info, char **retstr)
819 {
820   assuan_context_t ctx = opaque;
821   char *command;
822   int rc;
823   unsigned char *value;
824   size_t valuelen;
825
826   if (!retstr)
827     {
828       /* We prompt for keypad entry.  To make sure that the popup has
829          been show we use an inquire and not just a status message.
830          We ignore any value returned.  */
831       if (info)
832         {
833           log_debug ("prompting for keypad entry '%s'\n", info);
834           rc = estream_asprintf (&command, "POPUPKEYPADPROMPT %s", info);
835           if (rc < 0)
836             return gpg_error (gpg_err_code_from_errno (errno));
837           rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
838           xfree (command);  
839         }
840       else
841         {
842           log_debug ("dismiss keypad entry prompt\n");
843           rc = assuan_inquire (ctx, "DISMISSKEYPADPROMPT",
844                                &value, &valuelen, MAXLEN_PIN); 
845         }
846       if (!rc)
847         xfree (value);
848       return rc;
849     }
850
851   *retstr = NULL;
852   log_debug ("asking for PIN '%s'\n", info);
853
854   rc = estream_asprintf (&command, "NEEDPIN %s", info);
855   if (rc < 0)
856     return gpg_error (gpg_err_code_from_errno (errno));
857
858   /* Fixme: Write an inquire function which returns the result in
859      secure memory and check all further handling of the PIN. */
860   rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
861   xfree (command);  
862   if (rc)
863     return rc;
864
865   if (!valuelen || value[valuelen-1])
866     {
867       /* We require that the returned value is an UTF-8 string */
868       xfree (value);
869       return gpg_error (GPG_ERR_INV_RESPONSE);
870     }
871   *retstr = (char*)value;
872   return 0;
873 }
874
875
876 static const char hlp_pksign[] = 
877   "PKSIGN [--hash=[rmd160|sha{1,224,256,384,512}|md5]] <hexified_id>\n"
878   "\n"
879   "The --hash option is optional; the default is SHA1.";
880 static gpg_error_t
881 cmd_pksign (assuan_context_t ctx, char *line)
882 {
883   ctrl_t ctrl = assuan_get_pointer (ctx);
884   int rc;
885   unsigned char *outdata;
886   size_t outdatalen;
887   char *keyidstr;
888   int hash_algo;
889
890   if (has_option (line, "--hash=rmd160"))
891     hash_algo = GCRY_MD_RMD160;
892   else if (has_option (line, "--hash=sha1"))
893     hash_algo = GCRY_MD_SHA1;
894   else if (has_option (line, "--hash=sha224"))
895     hash_algo = GCRY_MD_SHA224;
896   else if (has_option (line, "--hash=sha256"))
897     hash_algo = GCRY_MD_SHA256;
898   else if (has_option (line, "--hash=sha384"))
899     hash_algo = GCRY_MD_SHA384;
900   else if (has_option (line, "--hash=sha512"))
901     hash_algo = GCRY_MD_SHA512;
902   else if (has_option (line, "--hash=md5"))
903     hash_algo = GCRY_MD_MD5;
904   else if (!strstr (line, "--"))
905     hash_algo = GCRY_MD_SHA1; 
906   else
907     return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
908
909   line = skip_options (line);
910
911   if ( IS_LOCKED (ctrl) )
912     return gpg_error (GPG_ERR_LOCKED);
913
914   if ((rc = open_card (ctrl, NULL)))
915     return rc;
916
917   /* We have to use a copy of the key ID because the function may use
918      the pin_cb which in turn uses the assuan line buffer and thus
919      overwriting the original line with the keyid */
920   keyidstr = xtrystrdup (line);
921   if (!keyidstr)
922     return out_of_core ();
923   
924   rc = app_sign (ctrl->app_ctx,
925                  keyidstr, hash_algo,
926                  pin_cb, ctx,
927                  ctrl->in_data.value, ctrl->in_data.valuelen,
928                  &outdata, &outdatalen);
929
930   xfree (keyidstr);
931   if (rc)
932     {
933       log_error ("app_sign failed: %s\n", gpg_strerror (rc));
934     }
935   else
936     {
937       rc = assuan_send_data (ctx, outdata, outdatalen);
938       xfree (outdata);
939       if (rc)
940         return rc; /* that is already an assuan error code */
941     }
942
943   TEST_CARD_REMOVAL (ctrl, rc);
944   return rc;
945 }
946
947
948 static const char hlp_pkauth[] = 
949   "PKAUTH <hexified_id>";
950 static gpg_error_t
951 cmd_pkauth (assuan_context_t ctx, char *line)
952 {
953   ctrl_t ctrl = assuan_get_pointer (ctx);
954   int rc;
955   unsigned char *outdata;
956   size_t outdatalen;
957   char *keyidstr;
958
959   if ( IS_LOCKED (ctrl) )
960     return gpg_error (GPG_ERR_LOCKED);
961
962   if ((rc = open_card (ctrl, NULL)))
963     return rc;
964
965   if (!ctrl->app_ctx)
966     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
967
968  /* We have to use a copy of the key ID because the function may use
969      the pin_cb which in turn uses the assuan line buffer and thus
970      overwriting the original line with the keyid */
971   keyidstr = xtrystrdup (line);
972   if (!keyidstr)
973     return out_of_core ();
974   
975   rc = app_auth (ctrl->app_ctx,
976                  keyidstr,
977                  pin_cb, ctx,
978                  ctrl->in_data.value, ctrl->in_data.valuelen,
979                  &outdata, &outdatalen);
980   xfree (keyidstr);
981   if (rc)
982     {
983       log_error ("app_auth failed: %s\n", gpg_strerror (rc));
984     }
985   else
986     {
987       rc = assuan_send_data (ctx, outdata, outdatalen);
988       xfree (outdata);
989       if (rc)
990         return rc; /* that is already an assuan error code */
991     }
992
993   TEST_CARD_REMOVAL (ctrl, rc);
994   return rc;
995 }
996
997
998 static const char hlp_pkdecrypt[] = 
999   "PKDECRYPT <hexified_id>";
1000 static gpg_error_t
1001 cmd_pkdecrypt (assuan_context_t ctx, char *line)
1002 {
1003   ctrl_t ctrl = assuan_get_pointer (ctx);
1004   int rc;
1005   unsigned char *outdata;
1006   size_t outdatalen;
1007   char *keyidstr;
1008
1009   if ( IS_LOCKED (ctrl) )
1010     return gpg_error (GPG_ERR_LOCKED);
1011
1012   if ((rc = open_card (ctrl, NULL)))
1013     return rc;
1014
1015   keyidstr = xtrystrdup (line);
1016   if (!keyidstr)
1017     return out_of_core ();
1018   rc = app_decipher (ctrl->app_ctx,
1019                      keyidstr, 
1020                      pin_cb, ctx,
1021                      ctrl->in_data.value, ctrl->in_data.valuelen,
1022                      &outdata, &outdatalen);
1023
1024   xfree (keyidstr);
1025   if (rc)
1026     {
1027       log_error ("app_decipher failed: %s\n", gpg_strerror (rc));
1028     }
1029   else
1030     {
1031       rc = assuan_send_data (ctx, outdata, outdatalen);
1032       xfree (outdata);
1033       if (rc)
1034         return rc; /* that is already an assuan error code */
1035     }
1036
1037   TEST_CARD_REMOVAL (ctrl, rc);
1038   return rc;
1039 }
1040
1041
1042 static const char hlp_getattr[] = 
1043   "GETATTR <name>\n"
1044   "\n"
1045   "This command is used to retrieve data from a smartcard.  The\n"
1046   "allowed names depend on the currently selected smartcard\n"
1047   "application.  NAME must be percent and '+' escaped.  The value is\n"
1048   "returned through status message, see the LEARN command for details.\n"
1049   "\n"
1050   "However, the current implementation assumes that Name is not escaped;\n"
1051   "this works as long as noone uses arbitrary escaping. \n"
1052   "\n"
1053   "Note, that this function may even be used on a locked card.";
1054 static gpg_error_t
1055 cmd_getattr (assuan_context_t ctx, char *line)
1056 {
1057   ctrl_t ctrl = assuan_get_pointer (ctx);
1058   int rc;
1059   const char *keyword;
1060
1061   if ((rc = open_card (ctrl, NULL)))
1062     return rc;
1063
1064   keyword = line;
1065   for (; *line && !spacep (line); line++)
1066     ;
1067   if (*line)
1068       *line++ = 0;
1069
1070   /* (We ignore any garbage for now.) */
1071
1072   /* FIXME: Applications should not return sensitive data if the card
1073      is locked.  */
1074   rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
1075
1076   TEST_CARD_REMOVAL (ctrl, rc);
1077   return rc;
1078 }
1079
1080
1081 static const char hlp_setattr[] = 
1082   "SETATTR <name> <value> \n"
1083   "\n"
1084   "This command is used to store data on a a smartcard.  The allowed\n"
1085   "names and values are depend on the currently selected smartcard\n"
1086   "application.  NAME and VALUE must be percent and '+' escaped.\n"
1087   "\n"
1088   "However, the current implementation assumes that NAME is not\n"
1089   "escaped; this works as long as noone uses arbitrary escaping.\n"
1090   "\n"
1091   "A PIN will be requested for most NAMEs.  See the corresponding\n"
1092   "setattr function of the actually used application (app-*.c) for\n"
1093   "details.";
1094 static gpg_error_t
1095 cmd_setattr (assuan_context_t ctx, char *orig_line)
1096 {
1097   ctrl_t ctrl = assuan_get_pointer (ctx);
1098   int rc;
1099   char *keyword;
1100   int keywordlen;
1101   size_t nbytes;
1102   char *line, *linebuf;
1103
1104   if ( IS_LOCKED (ctrl) )
1105     return gpg_error (GPG_ERR_LOCKED);
1106
1107   if ((rc = open_card (ctrl, NULL)))
1108     return rc;
1109
1110   /* We need to use a copy of LINE, because PIN_CB uses the same
1111      context and thus reuses the Assuan provided LINE. */
1112   line = linebuf = xtrystrdup (orig_line);
1113   if (!line)
1114     return out_of_core ();
1115
1116   keyword = line;
1117   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
1118     ;
1119   if (*line)
1120       *line++ = 0;
1121   while (spacep (line))
1122     line++;
1123   nbytes = percent_plus_unescape_inplace (line, 0);
1124
1125   rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx,
1126                     (const unsigned char*)line, nbytes);
1127   xfree (linebuf);
1128
1129   TEST_CARD_REMOVAL (ctrl, rc);
1130   return rc;
1131 }
1132
1133
1134 static const char hlp_writecert[] = 
1135   "WRITECERT <hexified_certid>\n"
1136   "\n"
1137   "This command is used to store a certifciate on a smartcard.  The\n"
1138   "allowed certids depend on the currently selected smartcard\n"
1139   "application. The actual certifciate is requested using the inquiry\n"
1140   "\"CERTDATA\" and needs to be provided in its raw (e.g. DER) form.\n"
1141   "\n"
1142   "In almost all cases a a PIN will be requested.  See the related\n"
1143   "writecert function of the actually used application (app-*.c) for\n"
1144   "details.";
1145 static gpg_error_t
1146 cmd_writecert (assuan_context_t ctx, char *line)
1147 {
1148   ctrl_t ctrl = assuan_get_pointer (ctx);
1149   int rc;
1150   char *certid;
1151   unsigned char *certdata;
1152   size_t certdatalen;
1153
1154   if ( IS_LOCKED (ctrl) )
1155     return gpg_error (GPG_ERR_LOCKED);
1156
1157   line = skip_options (line);
1158
1159   if (!*line)
1160     return set_error (GPG_ERR_ASS_PARAMETER, "no certid given");
1161   certid = line;
1162   while (*line && !spacep (line))
1163     line++;
1164   *line = 0;
1165
1166   if ((rc = open_card (ctrl, NULL)))
1167     return rc;
1168
1169   if (!ctrl->app_ctx)
1170     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1171
1172   certid = xtrystrdup (certid);
1173   if (!certid)
1174     return out_of_core ();
1175
1176   /* Now get the actual keydata. */
1177   rc = assuan_inquire (ctx, "CERTDATA",
1178                        &certdata, &certdatalen, MAXLEN_CERTDATA);
1179   if (rc)
1180     {
1181       xfree (certid);
1182       return rc;
1183     }
1184
1185   /* Write the certificate to the card. */
1186   rc = app_writecert (ctrl->app_ctx, ctrl, certid, 
1187                       pin_cb, ctx, certdata, certdatalen);
1188   xfree (certid);
1189   xfree (certdata);
1190
1191   TEST_CARD_REMOVAL (ctrl, rc);
1192   return rc;
1193 }
1194
1195
1196 static const char hlp_writekey[] = 
1197   "WRITEKEY [--force] <keyid> \n"
1198   "\n"
1199   "This command is used to store a secret key on a a smartcard.  The\n"
1200   "allowed keyids depend on the currently selected smartcard\n"
1201   "application. The actual keydata is requested using the inquiry\n"
1202   "\"KEYDATA\" and need to be provided without any protection.  With\n"
1203   "--force set an existing key under this KEYID will get overwritten.\n"
1204   "The keydata is expected to be the usual canonical encoded\n"
1205   "S-expression.\n"
1206   "\n"
1207   "A PIN will be requested for most NAMEs.  See the corresponding\n"
1208   "writekey function of the actually used application (app-*.c) for\n"
1209   "details.";
1210 static gpg_error_t
1211 cmd_writekey (assuan_context_t ctx, char *line)
1212 {
1213   ctrl_t ctrl = assuan_get_pointer (ctx);
1214   int rc;
1215   char *keyid;
1216   int force = has_option (line, "--force");
1217   unsigned char *keydata;
1218   size_t keydatalen;
1219
1220   if ( IS_LOCKED (ctrl) )
1221     return gpg_error (GPG_ERR_LOCKED);
1222
1223   line = skip_options (line);
1224
1225   if (!*line)
1226     return set_error (GPG_ERR_ASS_PARAMETER, "no keyid given");
1227   keyid = line;
1228   while (*line && !spacep (line))
1229     line++;
1230   *line = 0;
1231
1232   if ((rc = open_card (ctrl, NULL)))
1233     return rc;
1234
1235   if (!ctrl->app_ctx)
1236     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1237
1238   keyid = xtrystrdup (keyid);
1239   if (!keyid)
1240     return out_of_core ();
1241
1242   /* Now get the actual keydata. */
1243   assuan_begin_confidential (ctx);
1244   rc = assuan_inquire (ctx, "KEYDATA", &keydata, &keydatalen, MAXLEN_KEYDATA);
1245   assuan_end_confidential (ctx);
1246   if (rc)
1247     {
1248       xfree (keyid);
1249       return rc;
1250     }
1251
1252   /* Write the key to the card. */
1253   rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0,
1254                      pin_cb, ctx, keydata, keydatalen);
1255   xfree (keyid);
1256   xfree (keydata);
1257
1258   TEST_CARD_REMOVAL (ctrl, rc);
1259   return rc;
1260 }
1261
1262
1263 static const char hlp_genkey[] = 
1264   "GENKEY [--force] [--timestamp=<isodate>] <no>\n"
1265   "\n"
1266   "Generate a key on-card identified by NO, which is application\n"
1267   "specific.  Return values are application specific.  For OpenPGP\n"
1268   "cards 2 status lines are returned:\n"
1269   "\n"
1270   "  S KEY-FPR  <hexstring>\n"
1271   "  S KEY-CREATED-AT <seconds_since_epoch>\n"
1272   "  S KEY-DATA [p|n] <hexdata>\n"
1273   "\n"
1274   "--force is required to overwrite an already existing key.  The\n"
1275   "KEY-CREATED-AT is required for further processing because it is\n"
1276   "part of the hashed key material for the fingerprint.\n"
1277   "\n"
1278   "If --timestamp is given an OpenPGP key will be created using this\n"
1279   "value.  The value needs to be in ISO Format; e.g.\n"
1280   "\"--timestamp=20030316T120000\" and after 1970-01-01 00:00:00.\n"
1281   "\n"
1282   "The public part of the key can also later be retrieved using the\n"
1283   "READKEY command.";
1284 static gpg_error_t
1285 cmd_genkey (assuan_context_t ctx, char *line)
1286 {
1287   ctrl_t ctrl = assuan_get_pointer (ctx);
1288   int rc;
1289   char *keyno;
1290   int force;
1291   const char *s;
1292   time_t timestamp;
1293
1294   if ( IS_LOCKED (ctrl) )
1295     return gpg_error (GPG_ERR_LOCKED);
1296
1297   force = has_option (line, "--force");
1298
1299   if ((s=has_option_name (line, "--timestamp")))
1300     {
1301       if (*s != '=')
1302         return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
1303       timestamp = isotime2epoch (s+1);
1304       if (timestamp < 1)
1305         return set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
1306     }
1307   else
1308     timestamp = 0;
1309
1310
1311   line = skip_options (line);
1312   if (!*line)
1313     return set_error (GPG_ERR_ASS_PARAMETER, "no key number given");
1314   keyno = line;
1315   while (*line && !spacep (line))
1316     line++;
1317   *line = 0;
1318
1319   if ((rc = open_card (ctrl, NULL)))
1320     return rc;
1321
1322   if (!ctrl->app_ctx)
1323     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1324
1325   keyno = xtrystrdup (keyno);
1326   if (!keyno)
1327     return out_of_core ();
1328   rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0,
1329                    timestamp, pin_cb, ctx);
1330   xfree (keyno);
1331
1332   TEST_CARD_REMOVAL (ctrl, rc);
1333   return rc;
1334 }
1335
1336
1337 static const char hlp_random[] = 
1338   "RANDOM <nbytes>\n"
1339   "\n"
1340   "Get NBYTES of random from the card and send them back as data.\n"
1341   "This usually involves EEPROM write on the card and thus excessive\n"
1342   "use of this command may destroy the card.\n"
1343   "\n"
1344   "Note, that this function may be even be used on a locked card.";
1345 static gpg_error_t
1346 cmd_random (assuan_context_t ctx, char *line)
1347 {
1348   ctrl_t ctrl = assuan_get_pointer (ctx);
1349   int rc;
1350   size_t nbytes;
1351   unsigned char *buffer;
1352
1353   if (!*line)
1354     return set_error (GPG_ERR_ASS_PARAMETER, 
1355                       "number of requested bytes missing");
1356   nbytes = strtoul (line, NULL, 0);
1357
1358   if ((rc = open_card (ctrl, NULL)))
1359     return rc;
1360
1361   if (!ctrl->app_ctx)
1362     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1363
1364   buffer = xtrymalloc (nbytes);
1365   if (!buffer)
1366     return out_of_core ();
1367
1368   rc = app_get_challenge (ctrl->app_ctx, nbytes, buffer);
1369   if (!rc)
1370     {
1371       rc = assuan_send_data (ctx, buffer, nbytes);
1372       xfree (buffer);
1373       return rc; /* that is already an assuan error code */
1374     }
1375   xfree (buffer);
1376
1377   TEST_CARD_REMOVAL (ctrl, rc);
1378   return rc;
1379 }
1380
1381
1382 \f
1383 static const char hlp_passwd[] =
1384   "PASSWD [--reset] [--nullpin] <chvno>\n"
1385   "\n"
1386   "Change the PIN or, if --reset is given, reset the retry counter of\n"
1387   "the card holder verfication vector CHVNO.  The option --nullpin is\n"
1388   "used for TCOS cards to set the initial PIN.  The format of CHVNO\n"
1389   "depends on the card application.";
1390 static gpg_error_t
1391 cmd_passwd (assuan_context_t ctx, char *line)
1392 {
1393   ctrl_t ctrl = assuan_get_pointer (ctx);
1394   int rc;
1395   char *chvnostr;
1396   unsigned int flags = 0;
1397
1398   if (has_option (line, "--reset"))
1399     flags |= APP_CHANGE_FLAG_RESET;
1400   if (has_option (line, "--nullpin"))
1401     flags |= APP_CHANGE_FLAG_NULLPIN;
1402
1403   if ( IS_LOCKED (ctrl) )
1404     return gpg_error (GPG_ERR_LOCKED);
1405
1406   line = skip_options (line);
1407
1408   if (!*line)
1409     return set_error (GPG_ERR_ASS_PARAMETER, "no CHV number given");
1410   chvnostr = line;
1411   while (*line && !spacep (line))
1412     line++;
1413   *line = 0;
1414
1415   if ((rc = open_card (ctrl, NULL)))
1416     return rc;
1417
1418   if (!ctrl->app_ctx)
1419     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1420   
1421   chvnostr = xtrystrdup (chvnostr);
1422   if (!chvnostr)
1423     return out_of_core ();
1424   rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
1425   if (rc)
1426     log_error ("command passwd failed: %s\n", gpg_strerror (rc));
1427   xfree (chvnostr);
1428
1429   TEST_CARD_REMOVAL (ctrl, rc);
1430   return rc;
1431 }
1432
1433
1434 static const char hlp_checkpin[] = 
1435   "CHECKPIN <idstr>\n"
1436   "\n"
1437   "Perform a VERIFY operation without doing anything else.  This may\n"
1438   "be used to initialize a the PIN cache earlier to long lasting\n"
1439   "operations.  Its use is highly application dependent.\n"
1440   "\n"
1441   "For OpenPGP:\n"
1442   "\n"
1443   "   Perform a simple verify operation for CHV1 and CHV2, so that\n"
1444   "   further operations won't ask for CHV2 and it is possible to do a\n"
1445   "   cheap check on the PIN: If there is something wrong with the PIN\n"
1446   "   entry system, only the regular CHV will get blocked and not the\n"
1447   "   dangerous CHV3.  IDSTR is the usual card's serial number in hex\n"
1448   "   notation; an optional fingerprint part will get ignored.  There\n"
1449   "   is however a special mode if the IDSTR is sffixed with the\n"
1450   "   literal string \"[CHV3]\": In this case the Admin PIN is checked\n"
1451   "   if and only if the retry counter is still at 3.\n"
1452   "\n"
1453   "For Netkey:\n"
1454   "\n"
1455   "   Any of the valid PIN Ids may be used.  These are the strings:\n"
1456   "\n"
1457   "     PW1.CH       - Global password 1\n"
1458   "     PW2.CH       - Global password 2\n"
1459   "     PW1.CH.SIG   - SigG password 1\n"
1460   "     PW2.CH.SIG   - SigG password 2\n"
1461   "\n"
1462   "   For a definitive list, see the implementation in app-nks.c.\n"
1463   "   Note that we call a PW2.* PIN a \"PUK\" despite that since TCOS\n"
1464   "   3.0 they are technically alternative PINs used to mutally\n"
1465   "   unblock each other.";
1466 static gpg_error_t
1467 cmd_checkpin (assuan_context_t ctx, char *line)
1468 {
1469   ctrl_t ctrl = assuan_get_pointer (ctx);
1470   int rc;
1471   char *idstr;
1472
1473   if ( IS_LOCKED (ctrl) )
1474     return gpg_error (GPG_ERR_LOCKED);
1475
1476   if ((rc = open_card (ctrl, NULL)))
1477     return rc;
1478
1479   if (!ctrl->app_ctx)
1480     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1481
1482   /* We have to use a copy of the key ID because the function may use
1483      the pin_cb which in turn uses the assuan line buffer and thus
1484      overwriting the original line with the keyid. */
1485   idstr = xtrystrdup (line);
1486   if (!idstr)
1487     return out_of_core ();
1488   
1489   rc = app_check_pin (ctrl->app_ctx, idstr, pin_cb, ctx);
1490   xfree (idstr);
1491   if (rc)
1492     log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
1493
1494   TEST_CARD_REMOVAL (ctrl, rc);
1495   return rc;
1496 }
1497
1498
1499 static const char hlp_lock[] = 
1500   "LOCK [--wait]\n"
1501   "\n"
1502   "Grant exclusive card access to this session.  Note that there is\n"
1503   "no lock counter used and a second lock from the same session will\n"
1504   "be ignored.  A single unlock (or RESET) unlocks the session.\n"
1505   "Return GPG_ERR_LOCKED if another session has locked the reader.\n"
1506   "\n"
1507   "If the option --wait is given the command will wait until a\n"
1508   "lock has been released.";
1509 static gpg_error_t
1510 cmd_lock (assuan_context_t ctx, char *line)
1511 {
1512   ctrl_t ctrl = assuan_get_pointer (ctx);
1513   int rc = 0;
1514
1515  retry:
1516   if (locked_session)
1517     {
1518       if (locked_session != ctrl->server_local)
1519         rc = gpg_error (GPG_ERR_LOCKED);
1520     }
1521   else
1522     locked_session = ctrl->server_local;
1523
1524 #ifdef USE_GNU_PTH
1525   if (rc && has_option (line, "--wait"))
1526     {
1527       rc = 0;
1528       pth_sleep (1); /* Better implement an event mechanism. However,
1529                         for card operations this should be
1530                         sufficient. */
1531       /* FIXME: Need to check that the connection is still alive.
1532          This can be done by issuing status messages. */
1533       goto retry;
1534     }
1535 #endif /*USE_GNU_PTH*/
1536   
1537   if (rc)
1538     log_error ("cmd_lock failed: %s\n", gpg_strerror (rc));
1539   return rc;
1540 }
1541
1542
1543 static const char hlp_unlock[] = 
1544   "UNLOCK\n"
1545   "\n"
1546   "Release exclusive card access.";
1547 static gpg_error_t
1548 cmd_unlock (assuan_context_t ctx, char *line)
1549 {
1550   ctrl_t ctrl = assuan_get_pointer (ctx);
1551   int rc = 0;
1552
1553   (void)line;
1554
1555   if (locked_session)
1556     {
1557       if (locked_session != ctrl->server_local)
1558         rc = gpg_error (GPG_ERR_LOCKED);
1559       else
1560         locked_session = NULL;
1561     }
1562   else
1563     rc = gpg_error (GPG_ERR_NOT_LOCKED);
1564
1565   if (rc)
1566     log_error ("cmd_unlock failed: %s\n", gpg_strerror (rc));
1567   return rc;
1568 }
1569
1570
1571 static const char hlp_getinfo[] = 
1572   "GETINFO <what>\n"
1573   "\n"
1574   "Multi purpose command to return certain information.  \n"
1575   "Supported values of WHAT are:\n"
1576   "\n"
1577   "version     - Return the version of the program.\n"
1578   "pid         - Return the process id of the server.\n"
1579   "\n"
1580   "socket_name - Return the name of the socket.\n"
1581   "\n"
1582   "status - Return the status of the current slot (in the future, may\n"
1583   "also return the status of all slots).  The status is a list of\n"
1584   "one-character flags.  The following flags are currently defined:\n"
1585   "  'u'  Usable card present.  This is the normal state during operation.\n"
1586   "  'r'  Card removed.  A reset is necessary.\n"
1587   "These flags are exclusive.\n"
1588   "\n"
1589   "reader_list - Return a list of detected card readers.  Does\n"
1590   "              currently only work with the internal CCID driver.\n"
1591   "\n"
1592   "deny_admin  - Returns OK if admin commands are not allowed or\n"
1593   "              GPG_ERR_GENERAL if admin commands are allowed.\n"
1594   "\n"
1595   "app_list    - Return a list of supported applications.  One\n"
1596   "              application per line, fields delimited by colons,\n"
1597   "              first field is the name.";
1598 static gpg_error_t
1599 cmd_getinfo (assuan_context_t ctx, char *line)
1600 {
1601   int rc = 0;
1602
1603   if (!strcmp (line, "version"))
1604     {
1605       const char *s = VERSION;
1606       rc = assuan_send_data (ctx, s, strlen (s));
1607     }
1608   else if (!strcmp (line, "pid"))
1609     {
1610       char numbuf[50];
1611
1612       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1613       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1614     }
1615   else if (!strcmp (line, "socket_name"))
1616     {
1617       const char *s = scd_get_socket_name ();
1618
1619       if (s)
1620         rc = assuan_send_data (ctx, s, strlen (s));
1621       else
1622         rc = gpg_error (GPG_ERR_NO_DATA);
1623     }
1624   else if (!strcmp (line, "status"))
1625     {
1626       ctrl_t ctrl = assuan_get_pointer (ctx);
1627       int slot = ctrl->reader_slot;
1628       char flag = 'r';
1629
1630       if (!ctrl->server_local->card_removed && slot != -1)
1631         {
1632           struct slot_status_s *ss;
1633           
1634           if (!(slot >= 0 && slot < DIM(slot_table)))
1635             BUG ();
1636
1637           ss = &slot_table[slot];
1638
1639           if (!ss->valid)
1640             BUG ();
1641
1642           if (ss->any && (ss->status & 1))
1643             flag = 'u';
1644         }
1645       rc = assuan_send_data (ctx, &flag, 1);
1646     }
1647   else if (!strcmp (line, "reader_list"))
1648     {
1649 #ifdef HAVE_LIBUSB
1650       char *s = ccid_get_reader_list ();
1651 #else
1652       char *s = NULL;
1653 #endif
1654       
1655       if (s)
1656         rc = assuan_send_data (ctx, s, strlen (s));
1657       else
1658         rc = gpg_error (GPG_ERR_NO_DATA);
1659       xfree (s);
1660     }
1661   else if (!strcmp (line, "deny_admin"))
1662     rc = opt.allow_admin? gpg_error (GPG_ERR_GENERAL) : 0;
1663   else if (!strcmp (line, "app_list"))
1664     {
1665       char *s = get_supported_applications ();
1666       if (s)
1667         rc = assuan_send_data (ctx, s, strlen (s));
1668       else
1669         rc = 0;
1670       xfree (s);
1671     }
1672   else
1673     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1674   return rc;
1675 }
1676
1677
1678 static const char hlp_restart[] = 
1679   "RESTART\n"
1680   "\n"
1681   "Restart the current connection; this is a kind of warm reset.  It\n"
1682   "deletes the context used by this connection but does not send a\n"
1683   "RESET to the card.  Thus the card itself won't get reset. \n"
1684   "\n"
1685   "This is used by gpg-agent to reuse a primary pipe connection and\n"
1686   "may be used by clients to backup from a conflict in the serial\n"
1687   "command; i.e. to select another application.";
1688 static gpg_error_t
1689 cmd_restart (assuan_context_t ctx, char *line)
1690 {
1691   ctrl_t ctrl = assuan_get_pointer (ctx);
1692
1693   (void)line;
1694
1695   if (ctrl->app_ctx)
1696     {
1697       release_application (ctrl->app_ctx);
1698       ctrl->app_ctx = NULL;
1699     }
1700   if (locked_session && ctrl->server_local == locked_session)
1701     {
1702       locked_session = NULL;
1703       log_info ("implicitly unlocking due to RESTART\n");
1704     }
1705   return 0;
1706 }
1707
1708
1709 static const char hlp_disconnect[] = 
1710   "DISCONNECT\n"
1711   "\n"
1712   "Disconnect the card if it is not any longer used by other\n"
1713   "connections and the backend supports a disconnect operation.";
1714 static gpg_error_t
1715 cmd_disconnect (assuan_context_t ctx, char *line)
1716 {
1717   ctrl_t ctrl = assuan_get_pointer (ctx);
1718
1719   (void)line;
1720   
1721   ctrl->server_local->disconnect_allowed = 1;
1722   return 0;
1723 }
1724
1725
1726
1727 static const char hlp_apdu[] = 
1728   "APDU [--atr] [--more] [--exlen[=N]] [hexstring]\n"
1729   "\n"
1730   "Send an APDU to the current reader.  This command bypasses the high\n"
1731   "level functions and sends the data directly to the card.  HEXSTRING\n"
1732   "is expected to be a proper APDU.  If HEXSTRING is not given no\n"
1733   "commands are set to the card but the command will implictly check\n"
1734   "whether the card is ready for use. \n"
1735   "\n"
1736   "Using the option \"--atr\" returns the ATR of the card as a status\n"
1737   "message before any data like this:\n"
1738   "  S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1\n"
1739   "\n"
1740   "Using the option --more handles the card status word MORE_DATA\n"
1741   "(61xx) and concatenates all reponses to one block.\n"
1742   "\n"
1743   "Using the option \"--exlen\" the returned APDU may use extended\n"
1744   "length up to N bytes.  If N is not given a default value is used\n"
1745   "(currently 4096).";
1746 static gpg_error_t
1747 cmd_apdu (assuan_context_t ctx, char *line)
1748 {
1749   ctrl_t ctrl = assuan_get_pointer (ctx);
1750   int rc;
1751   unsigned char *apdu;
1752   size_t apdulen;
1753   int with_atr;
1754   int handle_more;
1755   const char *s;
1756   size_t exlen;
1757
1758   with_atr = has_option (line, "--atr");
1759   handle_more = has_option (line, "--more");
1760
1761   if ((s=has_option_name (line, "--exlen")))
1762     {
1763       if (*s == '=')
1764         exlen = strtoul (s+1, NULL, 0);
1765       else
1766         exlen = 4096;
1767     }
1768   else
1769     exlen = 0;
1770
1771   line = skip_options (line);
1772
1773   if ( IS_LOCKED (ctrl) )
1774     return gpg_error (GPG_ERR_LOCKED);
1775
1776   if ((rc = open_card (ctrl, NULL)))
1777     return rc;
1778
1779   if (with_atr)
1780     {
1781       unsigned char *atr;
1782       size_t atrlen;
1783       char hexbuf[400];
1784       
1785       atr = apdu_get_atr (ctrl->reader_slot, &atrlen);
1786       if (!atr || atrlen > sizeof hexbuf - 2 )
1787         {
1788           rc = gpg_error (GPG_ERR_INV_CARD);
1789           goto leave;
1790         }
1791       bin2hex (atr, atrlen, hexbuf);
1792       xfree (atr);
1793       send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
1794     }
1795
1796   apdu = hex_to_buffer (line, &apdulen);
1797   if (!apdu)
1798     {
1799       rc = gpg_error_from_syserror ();
1800       goto leave;
1801     }
1802   if (apdulen)
1803     {
1804       unsigned char *result = NULL;
1805       size_t resultlen;
1806
1807       rc = apdu_send_direct (ctrl->reader_slot, exlen,
1808                              apdu, apdulen, handle_more,
1809                              &result, &resultlen);
1810       if (rc)
1811         log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));
1812       else
1813         {
1814           rc = assuan_send_data (ctx, result, resultlen);
1815           xfree (result);
1816         }
1817     }
1818   xfree (apdu);
1819
1820  leave:
1821   TEST_CARD_REMOVAL (ctrl, rc);
1822   return rc;
1823 }
1824
1825
1826 static const char hlp_killscd[] = 
1827   "KILLSCD\n"
1828   "\n"
1829   "Commit suicide.";
1830 static gpg_error_t
1831 cmd_killscd (assuan_context_t ctx, char *line)
1832 {
1833   ctrl_t ctrl = assuan_get_pointer (ctx);
1834
1835   (void)line;
1836
1837   ctrl->server_local->stopme = 1;
1838   return gpg_error (GPG_ERR_EOF);
1839 }
1840
1841
1842 \f
1843 /* Tell the assuan library about our commands */
1844 static int
1845 register_commands (assuan_context_t ctx)
1846 {
1847   static struct {
1848     const char *name;
1849     assuan_handler_t handler;
1850     const char * const help;
1851   } table[] = {
1852     { "SERIALNO",     cmd_serialno, hlp_serialno },
1853     { "LEARN",        cmd_learn,    hlp_learn },
1854     { "READCERT",     cmd_readcert, hlp_readcert },
1855     { "READKEY",      cmd_readkey,  hlp_readkey },
1856     { "SETDATA",      cmd_setdata,  hlp_setdata },
1857     { "PKSIGN",       cmd_pksign,   hlp_pksign },
1858     { "PKAUTH",       cmd_pkauth,   hlp_pkauth },
1859     { "PKDECRYPT",    cmd_pkdecrypt,hlp_pkdecrypt },
1860     { "INPUT",        NULL }, 
1861     { "OUTPUT",       NULL }, 
1862     { "GETATTR",      cmd_getattr,  hlp_getattr },
1863     { "SETATTR",      cmd_setattr,  hlp_setattr },
1864     { "WRITECERT",    cmd_writecert,hlp_writecert },
1865     { "WRITEKEY",     cmd_writekey, hlp_writekey },
1866     { "GENKEY",       cmd_genkey,   hlp_genkey },
1867     { "RANDOM",       cmd_random,   hlp_random },
1868     { "PASSWD",       cmd_passwd,   hlp_passwd },
1869     { "CHECKPIN",     cmd_checkpin, hlp_checkpin },
1870     { "LOCK",         cmd_lock,     hlp_lock },
1871     { "UNLOCK",       cmd_unlock,   hlp_unlock },
1872     { "GETINFO",      cmd_getinfo,  hlp_getinfo },
1873     { "RESTART",      cmd_restart,  hlp_restart },
1874     { "DISCONNECT",   cmd_disconnect,hlp_disconnect },
1875     { "APDU",         cmd_apdu,     hlp_apdu },
1876     { "KILLSCD",      cmd_killscd,  hlp_killscd },
1877     { NULL }
1878   };
1879   int i, rc;
1880
1881   for (i=0; table[i].name; i++)
1882     {
1883       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1884                                     table[i].help);
1885       if (rc)
1886         return rc;
1887     } 
1888   assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
1889
1890   assuan_register_reset_notify (ctx, reset_notify);
1891   assuan_register_option_handler (ctx, option_handler);
1892   return 0;
1893 }
1894
1895
1896 /* Startup the server.  If FD is given as -1 this is simple pipe
1897    server, otherwise it is a regular server.  Returns true if there
1898    are no more active asessions.  */
1899 int
1900 scd_command_handler (ctrl_t ctrl, int fd)
1901 {
1902   int rc;
1903   assuan_context_t ctx = NULL;
1904   int stopme;
1905   
1906   rc = assuan_new (&ctx);
1907   if (rc)
1908     {
1909       log_error ("failed to allocate assuan context: %s\n",
1910                  gpg_strerror (rc));
1911       scd_exit (2);
1912     }
1913
1914   if (fd == -1)
1915     {
1916       assuan_fd_t filedes[2];
1917
1918       filedes[0] = assuan_fdopen (0);
1919       filedes[1] = assuan_fdopen (1);
1920       rc = assuan_init_pipe_server (ctx, filedes);
1921     }
1922   else
1923     {
1924       rc = assuan_init_socket_server (ctx, INT2FD(fd),
1925                                       ASSUAN_SOCKET_SERVER_ACCEPTED);
1926     }
1927   if (rc)
1928     {
1929       log_error ("failed to initialize the server: %s\n",
1930                  gpg_strerror(rc));
1931       scd_exit (2);
1932     }
1933   rc = register_commands (ctx);
1934   if (rc)
1935     {
1936       log_error ("failed to register commands with Assuan: %s\n",
1937                  gpg_strerror(rc));
1938       scd_exit (2);
1939     }
1940   assuan_set_pointer (ctx, ctrl);
1941
1942   /* Allocate and initialize the server object.  Put it into the list
1943      of active sessions. */
1944   ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
1945   ctrl->server_local->next_session = session_list;
1946   session_list = ctrl->server_local;
1947   ctrl->server_local->ctrl_backlink = ctrl;
1948   ctrl->server_local->assuan_ctx = ctx;
1949
1950   /* We open the reader right at startup so that the ticker is able to
1951      update the status file. */
1952   if (ctrl->reader_slot == -1)
1953     {
1954       ctrl->reader_slot = get_reader_slot ();
1955     }
1956
1957   /* Command processing loop. */
1958   for (;;)
1959     {
1960       rc = assuan_accept (ctx);
1961       if (rc == -1)
1962         {
1963           break;
1964         }
1965       else if (rc)
1966         {
1967           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1968           break;
1969         }
1970       
1971       rc = assuan_process (ctx);
1972       if (rc)
1973         {
1974           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1975           continue;
1976         }
1977     }
1978
1979   /* Cleanup.  We don't send an explicit reset to the card.  */
1980   do_reset (ctrl, 0); 
1981
1982   /* Release the server object.  */
1983   if (session_list == ctrl->server_local)
1984     session_list = ctrl->server_local->next_session;
1985   else
1986     {
1987       struct server_local_s *sl;
1988       
1989       for (sl=session_list; sl->next_session; sl = sl->next_session)
1990         if (sl->next_session == ctrl->server_local)
1991           break;
1992       if (!sl->next_session)
1993           BUG ();
1994       sl->next_session = ctrl->server_local->next_session;
1995     }
1996   stopme = ctrl->server_local->stopme;
1997   xfree (ctrl->server_local);
1998   ctrl->server_local = NULL;
1999
2000   /* Release the Assuan context.  */
2001   assuan_release (ctx);
2002
2003   if (stopme)
2004     scd_exit (0);
2005
2006   /* If there are no more sessions return true.  */
2007   return !session_list;
2008 }
2009
2010
2011 /* Send a line with status information via assuan and escape all given
2012    buffers. The variable elements are pairs of (char *, size_t),
2013    terminated with a (NULL, 0). */
2014 void
2015 send_status_info (ctrl_t ctrl, const char *keyword, ...)
2016 {
2017   va_list arg_ptr;
2018   const unsigned char *value;
2019   size_t valuelen;
2020   char buf[950], *p;
2021   size_t n;
2022   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
2023   
2024   va_start (arg_ptr, keyword);
2025
2026   p = buf; 
2027   n = 0;
2028   while ( (value = va_arg (arg_ptr, const unsigned char *)) )
2029     {
2030       valuelen = va_arg (arg_ptr, size_t);
2031       if (!valuelen)
2032         continue; /* empty buffer */
2033       if (n)
2034         {
2035           *p++ = ' ';
2036           n++;
2037         }
2038       for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
2039         {
2040           if (*value < ' ' || *value == '+')
2041             {
2042               sprintf (p, "%%%02X", *value);
2043               p += 3;
2044             }
2045           else if (*value == ' ')
2046             *p++ = '+';
2047           else
2048             *p++ = *value;
2049         }
2050     }
2051   *p = 0;
2052   assuan_write_status (ctx, keyword, buf);
2053
2054   va_end (arg_ptr);
2055 }
2056
2057
2058 /* Send a ready formatted status line via assuan.  */
2059 void
2060 send_status_direct (ctrl_t ctrl, const char *keyword, const char *args)
2061 {
2062   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
2063
2064   if (strchr (args, '\n'))
2065     log_error ("error: LF detected in status line - not sending\n");
2066   else
2067     assuan_write_status (ctx, keyword, args);
2068 }
2069
2070
2071 /* Helper to send the clients a status change notification.  */
2072 static void
2073 send_client_notifications (void)
2074 {
2075   struct {
2076     pid_t pid; 
2077 #ifdef HAVE_W32_SYSTEM
2078     HANDLE handle;
2079 #else
2080     int signo; 
2081 #endif
2082   } killed[50];
2083   int killidx = 0;
2084   int kidx;
2085   struct server_local_s *sl;
2086   
2087   for (sl=session_list; sl; sl = sl->next_session)
2088     {
2089       if (sl->event_signal && sl->assuan_ctx)
2090         {
2091           pid_t pid = assuan_get_pid (sl->assuan_ctx);
2092 #ifdef HAVE_W32_SYSTEM
2093           HANDLE handle = (void *)sl->event_signal;
2094           
2095           for (kidx=0; kidx < killidx; kidx++)
2096             if (killed[kidx].pid == pid 
2097                 && killed[kidx].handle == handle)
2098               break;
2099           if (kidx < killidx)
2100             log_info ("event %lx (%p) already triggered for client %d\n",
2101                       sl->event_signal, handle, (int)pid);
2102           else
2103             {
2104               log_info ("triggering event %lx (%p) for client %d\n",
2105                         sl->event_signal, handle, (int)pid);
2106               if (!SetEvent (handle))
2107                 log_error ("SetEvent(%lx) failed: %s\n",
2108                            sl->event_signal, w32_strerror (-1));
2109               if (killidx < DIM (killed))
2110                 {
2111                   killed[killidx].pid = pid;
2112                   killed[killidx].handle = handle;
2113                   killidx++;
2114                 }
2115             }
2116 #else /*!HAVE_W32_SYSTEM*/
2117           int signo = sl->event_signal;
2118           
2119           if (pid != (pid_t)(-1) && pid && signo > 0)
2120             {
2121               for (kidx=0; kidx < killidx; kidx++)
2122                 if (killed[kidx].pid == pid 
2123                     && killed[kidx].signo == signo)
2124                   break;
2125               if (kidx < killidx)
2126                 log_info ("signal %d already sent to client %d\n",
2127                           signo, (int)pid);
2128               else
2129                 {
2130                   log_info ("sending signal %d to client %d\n",
2131                             signo, (int)pid);
2132                   kill (pid, signo);
2133                   if (killidx < DIM (killed))
2134                     {
2135                       killed[killidx].pid = pid;
2136                       killed[killidx].signo = signo;
2137                       killidx++;
2138                     }
2139                 }
2140             }
2141 #endif /*!HAVE_W32_SYSTEM*/
2142         }
2143     }
2144 }
2145
2146
2147
2148 /* This is the core of scd_update_reader_status_file but the caller
2149    needs to take care of the locking.  */
2150 static void
2151 update_reader_status_file (int set_card_removed_flag)
2152 {
2153   int idx;
2154   unsigned int status, changed;
2155
2156   /* Make sure that the reader has been opened.  Like get_reader_slot,
2157      this part of the code assumes that there is only one reader.  */
2158   if (!slot_table[0].valid)
2159     (void)get_reader_slot ();
2160
2161   /* Note, that we only try to get the status, because it does not
2162      make sense to wait here for a operation to complete.  If we are
2163      busy working with a card, delays in the status file update should
2164      be acceptable. */
2165   for (idx=0; idx < DIM(slot_table); idx++)
2166     {
2167       struct slot_status_s *ss = slot_table + idx;
2168       struct server_local_s *sl;
2169       int sw_apdu;
2170
2171       if (!ss->valid || ss->slot == -1)
2172         continue; /* Not valid or reader not yet open. */
2173       
2174       sw_apdu = apdu_get_status (ss->slot, 0, &status, &changed);
2175       if (sw_apdu == SW_HOST_NO_READER)
2176         {
2177           /* Most likely the _reader_ has been unplugged.  */
2178           status = 0;
2179           changed = ss->changed;
2180         }
2181       else if (sw_apdu)
2182         {
2183           /* Get status failed.  Ignore that.  */
2184           continue; 
2185         }
2186
2187       if (!ss->any || ss->status != status || ss->changed != changed )
2188         {
2189           char *fname;
2190           char templ[50];
2191           FILE *fp;
2192
2193           log_info ("updating slot %d status: 0x%04X->0x%04X (%u->%u)\n",
2194                     ss->slot, ss->status, status, ss->changed, changed);
2195           ss->status = status;
2196           ss->changed = changed;
2197
2198           /* FIXME: Should this be IDX instead of ss->slot?  This
2199              depends on how client sessions will associate the reader
2200              status with their session.  */
2201           snprintf (templ, sizeof templ, "reader_%d.status", ss->slot);
2202           fname = make_filename (opt.homedir, templ, NULL );
2203           fp = fopen (fname, "w");
2204           if (fp)
2205             {
2206               fprintf (fp, "%s\n",
2207                        (status & 1)? "USABLE":
2208                        (status & 4)? "ACTIVE":
2209                        (status & 2)? "PRESENT": "NOCARD");
2210               fclose (fp);
2211             }
2212           xfree (fname);
2213             
2214           /* If a status script is executable, run it. */
2215           {
2216             const char *args[9], *envs[2];
2217             char numbuf1[30], numbuf2[30], numbuf3[30];
2218             char *homestr, *envstr;
2219             gpg_error_t err;
2220             
2221             homestr = make_filename (opt.homedir, NULL);
2222             if (estream_asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0)
2223               log_error ("out of core while building environment\n");
2224             else
2225               {
2226                 envs[0] = envstr;
2227                 envs[1] = NULL;
2228
2229                 sprintf (numbuf1, "%d", ss->slot);
2230                 sprintf (numbuf2, "0x%04X", ss->status);
2231                 sprintf (numbuf3, "0x%04X", status);
2232                 args[0] = "--reader-port";
2233                 args[1] = numbuf1; 
2234                 args[2] = "--old-code";
2235                 args[3] = numbuf2;  
2236                 args[4] = "--new-code";
2237                 args[5] = numbuf3; 
2238                 args[6] = "--status";
2239                 args[7] = ((status & 1)? "USABLE":
2240                            (status & 4)? "ACTIVE":
2241                            (status & 2)? "PRESENT": "NOCARD");
2242                 args[8] = NULL;  
2243
2244                 fname = make_filename (opt.homedir, "scd-event", NULL);
2245                 err = gnupg_spawn_process_detached (fname, args, envs);
2246                 if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
2247                   log_error ("failed to run event handler `%s': %s\n",
2248                              fname, gpg_strerror (err));
2249                 xfree (fname);
2250                 xfree (envstr);
2251               }
2252             xfree (homestr);
2253           }
2254
2255           /* Set the card removed flag for all current sessions.  We
2256              will set this on any card change because a reset or
2257              SERIALNO request must be done in any case.  */
2258           if (ss->any && set_card_removed_flag)
2259             update_card_removed (idx, 1);
2260           
2261           ss->any = 1;
2262
2263           /* Send a signal to all clients who applied for it.  */
2264           send_client_notifications ();
2265         }
2266       
2267       /* Check whether a disconnect is pending.  */
2268       if (opt.card_timeout)
2269         {
2270           for (sl=session_list; sl; sl = sl->next_session)
2271             if (!sl->disconnect_allowed)
2272               break; 
2273           if (session_list && !sl)
2274             {
2275               /* FIXME: Use a real timeout.  */
2276               /* At least one connection and all allow a disconnect.  */
2277               log_info ("disconnecting card in slot %d\n", ss->slot);
2278               apdu_disconnect (ss->slot);
2279             }
2280         }
2281       
2282     }
2283 }
2284
2285 /* This function is called by the ticker thread to check for changes
2286    of the reader stati.  It updates the reader status files and if
2287    requested by the caller also send a signal to the caller.  */
2288 void
2289 scd_update_reader_status_file (void)
2290 {
2291   if (!pth_mutex_acquire (&status_file_update_lock, 1, NULL))
2292     return; /* locked - give up. */
2293   update_reader_status_file (1);
2294   if (!pth_mutex_release (&status_file_update_lock))
2295     log_error ("failed to release status_file_update lock\n");
2296 }