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