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