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