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