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