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