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