a579b24eb63ad390122f0838021ca0f140ba0e81
[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 3 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   "  'p' and 'n' are the names of the RSA parameters; '-' is used to\n"
1298   "  indicate that HEXDATA is the first chunk of a parameter given\n"
1299   "  by the next KEY-DATA.\n"
1300   "\n"
1301   "--force is required to overwrite an already existing key.  The\n"
1302   "KEY-CREATED-AT is required for further processing because it is\n"
1303   "part of the hashed key material for the fingerprint.\n"
1304   "\n"
1305   "If --timestamp is given an OpenPGP key will be created using this\n"
1306   "value.  The value needs to be in ISO Format; e.g.\n"
1307   "\"--timestamp=20030316T120000\" and after 1970-01-01 00:00:00.\n"
1308   "\n"
1309   "The public part of the key can also later be retrieved using the\n"
1310   "READKEY command.";
1311 static gpg_error_t
1312 cmd_genkey (assuan_context_t ctx, char *line)
1313 {
1314   ctrl_t ctrl = assuan_get_pointer (ctx);
1315   int rc;
1316   char *keyno;
1317   int force;
1318   const char *s;
1319   time_t timestamp;
1320
1321   if ( IS_LOCKED (ctrl) )
1322     return gpg_error (GPG_ERR_LOCKED);
1323
1324   force = has_option (line, "--force");
1325
1326   if ((s=has_option_name (line, "--timestamp")))
1327     {
1328       if (*s != '=')
1329         return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
1330       timestamp = isotime2epoch (s+1);
1331       if (timestamp < 1)
1332         return set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
1333     }
1334   else
1335     timestamp = 0;
1336
1337
1338   line = skip_options (line);
1339   if (!*line)
1340     return set_error (GPG_ERR_ASS_PARAMETER, "no key number given");
1341   keyno = line;
1342   while (*line && !spacep (line))
1343     line++;
1344   *line = 0;
1345
1346   if ((rc = open_card (ctrl, NULL)))
1347     return rc;
1348
1349   if (!ctrl->app_ctx)
1350     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1351
1352   keyno = xtrystrdup (keyno);
1353   if (!keyno)
1354     return out_of_core ();
1355   rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0,
1356                    timestamp, pin_cb, ctx);
1357   xfree (keyno);
1358
1359   TEST_CARD_REMOVAL (ctrl, rc);
1360   return rc;
1361 }
1362
1363
1364 static const char hlp_random[] =
1365   "RANDOM <nbytes>\n"
1366   "\n"
1367   "Get NBYTES of random from the card and send them back as data.\n"
1368   "This usually involves EEPROM write on the card and thus excessive\n"
1369   "use of this command may destroy the card.\n"
1370   "\n"
1371   "Note, that this function may be even be used on a locked card.";
1372 static gpg_error_t
1373 cmd_random (assuan_context_t ctx, char *line)
1374 {
1375   ctrl_t ctrl = assuan_get_pointer (ctx);
1376   int rc;
1377   size_t nbytes;
1378   unsigned char *buffer;
1379
1380   if (!*line)
1381     return set_error (GPG_ERR_ASS_PARAMETER,
1382                       "number of requested bytes missing");
1383   nbytes = strtoul (line, NULL, 0);
1384
1385   if ((rc = open_card (ctrl, NULL)))
1386     return rc;
1387
1388   if (!ctrl->app_ctx)
1389     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1390
1391   buffer = xtrymalloc (nbytes);
1392   if (!buffer)
1393     return out_of_core ();
1394
1395   rc = app_get_challenge (ctrl->app_ctx, nbytes, buffer);
1396   if (!rc)
1397     {
1398       rc = assuan_send_data (ctx, buffer, nbytes);
1399       xfree (buffer);
1400       return rc; /* that is already an assuan error code */
1401     }
1402   xfree (buffer);
1403
1404   TEST_CARD_REMOVAL (ctrl, rc);
1405   return rc;
1406 }
1407
1408
1409 \f
1410 static const char hlp_passwd[] =
1411   "PASSWD [--reset] [--nullpin] <chvno>\n"
1412   "\n"
1413   "Change the PIN or, if --reset is given, reset the retry counter of\n"
1414   "the card holder verfication vector CHVNO.  The option --nullpin is\n"
1415   "used for TCOS cards to set the initial PIN.  The format of CHVNO\n"
1416   "depends on the card application.";
1417 static gpg_error_t
1418 cmd_passwd (assuan_context_t ctx, char *line)
1419 {
1420   ctrl_t ctrl = assuan_get_pointer (ctx);
1421   int rc;
1422   char *chvnostr;
1423   unsigned int flags = 0;
1424
1425   if (has_option (line, "--reset"))
1426     flags |= APP_CHANGE_FLAG_RESET;
1427   if (has_option (line, "--nullpin"))
1428     flags |= APP_CHANGE_FLAG_NULLPIN;
1429
1430   if ( IS_LOCKED (ctrl) )
1431     return gpg_error (GPG_ERR_LOCKED);
1432
1433   line = skip_options (line);
1434
1435   if (!*line)
1436     return set_error (GPG_ERR_ASS_PARAMETER, "no CHV number given");
1437   chvnostr = line;
1438   while (*line && !spacep (line))
1439     line++;
1440   *line = 0;
1441
1442   if ((rc = open_card (ctrl, NULL)))
1443     return rc;
1444
1445   if (!ctrl->app_ctx)
1446     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1447
1448   chvnostr = xtrystrdup (chvnostr);
1449   if (!chvnostr)
1450     return out_of_core ();
1451   rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
1452   if (rc)
1453     log_error ("command passwd failed: %s\n", gpg_strerror (rc));
1454   xfree (chvnostr);
1455
1456   TEST_CARD_REMOVAL (ctrl, rc);
1457   return rc;
1458 }
1459
1460
1461 static const char hlp_checkpin[] =
1462   "CHECKPIN <idstr>\n"
1463   "\n"
1464   "Perform a VERIFY operation without doing anything else.  This may\n"
1465   "be used to initialize a the PIN cache earlier to long lasting\n"
1466   "operations.  Its use is highly application dependent.\n"
1467   "\n"
1468   "For OpenPGP:\n"
1469   "\n"
1470   "   Perform a simple verify operation for CHV1 and CHV2, so that\n"
1471   "   further operations won't ask for CHV2 and it is possible to do a\n"
1472   "   cheap check on the PIN: If there is something wrong with the PIN\n"
1473   "   entry system, only the regular CHV will get blocked and not the\n"
1474   "   dangerous CHV3.  IDSTR is the usual card's serial number in hex\n"
1475   "   notation; an optional fingerprint part will get ignored.  There\n"
1476   "   is however a special mode if the IDSTR is sffixed with the\n"
1477   "   literal string \"[CHV3]\": In this case the Admin PIN is checked\n"
1478   "   if and only if the retry counter is still at 3.\n"
1479   "\n"
1480   "For Netkey:\n"
1481   "\n"
1482   "   Any of the valid PIN Ids may be used.  These are the strings:\n"
1483   "\n"
1484   "     PW1.CH       - Global password 1\n"
1485   "     PW2.CH       - Global password 2\n"
1486   "     PW1.CH.SIG   - SigG password 1\n"
1487   "     PW2.CH.SIG   - SigG password 2\n"
1488   "\n"
1489   "   For a definitive list, see the implementation in app-nks.c.\n"
1490   "   Note that we call a PW2.* PIN a \"PUK\" despite that since TCOS\n"
1491   "   3.0 they are technically alternative PINs used to mutally\n"
1492   "   unblock each other.";
1493 static gpg_error_t
1494 cmd_checkpin (assuan_context_t ctx, char *line)
1495 {
1496   ctrl_t ctrl = assuan_get_pointer (ctx);
1497   int rc;
1498   char *idstr;
1499
1500   if ( IS_LOCKED (ctrl) )
1501     return gpg_error (GPG_ERR_LOCKED);
1502
1503   if ((rc = open_card (ctrl, NULL)))
1504     return rc;
1505
1506   if (!ctrl->app_ctx)
1507     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1508
1509   /* We have to use a copy of the key ID because the function may use
1510      the pin_cb which in turn uses the assuan line buffer and thus
1511      overwriting the original line with the keyid. */
1512   idstr = xtrystrdup (line);
1513   if (!idstr)
1514     return out_of_core ();
1515
1516   rc = app_check_pin (ctrl->app_ctx, idstr, pin_cb, ctx);
1517   xfree (idstr);
1518   if (rc)
1519     log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
1520
1521   TEST_CARD_REMOVAL (ctrl, rc);
1522   return rc;
1523 }
1524
1525
1526 static const char hlp_lock[] =
1527   "LOCK [--wait]\n"
1528   "\n"
1529   "Grant exclusive card access to this session.  Note that there is\n"
1530   "no lock counter used and a second lock from the same session will\n"
1531   "be ignored.  A single unlock (or RESET) unlocks the session.\n"
1532   "Return GPG_ERR_LOCKED if another session has locked the reader.\n"
1533   "\n"
1534   "If the option --wait is given the command will wait until a\n"
1535   "lock has been released.";
1536 static gpg_error_t
1537 cmd_lock (assuan_context_t ctx, char *line)
1538 {
1539   ctrl_t ctrl = assuan_get_pointer (ctx);
1540   int rc = 0;
1541
1542  retry:
1543   if (locked_session)
1544     {
1545       if (locked_session != ctrl->server_local)
1546         rc = gpg_error (GPG_ERR_LOCKED);
1547     }
1548   else
1549     locked_session = ctrl->server_local;
1550
1551 #ifdef USE_GNU_PTH
1552   if (rc && has_option (line, "--wait"))
1553     {
1554       rc = 0;
1555       pth_sleep (1); /* Better implement an event mechanism. However,
1556                         for card operations this should be
1557                         sufficient. */
1558       /* FIXME: Need to check that the connection is still alive.
1559          This can be done by issuing status messages. */
1560       goto retry;
1561     }
1562 #endif /*USE_GNU_PTH*/
1563
1564   if (rc)
1565     log_error ("cmd_lock failed: %s\n", gpg_strerror (rc));
1566   return rc;
1567 }
1568
1569
1570 static const char hlp_unlock[] =
1571   "UNLOCK\n"
1572   "\n"
1573   "Release exclusive card access.";
1574 static gpg_error_t
1575 cmd_unlock (assuan_context_t ctx, char *line)
1576 {
1577   ctrl_t ctrl = assuan_get_pointer (ctx);
1578   int rc = 0;
1579
1580   (void)line;
1581
1582   if (locked_session)
1583     {
1584       if (locked_session != ctrl->server_local)
1585         rc = gpg_error (GPG_ERR_LOCKED);
1586       else
1587         locked_session = NULL;
1588     }
1589   else
1590     rc = gpg_error (GPG_ERR_NOT_LOCKED);
1591
1592   if (rc)
1593     log_error ("cmd_unlock failed: %s\n", gpg_strerror (rc));
1594   return rc;
1595 }
1596
1597
1598 static const char hlp_getinfo[] =
1599   "GETINFO <what>\n"
1600   "\n"
1601   "Multi purpose command to return certain information.  \n"
1602   "Supported values of WHAT are:\n"
1603   "\n"
1604   "version     - Return the version of the program.\n"
1605   "pid         - Return the process id of the server.\n"
1606   "\n"
1607   "socket_name - Return the name of the socket.\n"
1608   "\n"
1609   "status - Return the status of the current slot (in the future, may\n"
1610   "also return the status of all slots).  The status is a list of\n"
1611   "one-character flags.  The following flags are currently defined:\n"
1612   "  'u'  Usable card present.  This is the normal state during operation.\n"
1613   "  'r'  Card removed.  A reset is necessary.\n"
1614   "These flags are exclusive.\n"
1615   "\n"
1616   "reader_list - Return a list of detected card readers.  Does\n"
1617   "              currently only work with the internal CCID driver.\n"
1618   "\n"
1619   "deny_admin  - Returns OK if admin commands are not allowed or\n"
1620   "              GPG_ERR_GENERAL if admin commands are allowed.\n"
1621   "\n"
1622   "app_list    - Return a list of supported applications.  One\n"
1623   "              application per line, fields delimited by colons,\n"
1624   "              first field is the name.";
1625 static gpg_error_t
1626 cmd_getinfo (assuan_context_t ctx, char *line)
1627 {
1628   int rc = 0;
1629
1630   if (!strcmp (line, "version"))
1631     {
1632       const char *s = VERSION;
1633       rc = assuan_send_data (ctx, s, strlen (s));
1634     }
1635   else if (!strcmp (line, "pid"))
1636     {
1637       char numbuf[50];
1638
1639       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1640       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1641     }
1642   else if (!strcmp (line, "socket_name"))
1643     {
1644       const char *s = scd_get_socket_name ();
1645
1646       if (s)
1647         rc = assuan_send_data (ctx, s, strlen (s));
1648       else
1649         rc = gpg_error (GPG_ERR_NO_DATA);
1650     }
1651   else if (!strcmp (line, "status"))
1652     {
1653       ctrl_t ctrl = assuan_get_pointer (ctx);
1654       int slot = ctrl->reader_slot;
1655       char flag = 'r';
1656
1657       if (!ctrl->server_local->card_removed && slot != -1)
1658         {
1659           struct slot_status_s *ss;
1660
1661           if (!(slot >= 0 && slot < DIM(slot_table)))
1662             BUG ();
1663
1664           ss = &slot_table[slot];
1665
1666           if (!ss->valid)
1667             BUG ();
1668
1669           if (ss->any && (ss->status & 1))
1670             flag = 'u';
1671         }
1672       rc = assuan_send_data (ctx, &flag, 1);
1673     }
1674   else if (!strcmp (line, "reader_list"))
1675     {
1676 #ifdef HAVE_LIBUSB
1677       char *s = ccid_get_reader_list ();
1678 #else
1679       char *s = NULL;
1680 #endif
1681
1682       if (s)
1683         rc = assuan_send_data (ctx, s, strlen (s));
1684       else
1685         rc = gpg_error (GPG_ERR_NO_DATA);
1686       xfree (s);
1687     }
1688   else if (!strcmp (line, "deny_admin"))
1689     rc = opt.allow_admin? gpg_error (GPG_ERR_GENERAL) : 0;
1690   else if (!strcmp (line, "app_list"))
1691     {
1692       char *s = get_supported_applications ();
1693       if (s)
1694         rc = assuan_send_data (ctx, s, strlen (s));
1695       else
1696         rc = 0;
1697       xfree (s);
1698     }
1699   else
1700     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1701   return rc;
1702 }
1703
1704
1705 static const char hlp_restart[] =
1706   "RESTART\n"
1707   "\n"
1708   "Restart the current connection; this is a kind of warm reset.  It\n"
1709   "deletes the context used by this connection but does not send a\n"
1710   "RESET to the card.  Thus the card itself won't get reset. \n"
1711   "\n"
1712   "This is used by gpg-agent to reuse a primary pipe connection and\n"
1713   "may be used by clients to backup from a conflict in the serial\n"
1714   "command; i.e. to select another application.";
1715 static gpg_error_t
1716 cmd_restart (assuan_context_t ctx, char *line)
1717 {
1718   ctrl_t ctrl = assuan_get_pointer (ctx);
1719
1720   (void)line;
1721
1722   if (ctrl->app_ctx)
1723     {
1724       release_application (ctrl->app_ctx);
1725       ctrl->app_ctx = NULL;
1726     }
1727   if (locked_session && ctrl->server_local == locked_session)
1728     {
1729       locked_session = NULL;
1730       log_info ("implicitly unlocking due to RESTART\n");
1731     }
1732   return 0;
1733 }
1734
1735
1736 static const char hlp_disconnect[] =
1737   "DISCONNECT\n"
1738   "\n"
1739   "Disconnect the card if it is not any longer used by other\n"
1740   "connections and the backend supports a disconnect operation.";
1741 static gpg_error_t
1742 cmd_disconnect (assuan_context_t ctx, char *line)
1743 {
1744   ctrl_t ctrl = assuan_get_pointer (ctx);
1745
1746   (void)line;
1747
1748   ctrl->server_local->disconnect_allowed = 1;
1749   return 0;
1750 }
1751
1752
1753
1754 static const char hlp_apdu[] =
1755   "APDU [--atr] [--more] [--exlen[=N]] [hexstring]\n"
1756   "\n"
1757   "Send an APDU to the current reader.  This command bypasses the high\n"
1758   "level functions and sends the data directly to the card.  HEXSTRING\n"
1759   "is expected to be a proper APDU.  If HEXSTRING is not given no\n"
1760   "commands are set to the card but the command will implictly check\n"
1761   "whether the card is ready for use. \n"
1762   "\n"
1763   "Using the option \"--atr\" returns the ATR of the card as a status\n"
1764   "message before any data like this:\n"
1765   "  S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1\n"
1766   "\n"
1767   "Using the option --more handles the card status word MORE_DATA\n"
1768   "(61xx) and concatenates all reponses to one block.\n"
1769   "\n"
1770   "Using the option \"--exlen\" the returned APDU may use extended\n"
1771   "length up to N bytes.  If N is not given a default value is used\n"
1772   "(currently 4096).";
1773 static gpg_error_t
1774 cmd_apdu (assuan_context_t ctx, char *line)
1775 {
1776   ctrl_t ctrl = assuan_get_pointer (ctx);
1777   int rc;
1778   unsigned char *apdu;
1779   size_t apdulen;
1780   int with_atr;
1781   int handle_more;
1782   const char *s;
1783   size_t exlen;
1784
1785   with_atr = has_option (line, "--atr");
1786   handle_more = has_option (line, "--more");
1787
1788   if ((s=has_option_name (line, "--exlen")))
1789     {
1790       if (*s == '=')
1791         exlen = strtoul (s+1, NULL, 0);
1792       else
1793         exlen = 4096;
1794     }
1795   else
1796     exlen = 0;
1797
1798   line = skip_options (line);
1799
1800   if ( IS_LOCKED (ctrl) )
1801     return gpg_error (GPG_ERR_LOCKED);
1802
1803   if ((rc = open_card (ctrl, NULL)))
1804     return rc;
1805
1806   if (with_atr)
1807     {
1808       unsigned char *atr;
1809       size_t atrlen;
1810       char hexbuf[400];
1811
1812       atr = apdu_get_atr (ctrl->reader_slot, &atrlen);
1813       if (!atr || atrlen > sizeof hexbuf - 2 )
1814         {
1815           rc = gpg_error (GPG_ERR_INV_CARD);
1816           goto leave;
1817         }
1818       bin2hex (atr, atrlen, hexbuf);
1819       xfree (atr);
1820       send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
1821     }
1822
1823   apdu = hex_to_buffer (line, &apdulen);
1824   if (!apdu)
1825     {
1826       rc = gpg_error_from_syserror ();
1827       goto leave;
1828     }
1829   if (apdulen)
1830     {
1831       unsigned char *result = NULL;
1832       size_t resultlen;
1833
1834       rc = apdu_send_direct (ctrl->reader_slot, exlen,
1835                              apdu, apdulen, handle_more,
1836                              &result, &resultlen);
1837       if (rc)
1838         log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));
1839       else
1840         {
1841           rc = assuan_send_data (ctx, result, resultlen);
1842           xfree (result);
1843         }
1844     }
1845   xfree (apdu);
1846
1847  leave:
1848   TEST_CARD_REMOVAL (ctrl, rc);
1849   return rc;
1850 }
1851
1852
1853 static const char hlp_killscd[] =
1854   "KILLSCD\n"
1855   "\n"
1856   "Commit suicide.";
1857 static gpg_error_t
1858 cmd_killscd (assuan_context_t ctx, char *line)
1859 {
1860   ctrl_t ctrl = assuan_get_pointer (ctx);
1861
1862   (void)line;
1863
1864   ctrl->server_local->stopme = 1;
1865   return gpg_error (GPG_ERR_EOF);
1866 }
1867
1868
1869 \f
1870 /* Tell the assuan library about our commands */
1871 static int
1872 register_commands (assuan_context_t ctx)
1873 {
1874   static struct {
1875     const char *name;
1876     assuan_handler_t handler;
1877     const char * const help;
1878   } table[] = {
1879     { "SERIALNO",     cmd_serialno, hlp_serialno },
1880     { "LEARN",        cmd_learn,    hlp_learn },
1881     { "READCERT",     cmd_readcert, hlp_readcert },
1882     { "READKEY",      cmd_readkey,  hlp_readkey },
1883     { "SETDATA",      cmd_setdata,  hlp_setdata },
1884     { "PKSIGN",       cmd_pksign,   hlp_pksign },
1885     { "PKAUTH",       cmd_pkauth,   hlp_pkauth },
1886     { "PKDECRYPT",    cmd_pkdecrypt,hlp_pkdecrypt },
1887     { "INPUT",        NULL },
1888     { "OUTPUT",       NULL },
1889     { "GETATTR",      cmd_getattr,  hlp_getattr },
1890     { "SETATTR",      cmd_setattr,  hlp_setattr },
1891     { "WRITECERT",    cmd_writecert,hlp_writecert },
1892     { "WRITEKEY",     cmd_writekey, hlp_writekey },
1893     { "GENKEY",       cmd_genkey,   hlp_genkey },
1894     { "RANDOM",       cmd_random,   hlp_random },
1895     { "PASSWD",       cmd_passwd,   hlp_passwd },
1896     { "CHECKPIN",     cmd_checkpin, hlp_checkpin },
1897     { "LOCK",         cmd_lock,     hlp_lock },
1898     { "UNLOCK",       cmd_unlock,   hlp_unlock },
1899     { "GETINFO",      cmd_getinfo,  hlp_getinfo },
1900     { "RESTART",      cmd_restart,  hlp_restart },
1901     { "DISCONNECT",   cmd_disconnect,hlp_disconnect },
1902     { "APDU",         cmd_apdu,     hlp_apdu },
1903     { "KILLSCD",      cmd_killscd,  hlp_killscd },
1904     { NULL }
1905   };
1906   int i, rc;
1907
1908   for (i=0; table[i].name; i++)
1909     {
1910       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1911                                     table[i].help);
1912       if (rc)
1913         return rc;
1914     }
1915   assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
1916
1917   assuan_register_reset_notify (ctx, reset_notify);
1918   assuan_register_option_handler (ctx, option_handler);
1919   return 0;
1920 }
1921
1922
1923 /* Startup the server.  If FD is given as -1 this is simple pipe
1924    server, otherwise it is a regular server.  Returns true if there
1925    are no more active asessions.  */
1926 int
1927 scd_command_handler (ctrl_t ctrl, int fd)
1928 {
1929   int rc;
1930   assuan_context_t ctx = NULL;
1931   int stopme;
1932
1933   rc = assuan_new (&ctx);
1934   if (rc)
1935     {
1936       log_error ("failed to allocate assuan context: %s\n",
1937                  gpg_strerror (rc));
1938       scd_exit (2);
1939     }
1940
1941   if (fd == -1)
1942     {
1943       assuan_fd_t filedes[2];
1944
1945       filedes[0] = assuan_fdopen (0);
1946       filedes[1] = assuan_fdopen (1);
1947       rc = assuan_init_pipe_server (ctx, filedes);
1948     }
1949   else
1950     {
1951       rc = assuan_init_socket_server (ctx, INT2FD(fd),
1952                                       ASSUAN_SOCKET_SERVER_ACCEPTED);
1953     }
1954   if (rc)
1955     {
1956       log_error ("failed to initialize the server: %s\n",
1957                  gpg_strerror(rc));
1958       scd_exit (2);
1959     }
1960   rc = register_commands (ctx);
1961   if (rc)
1962     {
1963       log_error ("failed to register commands with Assuan: %s\n",
1964                  gpg_strerror(rc));
1965       scd_exit (2);
1966     }
1967   assuan_set_pointer (ctx, ctrl);
1968
1969   /* Allocate and initialize the server object.  Put it into the list
1970      of active sessions. */
1971   ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
1972   ctrl->server_local->next_session = session_list;
1973   session_list = ctrl->server_local;
1974   ctrl->server_local->ctrl_backlink = ctrl;
1975   ctrl->server_local->assuan_ctx = ctx;
1976
1977   /* We open the reader right at startup so that the ticker is able to
1978      update the status file. */
1979   if (ctrl->reader_slot == -1)
1980     {
1981       ctrl->reader_slot = get_reader_slot ();
1982     }
1983
1984   /* Command processing loop. */
1985   for (;;)
1986     {
1987       rc = assuan_accept (ctx);
1988       if (rc == -1)
1989         {
1990           break;
1991         }
1992       else if (rc)
1993         {
1994           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1995           break;
1996         }
1997
1998       rc = assuan_process (ctx);
1999       if (rc)
2000         {
2001           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
2002           continue;
2003         }
2004     }
2005
2006   /* Cleanup.  We don't send an explicit reset to the card.  */
2007   do_reset (ctrl, 0);
2008
2009   /* Release the server object.  */
2010   if (session_list == ctrl->server_local)
2011     session_list = ctrl->server_local->next_session;
2012   else
2013     {
2014       struct server_local_s *sl;
2015
2016       for (sl=session_list; sl->next_session; sl = sl->next_session)
2017         if (sl->next_session == ctrl->server_local)
2018           break;
2019       if (!sl->next_session)
2020           BUG ();
2021       sl->next_session = ctrl->server_local->next_session;
2022     }
2023   stopme = ctrl->server_local->stopme || reader_disabled;
2024   xfree (ctrl->server_local);
2025   ctrl->server_local = NULL;
2026
2027   /* Release the Assuan context.  */
2028   assuan_release (ctx);
2029
2030   if (stopme)
2031     scd_exit (0);
2032
2033   /* If there are no more sessions return true.  */
2034   return !session_list;
2035 }
2036
2037
2038 /* Send a line with status information via assuan and escape all given
2039    buffers. The variable elements are pairs of (char *, size_t),
2040    terminated with a (NULL, 0). */
2041 void
2042 send_status_info (ctrl_t ctrl, const char *keyword, ...)
2043 {
2044   va_list arg_ptr;
2045   const unsigned char *value;
2046   size_t valuelen;
2047   char buf[950], *p;
2048   size_t n;
2049   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
2050
2051   va_start (arg_ptr, keyword);
2052
2053   p = buf;
2054   n = 0;
2055   while ( (value = va_arg (arg_ptr, const unsigned char *)) )
2056     {
2057       valuelen = va_arg (arg_ptr, size_t);
2058       if (!valuelen)
2059         continue; /* empty buffer */
2060       if (n)
2061         {
2062           *p++ = ' ';
2063           n++;
2064         }
2065       for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
2066         {
2067           if (*value < ' ' || *value == '+')
2068             {
2069               sprintf (p, "%%%02X", *value);
2070               p += 3;
2071             }
2072           else if (*value == ' ')
2073             *p++ = '+';
2074           else
2075             *p++ = *value;
2076         }
2077     }
2078   *p = 0;
2079   assuan_write_status (ctx, keyword, buf);
2080
2081   va_end (arg_ptr);
2082 }
2083
2084
2085 /* Send a ready formatted status line via assuan.  */
2086 void
2087 send_status_direct (ctrl_t ctrl, const char *keyword, const char *args)
2088 {
2089   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
2090
2091   if (strchr (args, '\n'))
2092     log_error ("error: LF detected in status line - not sending\n");
2093   else
2094     assuan_write_status (ctx, keyword, args);
2095 }
2096
2097
2098 /* Helper to send the clients a status change notification.  */
2099 static void
2100 send_client_notifications (void)
2101 {
2102   struct {
2103     pid_t pid;
2104 #ifdef HAVE_W32_SYSTEM
2105     HANDLE handle;
2106 #else
2107     int signo;
2108 #endif
2109   } killed[50];
2110   int killidx = 0;
2111   int kidx;
2112   struct server_local_s *sl;
2113
2114   for (sl=session_list; sl; sl = sl->next_session)
2115     {
2116       if (sl->event_signal && sl->assuan_ctx)
2117         {
2118           pid_t pid = assuan_get_pid (sl->assuan_ctx);
2119 #ifdef HAVE_W32_SYSTEM
2120           HANDLE handle = (void *)sl->event_signal;
2121
2122           for (kidx=0; kidx < killidx; kidx++)
2123             if (killed[kidx].pid == pid
2124                 && killed[kidx].handle == handle)
2125               break;
2126           if (kidx < killidx)
2127             log_info ("event %lx (%p) already triggered for client %d\n",
2128                       sl->event_signal, handle, (int)pid);
2129           else
2130             {
2131               log_info ("triggering event %lx (%p) for client %d\n",
2132                         sl->event_signal, handle, (int)pid);
2133               if (!SetEvent (handle))
2134                 log_error ("SetEvent(%lx) failed: %s\n",
2135                            sl->event_signal, w32_strerror (-1));
2136               if (killidx < DIM (killed))
2137                 {
2138                   killed[killidx].pid = pid;
2139                   killed[killidx].handle = handle;
2140                   killidx++;
2141                 }
2142             }
2143 #else /*!HAVE_W32_SYSTEM*/
2144           int signo = sl->event_signal;
2145
2146           if (pid != (pid_t)(-1) && pid && signo > 0)
2147             {
2148               for (kidx=0; kidx < killidx; kidx++)
2149                 if (killed[kidx].pid == pid
2150                     && killed[kidx].signo == signo)
2151                   break;
2152               if (kidx < killidx)
2153                 log_info ("signal %d already sent to client %d\n",
2154                           signo, (int)pid);
2155               else
2156                 {
2157                   log_info ("sending signal %d to client %d\n",
2158                             signo, (int)pid);
2159                   kill (pid, signo);
2160                   if (killidx < DIM (killed))
2161                     {
2162                       killed[killidx].pid = pid;
2163                       killed[killidx].signo = signo;
2164                       killidx++;
2165                     }
2166                 }
2167             }
2168 #endif /*!HAVE_W32_SYSTEM*/
2169         }
2170     }
2171 }
2172
2173
2174
2175 /* This is the core of scd_update_reader_status_file but the caller
2176    needs to take care of the locking.  */
2177 static void
2178 update_reader_status_file (int set_card_removed_flag)
2179 {
2180   int idx;
2181   unsigned int status, changed;
2182
2183   /* Make sure that the reader has been opened.  Like get_reader_slot,
2184      this part of the code assumes that there is only one reader.  */
2185   if (!slot_table[0].valid)
2186     (void)get_reader_slot ();
2187
2188   /* Note, that we only try to get the status, because it does not
2189      make sense to wait here for a operation to complete.  If we are
2190      busy working with a card, delays in the status file update should
2191      be acceptable. */
2192   for (idx=0; idx < DIM(slot_table); idx++)
2193     {
2194       struct slot_status_s *ss = slot_table + idx;
2195       struct server_local_s *sl;
2196       int sw_apdu;
2197
2198       if (!ss->valid || ss->slot == -1)
2199         continue; /* Not valid or reader not yet open. */
2200
2201       sw_apdu = apdu_get_status (ss->slot, 0, &status, &changed);
2202       if (sw_apdu == SW_HOST_NO_READER)
2203         {
2204           /* Most likely the _reader_ has been unplugged.  */
2205           apdu_close_reader(ss->slot);
2206           ss->valid = 0;
2207           status = 0;
2208           changed = ss->changed;
2209         }
2210       else if (sw_apdu)
2211         {
2212           /* Get status failed.  Ignore that.  */
2213           continue;
2214         }
2215
2216       if (!ss->any || ss->status != status || ss->changed != changed )
2217         {
2218           char *fname;
2219           char templ[50];
2220           FILE *fp;
2221
2222           log_info ("updating slot %d status: 0x%04X->0x%04X (%u->%u)\n",
2223                     ss->slot, ss->status, status, ss->changed, changed);
2224           ss->status = status;
2225           ss->changed = changed;
2226
2227           /* FIXME: Should this be IDX instead of ss->slot?  This
2228              depends on how client sessions will associate the reader
2229              status with their session.  */
2230           snprintf (templ, sizeof templ, "reader_%d.status", ss->slot);
2231           fname = make_filename (opt.homedir, templ, NULL );
2232           fp = fopen (fname, "w");
2233           if (fp)
2234             {
2235               fprintf (fp, "%s\n",
2236                        (status & 1)? "USABLE":
2237                        (status & 4)? "ACTIVE":
2238                        (status & 2)? "PRESENT": "NOCARD");
2239               fclose (fp);
2240             }
2241           xfree (fname);
2242
2243           /* If a status script is executable, run it. */
2244           {
2245             const char *args[9], *envs[2];
2246             char numbuf1[30], numbuf2[30], numbuf3[30];
2247             char *homestr, *envstr;
2248             gpg_error_t err;
2249
2250             homestr = make_filename (opt.homedir, NULL);
2251             if (estream_asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0)
2252               log_error ("out of core while building environment\n");
2253             else
2254               {
2255                 envs[0] = envstr;
2256                 envs[1] = NULL;
2257
2258                 sprintf (numbuf1, "%d", ss->slot);
2259                 sprintf (numbuf2, "0x%04X", ss->status);
2260                 sprintf (numbuf3, "0x%04X", status);
2261                 args[0] = "--reader-port";
2262                 args[1] = numbuf1;
2263                 args[2] = "--old-code";
2264                 args[3] = numbuf2;
2265                 args[4] = "--new-code";
2266                 args[5] = numbuf3;
2267                 args[6] = "--status";
2268                 args[7] = ((status & 1)? "USABLE":
2269                            (status & 4)? "ACTIVE":
2270                            (status & 2)? "PRESENT": "NOCARD");
2271                 args[8] = NULL;
2272
2273                 fname = make_filename (opt.homedir, "scd-event", NULL);
2274                 err = gnupg_spawn_process_detached (fname, args, envs);
2275                 if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
2276                   log_error ("failed to run event handler `%s': %s\n",
2277                              fname, gpg_strerror (err));
2278                 xfree (fname);
2279                 xfree (envstr);
2280               }
2281             xfree (homestr);
2282           }
2283
2284           /* Set the card removed flag for all current sessions.  We
2285              will set this on any card change because a reset or
2286              SERIALNO request must be done in any case.  */
2287           if (ss->any && set_card_removed_flag)
2288             update_card_removed (idx, 1);
2289
2290           ss->any = 1;
2291
2292           /* Send a signal to all clients who applied for it.  */
2293           send_client_notifications ();
2294         }
2295
2296       /* Check whether a disconnect is pending.  */
2297       if (opt.card_timeout)
2298         {
2299           for (sl=session_list; sl; sl = sl->next_session)
2300             if (!sl->disconnect_allowed)
2301               break;
2302           if (session_list && !sl)
2303             {
2304               /* FIXME: Use a real timeout.  */
2305               /* At least one connection and all allow a disconnect.  */
2306               log_info ("disconnecting card in slot %d\n", ss->slot);
2307               apdu_disconnect (ss->slot);
2308             }
2309         }
2310
2311     }
2312 }
2313
2314 /* This function is called by the ticker thread to check for changes
2315    of the reader stati.  It updates the reader status files and if
2316    requested by the caller also send a signal to the caller.  */
2317 void
2318 scd_update_reader_status_file (void)
2319 {
2320   if (!pth_mutex_acquire (&status_file_update_lock, 1, NULL))
2321     return; /* locked - give up. */
2322   update_reader_status_file (1);
2323   if (!pth_mutex_release (&status_file_update_lock))
2324     log_error ("failed to release status_file_update lock\n");
2325 }