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