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