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