52b22c6a0f8b7865b7d0f36b6bf9254d8391f04a
[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   ctrl->in_data.value = buf;
831   ctrl->in_data.valuelen = n;
832   for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
833     buf[n] = xtoi_2 (p);
834   return 0;
835 }
836
837
838
839 static gpg_error_t 
840 pin_cb (void *opaque, const char *info, char **retstr)
841 {
842   assuan_context_t ctx = opaque;
843   char *command;
844   int rc;
845   unsigned char *value;
846   size_t valuelen;
847
848   if (!retstr)
849     {
850       /* We prompt for keypad entry.  To make sure that the popup has
851          been show we use an inquire and not just a status message.
852          We ignore any value returned.  */
853       if (info)
854         {
855           log_debug ("prompting for keypad entry '%s'\n", info);
856           rc = estream_asprintf (&command, "POPUPKEYPADPROMPT %s", info);
857           if (rc < 0)
858             return gpg_error (gpg_err_code_from_errno (errno));
859           rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
860           xfree (command);  
861         }
862       else
863         {
864           log_debug ("dismiss keypad entry prompt\n");
865           rc = assuan_inquire (ctx, "DISMISSKEYPADPROMPT",
866                                &value, &valuelen, MAXLEN_PIN); 
867         }
868       if (!rc)
869         xfree (value);
870       return rc;
871     }
872
873   *retstr = NULL;
874   log_debug ("asking for PIN '%s'\n", info);
875
876   rc = estream_asprintf (&command, "NEEDPIN %s", info);
877   if (rc < 0)
878     return gpg_error (gpg_err_code_from_errno (errno));
879
880   /* Fixme: Write an inquire function which returns the result in
881      secure memory and check all further handling of the PIN. */
882   rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
883   xfree (command);  
884   if (rc)
885     return rc;
886
887   if (!valuelen || value[valuelen-1])
888     {
889       /* We require that the returned value is an UTF-8 string */
890       xfree (value);
891       return gpg_error (GPG_ERR_INV_RESPONSE);
892     }
893   *retstr = (char*)value;
894   return 0;
895 }
896
897
898 static const char hlp_pksign[] = 
899   "PKSIGN [--hash=[rmd160|sha{1,224,256,384,512}|md5]] <hexified_id>\n"
900   "\n"
901   "The --hash option is optional; the default is SHA1.";
902 static gpg_error_t
903 cmd_pksign (assuan_context_t ctx, char *line)
904 {
905   ctrl_t ctrl = assuan_get_pointer (ctx);
906   int rc;
907   unsigned char *outdata;
908   size_t outdatalen;
909   char *keyidstr;
910   int hash_algo;
911
912   if (has_option (line, "--hash=rmd160"))
913     hash_algo = GCRY_MD_RMD160;
914   else if (has_option (line, "--hash=sha1"))
915     hash_algo = GCRY_MD_SHA1;
916   else if (has_option (line, "--hash=sha224"))
917     hash_algo = GCRY_MD_SHA224;
918   else if (has_option (line, "--hash=sha256"))
919     hash_algo = GCRY_MD_SHA256;
920   else if (has_option (line, "--hash=sha384"))
921     hash_algo = GCRY_MD_SHA384;
922   else if (has_option (line, "--hash=sha512"))
923     hash_algo = GCRY_MD_SHA512;
924   else if (has_option (line, "--hash=md5"))
925     hash_algo = GCRY_MD_MD5;
926   else if (!strstr (line, "--"))
927     hash_algo = GCRY_MD_SHA1; 
928   else
929     return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
930
931   line = skip_options (line);
932
933   if ( IS_LOCKED (ctrl) )
934     return gpg_error (GPG_ERR_LOCKED);
935
936   if ((rc = open_card (ctrl, NULL)))
937     return rc;
938
939   /* We have to use a copy of the key ID because the function may use
940      the pin_cb which in turn uses the assuan line buffer and thus
941      overwriting the original line with the keyid */
942   keyidstr = xtrystrdup (line);
943   if (!keyidstr)
944     return out_of_core ();
945   
946   rc = app_sign (ctrl->app_ctx,
947                  keyidstr, hash_algo,
948                  pin_cb, ctx,
949                  ctrl->in_data.value, ctrl->in_data.valuelen,
950                  &outdata, &outdatalen);
951
952   xfree (keyidstr);
953   if (rc)
954     {
955       log_error ("app_sign failed: %s\n", gpg_strerror (rc));
956     }
957   else
958     {
959       rc = assuan_send_data (ctx, outdata, outdatalen);
960       xfree (outdata);
961       if (rc)
962         return rc; /* that is already an assuan error code */
963     }
964
965   TEST_CARD_REMOVAL (ctrl, rc);
966   return rc;
967 }
968
969
970 static const char hlp_pkauth[] = 
971   "PKAUTH <hexified_id>";
972 static gpg_error_t
973 cmd_pkauth (assuan_context_t ctx, char *line)
974 {
975   ctrl_t ctrl = assuan_get_pointer (ctx);
976   int rc;
977   unsigned char *outdata;
978   size_t outdatalen;
979   char *keyidstr;
980
981   if ( IS_LOCKED (ctrl) )
982     return gpg_error (GPG_ERR_LOCKED);
983
984   if ((rc = open_card (ctrl, NULL)))
985     return rc;
986
987   if (!ctrl->app_ctx)
988     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
989
990  /* We have to use a copy of the key ID because the function may use
991      the pin_cb which in turn uses the assuan line buffer and thus
992      overwriting the original line with the keyid */
993   keyidstr = xtrystrdup (line);
994   if (!keyidstr)
995     return out_of_core ();
996   
997   rc = app_auth (ctrl->app_ctx,
998                  keyidstr,
999                  pin_cb, ctx,
1000                  ctrl->in_data.value, ctrl->in_data.valuelen,
1001                  &outdata, &outdatalen);
1002   xfree (keyidstr);
1003   if (rc)
1004     {
1005       log_error ("app_auth failed: %s\n", gpg_strerror (rc));
1006     }
1007   else
1008     {
1009       rc = assuan_send_data (ctx, outdata, outdatalen);
1010       xfree (outdata);
1011       if (rc)
1012         return rc; /* that is already an assuan error code */
1013     }
1014
1015   TEST_CARD_REMOVAL (ctrl, rc);
1016   return rc;
1017 }
1018
1019
1020 static const char hlp_pkdecrypt[] = 
1021   "PKDECRYPT <hexified_id>";
1022 static gpg_error_t
1023 cmd_pkdecrypt (assuan_context_t ctx, char *line)
1024 {
1025   ctrl_t ctrl = assuan_get_pointer (ctx);
1026   int rc;
1027   unsigned char *outdata;
1028   size_t outdatalen;
1029   char *keyidstr;
1030
1031   if ( IS_LOCKED (ctrl) )
1032     return gpg_error (GPG_ERR_LOCKED);
1033
1034   if ((rc = open_card (ctrl, NULL)))
1035     return rc;
1036
1037   keyidstr = xtrystrdup (line);
1038   if (!keyidstr)
1039     return out_of_core ();
1040   rc = app_decipher (ctrl->app_ctx,
1041                      keyidstr, 
1042                      pin_cb, ctx,
1043                      ctrl->in_data.value, ctrl->in_data.valuelen,
1044                      &outdata, &outdatalen);
1045
1046   xfree (keyidstr);
1047   if (rc)
1048     {
1049       log_error ("app_decipher failed: %s\n", gpg_strerror (rc));
1050     }
1051   else
1052     {
1053       rc = assuan_send_data (ctx, outdata, outdatalen);
1054       xfree (outdata);
1055       if (rc)
1056         return rc; /* that is already an assuan error code */
1057     }
1058
1059   TEST_CARD_REMOVAL (ctrl, rc);
1060   return rc;
1061 }
1062
1063
1064 static const char hlp_getattr[] = 
1065   "GETATTR <name>\n"
1066   "\n"
1067   "This command is used to retrieve data from a smartcard.  The\n"
1068   "allowed names depend on the currently selected smartcard\n"
1069   "application.  NAME must be percent and '+' escaped.  The value is\n"
1070   "returned through status message, see the LEARN command for details.\n"
1071   "\n"
1072   "However, the current implementation assumes that Name is not escaped;\n"
1073   "this works as long as noone uses arbitrary escaping. \n"
1074   "\n"
1075   "Note, that this function may even be used on a locked card.";
1076 static gpg_error_t
1077 cmd_getattr (assuan_context_t ctx, char *line)
1078 {
1079   ctrl_t ctrl = assuan_get_pointer (ctx);
1080   int rc;
1081   const char *keyword;
1082
1083   if ((rc = open_card (ctrl, NULL)))
1084     return rc;
1085
1086   keyword = line;
1087   for (; *line && !spacep (line); line++)
1088     ;
1089   if (*line)
1090       *line++ = 0;
1091
1092   /* (We ignore any garbage for now.) */
1093
1094   /* FIXME: Applications should not return sensitive data if the card
1095      is locked.  */
1096   rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
1097
1098   TEST_CARD_REMOVAL (ctrl, rc);
1099   return rc;
1100 }
1101
1102
1103 static const char hlp_setattr[] = 
1104   "SETATTR <name> <value> \n"
1105   "\n"
1106   "This command is used to store data on a a smartcard.  The allowed\n"
1107   "names and values are depend on the currently selected smartcard\n"
1108   "application.  NAME and VALUE must be percent and '+' escaped.\n"
1109   "\n"
1110   "However, the current implementation assumes that NAME is not\n"
1111   "escaped; this works as long as noone uses arbitrary escaping.\n"
1112   "\n"
1113   "A PIN will be requested for most NAMEs.  See the corresponding\n"
1114   "setattr function of the actually used application (app-*.c) for\n"
1115   "details.";
1116 static gpg_error_t
1117 cmd_setattr (assuan_context_t ctx, char *orig_line)
1118 {
1119   ctrl_t ctrl = assuan_get_pointer (ctx);
1120   int rc;
1121   char *keyword;
1122   int keywordlen;
1123   size_t nbytes;
1124   char *line, *linebuf;
1125
1126   if ( IS_LOCKED (ctrl) )
1127     return gpg_error (GPG_ERR_LOCKED);
1128
1129   if ((rc = open_card (ctrl, NULL)))
1130     return rc;
1131
1132   /* We need to use a copy of LINE, because PIN_CB uses the same
1133      context and thus reuses the Assuan provided LINE. */
1134   line = linebuf = xtrystrdup (orig_line);
1135   if (!line)
1136     return out_of_core ();
1137
1138   keyword = line;
1139   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
1140     ;
1141   if (*line)
1142       *line++ = 0;
1143   while (spacep (line))
1144     line++;
1145   nbytes = percent_plus_unescape_inplace (line, 0);
1146
1147   rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx,
1148                     (const unsigned char*)line, nbytes);
1149   xfree (linebuf);
1150
1151   TEST_CARD_REMOVAL (ctrl, rc);
1152   return rc;
1153 }
1154
1155
1156 static const char hlp_writecert[] = 
1157   "WRITECERT <hexified_certid>\n"
1158   "\n"
1159   "This command is used to store a certifciate on a smartcard.  The\n"
1160   "allowed certids depend on the currently selected smartcard\n"
1161   "application. The actual certifciate is requested using the inquiry\n"
1162   "\"CERTDATA\" and needs to be provided in its raw (e.g. DER) form.\n"
1163   "\n"
1164   "In almost all cases a a PIN will be requested.  See the related\n"
1165   "writecert function of the actually used application (app-*.c) for\n"
1166   "details.";
1167 static gpg_error_t
1168 cmd_writecert (assuan_context_t ctx, char *line)
1169 {
1170   ctrl_t ctrl = assuan_get_pointer (ctx);
1171   int rc;
1172   char *certid;
1173   unsigned char *certdata;
1174   size_t certdatalen;
1175
1176   if ( IS_LOCKED (ctrl) )
1177     return gpg_error (GPG_ERR_LOCKED);
1178
1179   line = skip_options (line);
1180
1181   if (!*line)
1182     return set_error (GPG_ERR_ASS_PARAMETER, "no certid given");
1183   certid = line;
1184   while (*line && !spacep (line))
1185     line++;
1186   *line = 0;
1187
1188   if ((rc = open_card (ctrl, NULL)))
1189     return rc;
1190
1191   if (!ctrl->app_ctx)
1192     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1193
1194   certid = xtrystrdup (certid);
1195   if (!certid)
1196     return out_of_core ();
1197
1198   /* Now get the actual keydata. */
1199   rc = assuan_inquire (ctx, "CERTDATA",
1200                        &certdata, &certdatalen, MAXLEN_CERTDATA);
1201   if (rc)
1202     {
1203       xfree (certid);
1204       return rc;
1205     }
1206
1207   /* Write the certificate to the card. */
1208   rc = app_writecert (ctrl->app_ctx, ctrl, certid, 
1209                       pin_cb, ctx, certdata, certdatalen);
1210   xfree (certid);
1211   xfree (certdata);
1212
1213   TEST_CARD_REMOVAL (ctrl, rc);
1214   return rc;
1215 }
1216
1217
1218 static const char hlp_writekey[] = 
1219   "WRITEKEY [--force] <keyid> \n"
1220   "\n"
1221   "This command is used to store a secret key on a a smartcard.  The\n"
1222   "allowed keyids depend on the currently selected smartcard\n"
1223   "application. The actual keydata is requested using the inquiry\n"
1224   "\"KEYDATA\" and need to be provided without any protection.  With\n"
1225   "--force set an existing key under this KEYID will get overwritten.\n"
1226   "The keydata is expected to be the usual canonical encoded\n"
1227   "S-expression.\n"
1228   "\n"
1229   "A PIN will be requested for most NAMEs.  See the corresponding\n"
1230   "writekey function of the actually used application (app-*.c) for\n"
1231   "details.";
1232 static gpg_error_t
1233 cmd_writekey (assuan_context_t ctx, char *line)
1234 {
1235   ctrl_t ctrl = assuan_get_pointer (ctx);
1236   int rc;
1237   char *keyid;
1238   int force = has_option (line, "--force");
1239   unsigned char *keydata;
1240   size_t keydatalen;
1241
1242   if ( IS_LOCKED (ctrl) )
1243     return gpg_error (GPG_ERR_LOCKED);
1244
1245   line = skip_options (line);
1246
1247   if (!*line)
1248     return set_error (GPG_ERR_ASS_PARAMETER, "no keyid given");
1249   keyid = line;
1250   while (*line && !spacep (line))
1251     line++;
1252   *line = 0;
1253
1254   if ((rc = open_card (ctrl, NULL)))
1255     return rc;
1256
1257   if (!ctrl->app_ctx)
1258     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1259
1260   keyid = xtrystrdup (keyid);
1261   if (!keyid)
1262     return out_of_core ();
1263
1264   /* Now get the actual keydata. */
1265   assuan_begin_confidential (ctx);
1266   rc = assuan_inquire (ctx, "KEYDATA", &keydata, &keydatalen, MAXLEN_KEYDATA);
1267   assuan_end_confidential (ctx);
1268   if (rc)
1269     {
1270       xfree (keyid);
1271       return rc;
1272     }
1273
1274   /* Write the key to the card. */
1275   rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0,
1276                      pin_cb, ctx, keydata, keydatalen);
1277   xfree (keyid);
1278   xfree (keydata);
1279
1280   TEST_CARD_REMOVAL (ctrl, rc);
1281   return rc;
1282 }
1283
1284
1285 static const char hlp_genkey[] = 
1286   "GENKEY [--force] [--timestamp=<isodate>] <no>\n"
1287   "\n"
1288   "Generate a key on-card identified by NO, which is application\n"
1289   "specific.  Return values are application specific.  For OpenPGP\n"
1290   "cards 3 status lines are returned:\n"
1291   "\n"
1292   "  S KEY-FPR  <hexstring>\n"
1293   "  S KEY-CREATED-AT <seconds_since_epoch>\n"
1294   "  S KEY-DATA [-|p|n] <hexdata>\n"
1295   "\n"
1296   "  'p' and 'n' are the names of the RSA parameters; '-' is used to\n"
1297   "  indicate that HEXDATA is the first chunk of a parameter given\n"
1298   "  by the next KEY-DATA.\n"
1299   "\n"
1300   "--force is required to overwrite an already existing key.  The\n"
1301   "KEY-CREATED-AT is required for further processing because it is\n"
1302   "part of the hashed key material for the fingerprint.\n"
1303   "\n"
1304   "If --timestamp is given an OpenPGP key will be created using this\n"
1305   "value.  The value needs to be in ISO Format; e.g.\n"
1306   "\"--timestamp=20030316T120000\" and after 1970-01-01 00:00:00.\n"
1307   "\n"
1308   "The public part of the key can also later be retrieved using the\n"
1309   "READKEY command.";
1310 static gpg_error_t
1311 cmd_genkey (assuan_context_t ctx, char *line)
1312 {
1313   ctrl_t ctrl = assuan_get_pointer (ctx);
1314   int rc;
1315   char *keyno;
1316   int force;
1317   const char *s;
1318   time_t timestamp;
1319
1320   if ( IS_LOCKED (ctrl) )
1321     return gpg_error (GPG_ERR_LOCKED);
1322
1323   force = has_option (line, "--force");
1324
1325   if ((s=has_option_name (line, "--timestamp")))
1326     {
1327       if (*s != '=')
1328         return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
1329       timestamp = isotime2epoch (s+1);
1330       if (timestamp < 1)
1331         return set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
1332     }
1333   else
1334     timestamp = 0;
1335
1336
1337   line = skip_options (line);
1338   if (!*line)
1339     return set_error (GPG_ERR_ASS_PARAMETER, "no key number given");
1340   keyno = line;
1341   while (*line && !spacep (line))
1342     line++;
1343   *line = 0;
1344
1345   if ((rc = open_card (ctrl, NULL)))
1346     return rc;
1347
1348   if (!ctrl->app_ctx)
1349     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1350
1351   keyno = xtrystrdup (keyno);
1352   if (!keyno)
1353     return out_of_core ();
1354   rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0,
1355                    timestamp, pin_cb, ctx);
1356   xfree (keyno);
1357
1358   TEST_CARD_REMOVAL (ctrl, rc);
1359   return rc;
1360 }
1361
1362
1363 static const char hlp_random[] = 
1364   "RANDOM <nbytes>\n"
1365   "\n"
1366   "Get NBYTES of random from the card and send them back as data.\n"
1367   "This usually involves EEPROM write on the card and thus excessive\n"
1368   "use of this command may destroy the card.\n"
1369   "\n"
1370   "Note, that this function may be even be used on a locked card.";
1371 static gpg_error_t
1372 cmd_random (assuan_context_t ctx, char *line)
1373 {
1374   ctrl_t ctrl = assuan_get_pointer (ctx);
1375   int rc;
1376   size_t nbytes;
1377   unsigned char *buffer;
1378
1379   if (!*line)
1380     return set_error (GPG_ERR_ASS_PARAMETER, 
1381                       "number of requested bytes missing");
1382   nbytes = strtoul (line, NULL, 0);
1383
1384   if ((rc = open_card (ctrl, NULL)))
1385     return rc;
1386
1387   if (!ctrl->app_ctx)
1388     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1389
1390   buffer = xtrymalloc (nbytes);
1391   if (!buffer)
1392     return out_of_core ();
1393
1394   rc = app_get_challenge (ctrl->app_ctx, nbytes, buffer);
1395   if (!rc)
1396     {
1397       rc = assuan_send_data (ctx, buffer, nbytes);
1398       xfree (buffer);
1399       return rc; /* that is already an assuan error code */
1400     }
1401   xfree (buffer);
1402
1403   TEST_CARD_REMOVAL (ctrl, rc);
1404   return rc;
1405 }
1406
1407
1408 \f
1409 static const char hlp_passwd[] =
1410   "PASSWD [--reset] [--nullpin] <chvno>\n"
1411   "\n"
1412   "Change the PIN or, if --reset is given, reset the retry counter of\n"
1413   "the card holder verfication vector CHVNO.  The option --nullpin is\n"
1414   "used for TCOS cards to set the initial PIN.  The format of CHVNO\n"
1415   "depends on the card application.";
1416 static gpg_error_t
1417 cmd_passwd (assuan_context_t ctx, char *line)
1418 {
1419   ctrl_t ctrl = assuan_get_pointer (ctx);
1420   int rc;
1421   char *chvnostr;
1422   unsigned int flags = 0;
1423
1424   if (has_option (line, "--reset"))
1425     flags |= APP_CHANGE_FLAG_RESET;
1426   if (has_option (line, "--nullpin"))
1427     flags |= APP_CHANGE_FLAG_NULLPIN;
1428
1429   if ( IS_LOCKED (ctrl) )
1430     return gpg_error (GPG_ERR_LOCKED);
1431
1432   line = skip_options (line);
1433
1434   if (!*line)
1435     return set_error (GPG_ERR_ASS_PARAMETER, "no CHV number given");
1436   chvnostr = line;
1437   while (*line && !spacep (line))
1438     line++;
1439   *line = 0;
1440
1441   if ((rc = open_card (ctrl, NULL)))
1442     return rc;
1443
1444   if (!ctrl->app_ctx)
1445     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1446   
1447   chvnostr = xtrystrdup (chvnostr);
1448   if (!chvnostr)
1449     return out_of_core ();
1450   rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
1451   if (rc)
1452     log_error ("command passwd failed: %s\n", gpg_strerror (rc));
1453   xfree (chvnostr);
1454
1455   TEST_CARD_REMOVAL (ctrl, rc);
1456   return rc;
1457 }
1458
1459
1460 static const char hlp_checkpin[] = 
1461   "CHECKPIN <idstr>\n"
1462   "\n"
1463   "Perform a VERIFY operation without doing anything else.  This may\n"
1464   "be used to initialize a the PIN cache earlier to long lasting\n"
1465   "operations.  Its use is highly application dependent.\n"
1466   "\n"
1467   "For OpenPGP:\n"
1468   "\n"
1469   "   Perform a simple verify operation for CHV1 and CHV2, so that\n"
1470   "   further operations won't ask for CHV2 and it is possible to do a\n"
1471   "   cheap check on the PIN: If there is something wrong with the PIN\n"
1472   "   entry system, only the regular CHV will get blocked and not the\n"
1473   "   dangerous CHV3.  IDSTR is the usual card's serial number in hex\n"
1474   "   notation; an optional fingerprint part will get ignored.  There\n"
1475   "   is however a special mode if the IDSTR is sffixed with the\n"
1476   "   literal string \"[CHV3]\": In this case the Admin PIN is checked\n"
1477   "   if and only if the retry counter is still at 3.\n"
1478   "\n"
1479   "For Netkey:\n"
1480   "\n"
1481   "   Any of the valid PIN Ids may be used.  These are the strings:\n"
1482   "\n"
1483   "     PW1.CH       - Global password 1\n"
1484   "     PW2.CH       - Global password 2\n"
1485   "     PW1.CH.SIG   - SigG password 1\n"
1486   "     PW2.CH.SIG   - SigG password 2\n"
1487   "\n"
1488   "   For a definitive list, see the implementation in app-nks.c.\n"
1489   "   Note that we call a PW2.* PIN a \"PUK\" despite that since TCOS\n"
1490   "   3.0 they are technically alternative PINs used to mutally\n"
1491   "   unblock each other.";
1492 static gpg_error_t
1493 cmd_checkpin (assuan_context_t ctx, char *line)
1494 {
1495   ctrl_t ctrl = assuan_get_pointer (ctx);
1496   int rc;
1497   char *idstr;
1498
1499   if ( IS_LOCKED (ctrl) )
1500     return gpg_error (GPG_ERR_LOCKED);
1501
1502   if ((rc = open_card (ctrl, NULL)))
1503     return rc;
1504
1505   if (!ctrl->app_ctx)
1506     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1507
1508   /* We have to use a copy of the key ID because the function may use
1509      the pin_cb which in turn uses the assuan line buffer and thus
1510      overwriting the original line with the keyid. */
1511   idstr = xtrystrdup (line);
1512   if (!idstr)
1513     return out_of_core ();
1514   
1515   rc = app_check_pin (ctrl->app_ctx, idstr, pin_cb, ctx);
1516   xfree (idstr);
1517   if (rc)
1518     log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
1519
1520   TEST_CARD_REMOVAL (ctrl, rc);
1521   return rc;
1522 }
1523
1524
1525 static const char hlp_lock[] = 
1526   "LOCK [--wait]\n"
1527   "\n"
1528   "Grant exclusive card access to this session.  Note that there is\n"
1529   "no lock counter used and a second lock from the same session will\n"
1530   "be ignored.  A single unlock (or RESET) unlocks the session.\n"
1531   "Return GPG_ERR_LOCKED if another session has locked the reader.\n"
1532   "\n"
1533   "If the option --wait is given the command will wait until a\n"
1534   "lock has been released.";
1535 static gpg_error_t
1536 cmd_lock (assuan_context_t ctx, char *line)
1537 {
1538   ctrl_t ctrl = assuan_get_pointer (ctx);
1539   int rc = 0;
1540
1541  retry:
1542   if (locked_session)
1543     {
1544       if (locked_session != ctrl->server_local)
1545         rc = gpg_error (GPG_ERR_LOCKED);
1546     }
1547   else
1548     locked_session = ctrl->server_local;
1549
1550 #ifdef USE_GNU_PTH
1551   if (rc && has_option (line, "--wait"))
1552     {
1553       rc = 0;
1554       pth_sleep (1); /* Better implement an event mechanism. However,
1555                         for card operations this should be
1556                         sufficient. */
1557       /* FIXME: Need to check that the connection is still alive.
1558          This can be done by issuing status messages. */
1559       goto retry;
1560     }
1561 #endif /*USE_GNU_PTH*/
1562   
1563   if (rc)
1564     log_error ("cmd_lock failed: %s\n", gpg_strerror (rc));
1565   return rc;
1566 }
1567
1568
1569 static const char hlp_unlock[] = 
1570   "UNLOCK\n"
1571   "\n"
1572   "Release exclusive card access.";
1573 static gpg_error_t
1574 cmd_unlock (assuan_context_t ctx, char *line)
1575 {
1576   ctrl_t ctrl = assuan_get_pointer (ctx);
1577   int rc = 0;
1578
1579   (void)line;
1580
1581   if (locked_session)
1582     {
1583       if (locked_session != ctrl->server_local)
1584         rc = gpg_error (GPG_ERR_LOCKED);
1585       else
1586         locked_session = NULL;
1587     }
1588   else
1589     rc = gpg_error (GPG_ERR_NOT_LOCKED);
1590
1591   if (rc)
1592     log_error ("cmd_unlock failed: %s\n", gpg_strerror (rc));
1593   return rc;
1594 }
1595
1596
1597 static const char hlp_getinfo[] = 
1598   "GETINFO <what>\n"
1599   "\n"
1600   "Multi purpose command to return certain information.  \n"
1601   "Supported values of WHAT are:\n"
1602   "\n"
1603   "version     - Return the version of the program.\n"
1604   "pid         - Return the process id of the server.\n"
1605   "\n"
1606   "socket_name - Return the name of the socket.\n"
1607   "\n"
1608   "status - Return the status of the current slot (in the future, may\n"
1609   "also return the status of all slots).  The status is a list of\n"
1610   "one-character flags.  The following flags are currently defined:\n"
1611   "  'u'  Usable card present.  This is the normal state during operation.\n"
1612   "  'r'  Card removed.  A reset is necessary.\n"
1613   "These flags are exclusive.\n"
1614   "\n"
1615   "reader_list - Return a list of detected card readers.  Does\n"
1616   "              currently only work with the internal CCID driver.\n"
1617   "\n"
1618   "deny_admin  - Returns OK if admin commands are not allowed or\n"
1619   "              GPG_ERR_GENERAL if admin commands are allowed.\n"
1620   "\n"
1621   "app_list    - Return a list of supported applications.  One\n"
1622   "              application per line, fields delimited by colons,\n"
1623   "              first field is the name.";
1624 static gpg_error_t
1625 cmd_getinfo (assuan_context_t ctx, char *line)
1626 {
1627   int rc = 0;
1628
1629   if (!strcmp (line, "version"))
1630     {
1631       const char *s = VERSION;
1632       rc = assuan_send_data (ctx, s, strlen (s));
1633     }
1634   else if (!strcmp (line, "pid"))
1635     {
1636       char numbuf[50];
1637
1638       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1639       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1640     }
1641   else if (!strcmp (line, "socket_name"))
1642     {
1643       const char *s = scd_get_socket_name ();
1644
1645       if (s)
1646         rc = assuan_send_data (ctx, s, strlen (s));
1647       else
1648         rc = gpg_error (GPG_ERR_NO_DATA);
1649     }
1650   else if (!strcmp (line, "status"))
1651     {
1652       ctrl_t ctrl = assuan_get_pointer (ctx);
1653       int slot = ctrl->reader_slot;
1654       char flag = 'r';
1655
1656       if (!ctrl->server_local->card_removed && slot != -1)
1657         {
1658           struct slot_status_s *ss;
1659           
1660           if (!(slot >= 0 && slot < DIM(slot_table)))
1661             BUG ();
1662
1663           ss = &slot_table[slot];
1664
1665           if (!ss->valid)
1666             BUG ();
1667
1668           if (ss->any && (ss->status & 1))
1669             flag = 'u';
1670         }
1671       rc = assuan_send_data (ctx, &flag, 1);
1672     }
1673   else if (!strcmp (line, "reader_list"))
1674     {
1675 #ifdef HAVE_LIBUSB
1676       char *s = ccid_get_reader_list ();
1677 #else
1678       char *s = NULL;
1679 #endif
1680       
1681       if (s)
1682         rc = assuan_send_data (ctx, s, strlen (s));
1683       else
1684         rc = gpg_error (GPG_ERR_NO_DATA);
1685       xfree (s);
1686     }
1687   else if (!strcmp (line, "deny_admin"))
1688     rc = opt.allow_admin? gpg_error (GPG_ERR_GENERAL) : 0;
1689   else if (!strcmp (line, "app_list"))
1690     {
1691       char *s = get_supported_applications ();
1692       if (s)
1693         rc = assuan_send_data (ctx, s, strlen (s));
1694       else
1695         rc = 0;
1696       xfree (s);
1697     }
1698   else
1699     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1700   return rc;
1701 }
1702
1703
1704 static const char hlp_restart[] = 
1705   "RESTART\n"
1706   "\n"
1707   "Restart the current connection; this is a kind of warm reset.  It\n"
1708   "deletes the context used by this connection but does not send a\n"
1709   "RESET to the card.  Thus the card itself won't get reset. \n"
1710   "\n"
1711   "This is used by gpg-agent to reuse a primary pipe connection and\n"
1712   "may be used by clients to backup from a conflict in the serial\n"
1713   "command; i.e. to select another application.";
1714 static gpg_error_t
1715 cmd_restart (assuan_context_t ctx, char *line)
1716 {
1717   ctrl_t ctrl = assuan_get_pointer (ctx);
1718
1719   (void)line;
1720
1721   if (ctrl->app_ctx)
1722     {
1723       release_application (ctrl->app_ctx);
1724       ctrl->app_ctx = NULL;
1725     }
1726   if (locked_session && ctrl->server_local == locked_session)
1727     {
1728       locked_session = NULL;
1729       log_info ("implicitly unlocking due to RESTART\n");
1730     }
1731   return 0;
1732 }
1733
1734
1735 static const char hlp_disconnect[] = 
1736   "DISCONNECT\n"
1737   "\n"
1738   "Disconnect the card if it is not any longer used by other\n"
1739   "connections and the backend supports a disconnect operation.";
1740 static gpg_error_t
1741 cmd_disconnect (assuan_context_t ctx, char *line)
1742 {
1743   ctrl_t ctrl = assuan_get_pointer (ctx);
1744
1745   (void)line;
1746   
1747   ctrl->server_local->disconnect_allowed = 1;
1748   return 0;
1749 }
1750
1751
1752
1753 static const char hlp_apdu[] = 
1754   "APDU [--atr] [--more] [--exlen[=N]] [hexstring]\n"
1755   "\n"
1756   "Send an APDU to the current reader.  This command bypasses the high\n"
1757   "level functions and sends the data directly to the card.  HEXSTRING\n"
1758   "is expected to be a proper APDU.  If HEXSTRING is not given no\n"
1759   "commands are set to the card but the command will implictly check\n"
1760   "whether the card is ready for use. \n"
1761   "\n"
1762   "Using the option \"--atr\" returns the ATR of the card as a status\n"
1763   "message before any data like this:\n"
1764   "  S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1\n"
1765   "\n"
1766   "Using the option --more handles the card status word MORE_DATA\n"
1767   "(61xx) and concatenates all reponses to one block.\n"
1768   "\n"
1769   "Using the option \"--exlen\" the returned APDU may use extended\n"
1770   "length up to N bytes.  If N is not given a default value is used\n"
1771   "(currently 4096).";
1772 static gpg_error_t
1773 cmd_apdu (assuan_context_t ctx, char *line)
1774 {
1775   ctrl_t ctrl = assuan_get_pointer (ctx);
1776   int rc;
1777   unsigned char *apdu;
1778   size_t apdulen;
1779   int with_atr;
1780   int handle_more;
1781   const char *s;
1782   size_t exlen;
1783
1784   with_atr = has_option (line, "--atr");
1785   handle_more = has_option (line, "--more");
1786
1787   if ((s=has_option_name (line, "--exlen")))
1788     {
1789       if (*s == '=')
1790         exlen = strtoul (s+1, NULL, 0);
1791       else
1792         exlen = 4096;
1793     }
1794   else
1795     exlen = 0;
1796
1797   line = skip_options (line);
1798
1799   if ( IS_LOCKED (ctrl) )
1800     return gpg_error (GPG_ERR_LOCKED);
1801
1802   if ((rc = open_card (ctrl, NULL)))
1803     return rc;
1804
1805   if (with_atr)
1806     {
1807       unsigned char *atr;
1808       size_t atrlen;
1809       char hexbuf[400];
1810       
1811       atr = apdu_get_atr (ctrl->reader_slot, &atrlen);
1812       if (!atr || atrlen > sizeof hexbuf - 2 )
1813         {
1814           rc = gpg_error (GPG_ERR_INV_CARD);
1815           goto leave;
1816         }
1817       bin2hex (atr, atrlen, hexbuf);
1818       xfree (atr);
1819       send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
1820     }
1821
1822   apdu = hex_to_buffer (line, &apdulen);
1823   if (!apdu)
1824     {
1825       rc = gpg_error_from_syserror ();
1826       goto leave;
1827     }
1828   if (apdulen)
1829     {
1830       unsigned char *result = NULL;
1831       size_t resultlen;
1832
1833       rc = apdu_send_direct (ctrl->reader_slot, exlen,
1834                              apdu, apdulen, handle_more,
1835                              &result, &resultlen);
1836       if (rc)
1837         log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));
1838       else
1839         {
1840           rc = assuan_send_data (ctx, result, resultlen);
1841           xfree (result);
1842         }
1843     }
1844   xfree (apdu);
1845
1846  leave:
1847   TEST_CARD_REMOVAL (ctrl, rc);
1848   return rc;
1849 }
1850
1851
1852 static const char hlp_killscd[] = 
1853   "KILLSCD\n"
1854   "\n"
1855   "Commit suicide.";
1856 static gpg_error_t
1857 cmd_killscd (assuan_context_t ctx, char *line)
1858 {
1859   ctrl_t ctrl = assuan_get_pointer (ctx);
1860
1861   (void)line;
1862
1863   ctrl->server_local->stopme = 1;
1864   return gpg_error (GPG_ERR_EOF);
1865 }
1866
1867
1868 \f
1869 /* Tell the assuan library about our commands */
1870 static int
1871 register_commands (assuan_context_t ctx)
1872 {
1873   static struct {
1874     const char *name;
1875     assuan_handler_t handler;
1876     const char * const help;
1877   } table[] = {
1878     { "SERIALNO",     cmd_serialno, hlp_serialno },
1879     { "LEARN",        cmd_learn,    hlp_learn },
1880     { "READCERT",     cmd_readcert, hlp_readcert },
1881     { "READKEY",      cmd_readkey,  hlp_readkey },
1882     { "SETDATA",      cmd_setdata,  hlp_setdata },
1883     { "PKSIGN",       cmd_pksign,   hlp_pksign },
1884     { "PKAUTH",       cmd_pkauth,   hlp_pkauth },
1885     { "PKDECRYPT",    cmd_pkdecrypt,hlp_pkdecrypt },
1886     { "INPUT",        NULL }, 
1887     { "OUTPUT",       NULL }, 
1888     { "GETATTR",      cmd_getattr,  hlp_getattr },
1889     { "SETATTR",      cmd_setattr,  hlp_setattr },
1890     { "WRITECERT",    cmd_writecert,hlp_writecert },
1891     { "WRITEKEY",     cmd_writekey, hlp_writekey },
1892     { "GENKEY",       cmd_genkey,   hlp_genkey },
1893     { "RANDOM",       cmd_random,   hlp_random },
1894     { "PASSWD",       cmd_passwd,   hlp_passwd },
1895     { "CHECKPIN",     cmd_checkpin, hlp_checkpin },
1896     { "LOCK",         cmd_lock,     hlp_lock },
1897     { "UNLOCK",       cmd_unlock,   hlp_unlock },
1898     { "GETINFO",      cmd_getinfo,  hlp_getinfo },
1899     { "RESTART",      cmd_restart,  hlp_restart },
1900     { "DISCONNECT",   cmd_disconnect,hlp_disconnect },
1901     { "APDU",         cmd_apdu,     hlp_apdu },
1902     { "KILLSCD",      cmd_killscd,  hlp_killscd },
1903     { NULL }
1904   };
1905   int i, rc;
1906
1907   for (i=0; table[i].name; i++)
1908     {
1909       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1910                                     table[i].help);
1911       if (rc)
1912         return rc;
1913     } 
1914   assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
1915
1916   assuan_register_reset_notify (ctx, reset_notify);
1917   assuan_register_option_handler (ctx, option_handler);
1918   return 0;
1919 }
1920
1921
1922 /* Startup the server.  If FD is given as -1 this is simple pipe
1923    server, otherwise it is a regular server.  Returns true if there
1924    are no more active asessions.  */
1925 int
1926 scd_command_handler (ctrl_t ctrl, int fd)
1927 {
1928   int rc;
1929   assuan_context_t ctx = NULL;
1930   int stopme;
1931   
1932   rc = assuan_new (&ctx);
1933   if (rc)
1934     {
1935       log_error ("failed to allocate assuan context: %s\n",
1936                  gpg_strerror (rc));
1937       scd_exit (2);
1938     }
1939
1940   if (fd == -1)
1941     {
1942       assuan_fd_t filedes[2];
1943
1944       filedes[0] = assuan_fdopen (0);
1945       filedes[1] = assuan_fdopen (1);
1946       rc = assuan_init_pipe_server (ctx, filedes);
1947     }
1948   else
1949     {
1950       rc = assuan_init_socket_server (ctx, INT2FD(fd),
1951                                       ASSUAN_SOCKET_SERVER_ACCEPTED);
1952     }
1953   if (rc)
1954     {
1955       log_error ("failed to initialize the server: %s\n",
1956                  gpg_strerror(rc));
1957       scd_exit (2);
1958     }
1959   rc = register_commands (ctx);
1960   if (rc)
1961     {
1962       log_error ("failed to register commands with Assuan: %s\n",
1963                  gpg_strerror(rc));
1964       scd_exit (2);
1965     }
1966   assuan_set_pointer (ctx, ctrl);
1967
1968   /* Allocate and initialize the server object.  Put it into the list
1969      of active sessions. */
1970   ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
1971   ctrl->server_local->next_session = session_list;
1972   session_list = ctrl->server_local;
1973   ctrl->server_local->ctrl_backlink = ctrl;
1974   ctrl->server_local->assuan_ctx = ctx;
1975
1976   if (DBG_ASSUAN)
1977     assuan_set_log_stream (ctx, log_get_stream ());
1978
1979   /* We open the reader right at startup so that the ticker is able to
1980      update the status file. */
1981   if (ctrl->reader_slot == -1)
1982     {
1983       ctrl->reader_slot = get_reader_slot ();
1984     }
1985
1986   /* Command processing loop. */
1987   for (;;)
1988     {
1989       rc = assuan_accept (ctx);
1990       if (rc == -1)
1991         {
1992           break;
1993         }
1994       else if (rc)
1995         {
1996           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1997           break;
1998         }
1999       
2000       rc = assuan_process (ctx);
2001       if (rc)
2002         {
2003           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
2004           continue;
2005         }
2006     }
2007
2008   /* Cleanup.  We don't send an explicit reset to the card.  */
2009   do_reset (ctrl, 0); 
2010
2011   /* Release the server object.  */
2012   if (session_list == ctrl->server_local)
2013     session_list = ctrl->server_local->next_session;
2014   else
2015     {
2016       struct server_local_s *sl;
2017       
2018       for (sl=session_list; sl->next_session; sl = sl->next_session)
2019         if (sl->next_session == ctrl->server_local)
2020           break;
2021       if (!sl->next_session)
2022           BUG ();
2023       sl->next_session = ctrl->server_local->next_session;
2024     }
2025   stopme = ctrl->server_local->stopme || reader_disabled;
2026   xfree (ctrl->server_local);
2027   ctrl->server_local = NULL;
2028
2029   /* Release the Assuan context.  */
2030   assuan_release (ctx);
2031
2032   if (stopme)
2033     scd_exit (0);
2034
2035   /* If there are no more sessions return true.  */
2036   return !session_list;
2037 }
2038
2039
2040 /* Send a line with status information via assuan and escape all given
2041    buffers. The variable elements are pairs of (char *, size_t),
2042    terminated with a (NULL, 0). */
2043 void
2044 send_status_info (ctrl_t ctrl, const char *keyword, ...)
2045 {
2046   va_list arg_ptr;
2047   const unsigned char *value;
2048   size_t valuelen;
2049   char buf[950], *p;
2050   size_t n;
2051   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
2052   
2053   va_start (arg_ptr, keyword);
2054
2055   p = buf; 
2056   n = 0;
2057   while ( (value = va_arg (arg_ptr, const unsigned char *)) )
2058     {
2059       valuelen = va_arg (arg_ptr, size_t);
2060       if (!valuelen)
2061         continue; /* empty buffer */
2062       if (n)
2063         {
2064           *p++ = ' ';
2065           n++;
2066         }
2067       for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
2068         {
2069           if (*value < ' ' || *value == '+')
2070             {
2071               sprintf (p, "%%%02X", *value);
2072               p += 3;
2073             }
2074           else if (*value == ' ')
2075             *p++ = '+';
2076           else
2077             *p++ = *value;
2078         }
2079     }
2080   *p = 0;
2081   assuan_write_status (ctx, keyword, buf);
2082
2083   va_end (arg_ptr);
2084 }
2085
2086
2087 /* Send a ready formatted status line via assuan.  */
2088 void
2089 send_status_direct (ctrl_t ctrl, const char *keyword, const char *args)
2090 {
2091   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
2092
2093   if (strchr (args, '\n'))
2094     log_error ("error: LF detected in status line - not sending\n");
2095   else
2096     assuan_write_status (ctx, keyword, args);
2097 }
2098
2099
2100 /* Helper to send the clients a status change notification.  */
2101 static void
2102 send_client_notifications (void)
2103 {
2104   struct {
2105     pid_t pid; 
2106 #ifdef HAVE_W32_SYSTEM
2107     HANDLE handle;
2108 #else
2109     int signo; 
2110 #endif
2111   } killed[50];
2112   int killidx = 0;
2113   int kidx;
2114   struct server_local_s *sl;
2115   
2116   for (sl=session_list; sl; sl = sl->next_session)
2117     {
2118       if (sl->event_signal && sl->assuan_ctx)
2119         {
2120           pid_t pid = assuan_get_pid (sl->assuan_ctx);
2121 #ifdef HAVE_W32_SYSTEM
2122           HANDLE handle = (void *)sl->event_signal;
2123           
2124           for (kidx=0; kidx < killidx; kidx++)
2125             if (killed[kidx].pid == pid 
2126                 && killed[kidx].handle == handle)
2127               break;
2128           if (kidx < killidx)
2129             log_info ("event %lx (%p) already triggered for client %d\n",
2130                       sl->event_signal, handle, (int)pid);
2131           else
2132             {
2133               log_info ("triggering event %lx (%p) for client %d\n",
2134                         sl->event_signal, handle, (int)pid);
2135               if (!SetEvent (handle))
2136                 log_error ("SetEvent(%lx) failed: %s\n",
2137                            sl->event_signal, w32_strerror (-1));
2138               if (killidx < DIM (killed))
2139                 {
2140                   killed[killidx].pid = pid;
2141                   killed[killidx].handle = handle;
2142                   killidx++;
2143                 }
2144             }
2145 #else /*!HAVE_W32_SYSTEM*/
2146           int signo = sl->event_signal;
2147           
2148           if (pid != (pid_t)(-1) && pid && signo > 0)
2149             {
2150               for (kidx=0; kidx < killidx; kidx++)
2151                 if (killed[kidx].pid == pid 
2152                     && killed[kidx].signo == signo)
2153                   break;
2154               if (kidx < killidx)
2155                 log_info ("signal %d already sent to client %d\n",
2156                           signo, (int)pid);
2157               else
2158                 {
2159                   log_info ("sending signal %d to client %d\n",
2160                             signo, (int)pid);
2161                   kill (pid, signo);
2162                   if (killidx < DIM (killed))
2163                     {
2164                       killed[killidx].pid = pid;
2165                       killed[killidx].signo = signo;
2166                       killidx++;
2167                     }
2168                 }
2169             }
2170 #endif /*!HAVE_W32_SYSTEM*/
2171         }
2172     }
2173 }
2174
2175
2176
2177 /* This is the core of scd_update_reader_status_file but the caller
2178    needs to take care of the locking.  */
2179 static void
2180 update_reader_status_file (int set_card_removed_flag)
2181 {
2182   int idx;
2183   unsigned int status, changed;
2184
2185   /* Make sure that the reader has been opened.  Like get_reader_slot,
2186      this part of the code assumes that there is only one reader.  */
2187   if (!slot_table[0].valid)
2188     (void)get_reader_slot ();
2189
2190   /* Note, that we only try to get the status, because it does not
2191      make sense to wait here for a operation to complete.  If we are
2192      busy working with a card, delays in the status file update should
2193      be acceptable. */
2194   for (idx=0; idx < DIM(slot_table); idx++)
2195     {
2196       struct slot_status_s *ss = slot_table + idx;
2197       struct server_local_s *sl;
2198       int sw_apdu;
2199
2200       if (!ss->valid || ss->slot == -1)
2201         continue; /* Not valid or reader not yet open. */
2202       
2203       sw_apdu = apdu_get_status (ss->slot, 0, &status, &changed);
2204       if (sw_apdu == SW_HOST_NO_READER)
2205         {
2206           /* Most likely the _reader_ has been unplugged.  */
2207           apdu_close_reader (ss->slot);
2208           ss->valid = 0;
2209           status = 0;
2210           changed = ss->changed;
2211         }
2212       else if (sw_apdu)
2213         {
2214           /* Get status failed.  Ignore that.  */
2215           continue; 
2216         }
2217
2218       if (!ss->any || ss->status != status || ss->changed != changed )
2219         {
2220           char *fname;
2221           char templ[50];
2222           FILE *fp;
2223
2224           log_info ("updating slot %d status: 0x%04X->0x%04X (%u->%u)\n",
2225                     ss->slot, ss->status, status, ss->changed, changed);
2226           ss->status = status;
2227           ss->changed = changed;
2228
2229           /* FIXME: Should this be IDX instead of ss->slot?  This
2230              depends on how client sessions will associate the reader
2231              status with their session.  */
2232           snprintf (templ, sizeof templ, "reader_%d.status", ss->slot);
2233           fname = make_filename (opt.homedir, templ, NULL );
2234           fp = fopen (fname, "w");
2235           if (fp)
2236             {
2237               fprintf (fp, "%s\n",
2238                        (status & 1)? "USABLE":
2239                        (status & 4)? "ACTIVE":
2240                        (status & 2)? "PRESENT": "NOCARD");
2241               fclose (fp);
2242             }
2243           xfree (fname);
2244             
2245           /* If a status script is executable, run it. */
2246           {
2247             const char *args[9], *envs[2];
2248             char numbuf1[30], numbuf2[30], numbuf3[30];
2249             char *homestr, *envstr;
2250             gpg_error_t err;
2251             
2252             homestr = make_filename (opt.homedir, NULL);
2253             if (estream_asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0)
2254               log_error ("out of core while building environment\n");
2255             else
2256               {
2257                 envs[0] = envstr;
2258                 envs[1] = NULL;
2259
2260                 sprintf (numbuf1, "%d", ss->slot);
2261                 sprintf (numbuf2, "0x%04X", ss->status);
2262                 sprintf (numbuf3, "0x%04X", status);
2263                 args[0] = "--reader-port";
2264                 args[1] = numbuf1; 
2265                 args[2] = "--old-code";
2266                 args[3] = numbuf2;  
2267                 args[4] = "--new-code";
2268                 args[5] = numbuf3; 
2269                 args[6] = "--status";
2270                 args[7] = ((status & 1)? "USABLE":
2271                            (status & 4)? "ACTIVE":
2272                            (status & 2)? "PRESENT": "NOCARD");
2273                 args[8] = NULL;  
2274
2275                 fname = make_filename (opt.homedir, "scd-event", NULL);
2276                 err = gnupg_spawn_process_detached (fname, args, envs);
2277                 if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
2278                   log_error ("failed to run event handler `%s': %s\n",
2279                              fname, gpg_strerror (err));
2280                 xfree (fname);
2281                 xfree (envstr);
2282               }
2283             xfree (homestr);
2284           }
2285
2286           /* Set the card removed flag for all current sessions.  We
2287              will set this on any card change because a reset or
2288              SERIALNO request must be done in any case.  */
2289           if (ss->any && set_card_removed_flag)
2290             update_card_removed (idx, 1);
2291           
2292           ss->any = 1;
2293
2294           /* Send a signal to all clients who applied for it.  */
2295           send_client_notifications ();
2296         }
2297       
2298       /* Check whether a disconnect is pending.  */
2299       if (opt.card_timeout)
2300         {
2301           for (sl=session_list; sl; sl = sl->next_session)
2302             if (!sl->disconnect_allowed)
2303               break; 
2304           if (session_list && !sl)
2305             {
2306               /* FIXME: Use a real timeout.  */
2307               /* At least one connection and all allow a disconnect.  */
2308               log_info ("disconnecting card in slot %d\n", ss->slot);
2309               apdu_disconnect (ss->slot);
2310             }
2311         }
2312       
2313     }
2314 }
2315
2316 /* This function is called by the ticker thread to check for changes
2317    of the reader stati.  It updates the reader status files and if
2318    requested by the caller also send a signal to the caller.  */
2319 void
2320 scd_update_reader_status_file (void)
2321 {
2322   if (!pth_mutex_acquire (&status_file_update_lock, 1, NULL))
2323     return; /* locked - give up. */
2324   update_reader_status_file (1);
2325   if (!pth_mutex_release (&status_file_update_lock))
2326     log_error ("failed to release status_file_update lock\n");
2327 }