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