70a4269592a8d4747d86f2cf694a56e2e4fe4f54
[gnupg.git] / scd / command.c
1 /* command.c - SCdaemon command handler
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
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 <assuan.h>
34
35 #include "scdaemon.h"
36 #include <ksba.h>
37 #include "app-common.h"
38 #include "apdu.h" /* Required for apdu_*_reader (). */
39
40 /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
41 #define MAXLEN_PIN 100
42
43 /* Maximum allowed size of key data as used in inquiries. */
44 #define MAXLEN_KEYDATA 4096
45
46
47 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
48
49
50 /* Macro to flag a removed card.  */
51 #define TEST_CARD_REMOVAL(c,r)                              \
52        do {                                                 \
53           int _r = (r);                                     \
54           if (gpg_err_code (_r) == GPG_ERR_CARD_NOT_PRESENT \
55               || gpg_err_code (_r) == GPG_ERR_CARD_REMOVED) \
56             update_card_removed ((c)->reader_slot, 1);      \
57        } while (0)
58
59 #define IS_LOCKED(c)                                                     \
60      (locked_session && locked_session != (c)->server_local              \
61       && (c)->reader_slot != -1 && locked_session->ctrl_backlink         \
62       && (c)->reader_slot == locked_session->ctrl_backlink->reader_slot)
63
64
65 /* This structure is used to keep track of open readers (slots). */
66 struct slot_status_s 
67 {
68   int valid;  /* True if the other objects are valid. */
69   int slot;   /* Slot number of the reader or -1 if not open. */
70
71   int reset_failed; /* A reset failed. */
72
73   int any;    /* Flag indicating whether any status check has been
74                  done.  This is set once to indicate that the status
75                  tracking for the slot has been initialized.  */
76   unsigned int status;  /* Last status of the slot. */
77   unsigned int changed; /* Last change counter of teh slot. */
78 };
79
80
81 /* Data used to associate an Assuan context with local server data.
82    This object describes the local properties of one session.  */
83 struct server_local_s 
84 {
85   /* We keep a list of all active sessions with the anchor at
86      SESSION_LIST (see below).  This field is used for linking. */
87   struct server_local_s *next_session; 
88
89   /* This object is usually assigned to a CTRL object (which is
90      globally visible).  While enumerating all sessions we sometimes
91      need to access data of the CTRL object; thus we keep a
92      backpointer here. */
93   ctrl_t ctrl_backlink;
94
95   /* The Assuan context used by this session/server. */
96   assuan_context_t assuan_ctx;
97
98   int event_signal;        /* Or 0 if not used. */
99
100   /* True if the card has been removed and a reset is required to
101      continue operation. */
102   int card_removed;        
103 };
104
105
106 /* The table with information on all used slots. */
107 static struct slot_status_s slot_table[10];
108
109
110 /* To keep track of all running sessions, we link all active server
111    contexts and the anchor in this variable.  */
112 static struct server_local_s *session_list;
113
114 /* If a session has been locked we store a link to its server object
115    in this variable. */
116 static struct server_local_s *locked_session;
117
118 /* While doing a reset we need to make sure that the ticker does not
119    call scd_update_reader_status_file while we are using it. */
120 static pth_mutex_t status_file_update_lock = PTH_MUTEX_INIT;
121
122 \f
123 /*-- Local prototypes --*/
124 static void update_reader_status_file (void);
125
126
127 \f
128 /* Update the CARD_REMOVED element of all sessions using the reader
129    given by SLOT to VALUE  */
130 static void
131 update_card_removed (int slot, int value)
132 {
133   struct server_local_s *sl;
134
135   for (sl=session_list; sl; sl = sl->next_session)
136     if (sl->ctrl_backlink
137         && sl->ctrl_backlink->reader_slot == slot)
138       {
139         sl->card_removed = value;
140       }
141   if (value)
142     application_notify_card_removed (slot);
143 }
144
145
146
147 /* Check whether the option NAME appears in LINE */
148 static int
149 has_option (const char *line, const char *name)
150 {
151   const char *s;
152   int n = strlen (name);
153
154   s = strstr (line, name);
155   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
156 }
157
158
159 /* Reset the card and free the application context.  With SEND_RESET
160    set to true actually send a RESET to the reader. */
161 static void
162 do_reset (ctrl_t ctrl, int send_reset)
163 {
164   int slot = ctrl->reader_slot;
165
166   if (!(slot == -1 || (slot >= 0 && slot < DIM(slot_table))))
167     BUG ();
168
169   if (ctrl->app_ctx)
170     {
171       release_application (ctrl->app_ctx);
172       ctrl->app_ctx = NULL;
173     }
174
175   if (slot != -1 && send_reset && !IS_LOCKED (ctrl) )
176     {
177       if (apdu_reset (slot)) 
178         {
179           slot_table[slot].reset_failed = 1;
180         }
181     }
182   ctrl->reader_slot = -1;
183
184   /* If we hold a lock, unlock now. */
185   if (locked_session && ctrl->server_local == locked_session)
186     {
187       locked_session = NULL;
188       log_info ("implicitly unlocking due to RESET\n");
189     }
190
191   /* Reset card removed flag for the current reader.  We need to take
192      the lock here so that the ticker thread won't concurrently try to
193      update the file.  Note that the update function will set the card
194      removed flag and we will later reset it - not a particualar nice
195      way of implementing it but it works. */
196   if (!pth_mutex_acquire (&status_file_update_lock, 0, NULL))
197     {
198       log_error ("failed to acquire status_fle_update lock\n");
199       return;
200     }
201   update_reader_status_file ();
202   update_card_removed (slot, 0);
203   if (!pth_mutex_release (&status_file_update_lock))
204     log_error ("failed to release status_file_update lock\n");
205 }
206
207 \f
208 static void
209 reset_notify (assuan_context_t ctx)
210 {
211   ctrl_t ctrl = assuan_get_pointer (ctx); 
212
213   do_reset (ctrl, 1);
214 }
215
216
217 static int
218 option_handler (assuan_context_t ctx, const char *key, const char *value)
219 {
220   ctrl_t ctrl = assuan_get_pointer (ctx);
221
222   if (!strcmp (key, "event-signal"))
223     {
224       /* A value of 0 is allowed to reset the event signal. */
225       int i = *value? atoi (value) : -1;
226       if (i < 0)
227         return ASSUAN_Parameter_Error;
228       ctrl->server_local->event_signal = i;
229     }
230
231  return 0;
232 }
233
234
235 /* Return the slot of the current reader or open the reader if no
236    other sessions are using a reader.  Note, that we currently support
237    only one reader but most of the code (except for this function)
238    should be able to cope with several readers.  */
239 static int
240 get_reader_slot (void)
241 {
242   struct slot_status_s *ss;
243
244   ss = &slot_table[0]; /* One reader for now. */
245
246   /* Initialize the item if needed. */
247   if (!ss->valid)
248     {
249       ss->slot = -1;
250       ss->valid = 1;
251     }
252
253   /* Try to open the reader. */
254   if (ss->slot == -1)
255     ss->slot = apdu_open_reader (opt.reader_port);
256
257   return ss->slot;
258 }
259
260 /* If the card has not yet been opened, do it.  Note that this
261    function returns an Assuan error, so don't map the error a second
262    time */
263 static assuan_error_t
264 open_card (ctrl_t ctrl, const char *apptype)
265 {
266   gpg_error_t err;
267   int slot;
268
269   /* If we ever got a card not present error code, return that.  Only
270      the SERIALNO command and a reset are able to clear from that
271      state. */
272   if (ctrl->server_local->card_removed)
273     return map_to_assuan_status (gpg_error (GPG_ERR_CARD_REMOVED));
274
275   if ( IS_LOCKED (ctrl) )
276     return gpg_error (GPG_ERR_LOCKED);
277
278   if (ctrl->app_ctx)
279     {
280       /* Already initialized for one specific application.  Need to
281          check that the client didn't requested a specific application
282          different from the one in use. */
283       return check_application_conflict (ctrl, apptype);
284     }
285
286   if (ctrl->reader_slot != -1)
287     slot = ctrl->reader_slot;
288   else
289     slot = get_reader_slot ();
290   ctrl->reader_slot = slot;
291   if (slot == -1)
292     err = gpg_error (GPG_ERR_CARD);
293   else
294     err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
295
296   TEST_CARD_REMOVAL (ctrl, err);
297   return map_to_assuan_status (err);
298 }
299
300
301 /* Do the percent and plus/space unescaping in place and return the
302    length of the valid buffer. */
303 static size_t
304 percent_plus_unescape (unsigned char *string)
305 {
306   unsigned char *p = string;
307   size_t n = 0;
308
309   while (*string)
310     {
311       if (*string == '%' && string[1] && string[2])
312         { 
313           string++;
314           *p++ = xtoi_2 (string);
315           n++;
316           string+= 2;
317         }
318       else if (*string == '+')
319         {
320           *p++ = ' ';
321           n++;
322           string++;
323         }
324       else
325         {
326           *p++ = *string++;
327           n++;
328         }
329     }
330
331   return n;
332 }
333
334
335
336 /* SERIALNO [APPTYPE] 
337
338    Return the serial number of the card using a status reponse.  This
339    functon should be used to check for the presence of a card.
340
341    If APPTYPE is given, an application of that type is selected and an
342    error is returned if the application is not supported or available.
343    The default is to auto-select the application using a hardwired
344    preference system.  Note, that a future extension to this function
345    may allow to specify a list and order of applications to try.
346
347    This function is special in that it can be used to reset the card.
348    Most other functions will return an error when a card change has
349    been detected and the use of this function is therefore required.
350
351    Background: We want to keep the client clear of handling card
352    changes between operations; i.e. the client can assume that all
353    operations are done on the same card unless he calls this function.
354  */
355 static int
356 cmd_serialno (assuan_context_t ctx, char *line)
357 {
358   ctrl_t ctrl = assuan_get_pointer (ctx);
359   int rc = 0;
360   char *serial_and_stamp;
361   char *serial;
362   time_t stamp;
363
364   /* Clear the remove flag so that the open_card is able to reread it.  */
365   if (ctrl->server_local->card_removed)
366     {
367       if ( IS_LOCKED (ctrl) )
368         return gpg_error (GPG_ERR_LOCKED);
369       do_reset (ctrl, 1);
370     }
371
372   if ((rc = open_card (ctrl, *line? line:NULL)))
373     return rc;
374
375   rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
376   if (rc)
377     return map_to_assuan_status (rc);
378
379   rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
380   xfree (serial);
381   if (rc < 0)
382     return ASSUAN_Out_Of_Core;
383   rc = 0;
384   assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
385   free (serial_and_stamp);
386   return 0;
387 }
388
389
390
391
392 /* LEARN [--force]
393
394    Learn all useful information of the currently inserted card.  When
395    used without the force options, the command might do an INQUIRE
396    like this:
397
398       INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
399
400    The client should just send an "END" if the processing should go on
401    or a "CANCEL" to force the function to terminate with a Cancel
402    error message.  The response of this command is a list of status
403    lines formatted as this:
404
405      S APPTYPE <apptype>
406
407    This returns the type of the application, currently the strings:
408
409        P15     = PKCS-15 structure used
410        DINSIG  = DIN SIG
411        OPENPGP = OpenPGP card
412  
413    are implemented.  These strings are aliases for the AID
414
415      S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
416
417    If there is no certificate yet stored on the card a single "X" is
418    returned as the keygrip.  In addition to the keypair info, information
419    about all certificates stored on the card is also returned:
420
421      S CERTINFO <certtype> <hexstring_with_id>
422
423    Where CERTTYPE is a number indicating the type of certificate:
424       0   := Unknown
425       100 := Regular X.509 cert
426       101 := Trusted X.509 cert
427       102 := Useful X.509 cert
428       110 := Root CA cert (DINSIG)
429
430    For certain cards, more information will be returned:
431
432      S KEY-FPR <no> <hexstring>
433
434    For OpenPGP cards this returns the stored fingerprints of the
435    keys. This can be used check whether a key is available on the
436    card.  NO may be 1, 2 or 3.
437
438      S CA-FPR <no> <hexstring>
439
440    Similar to above, these are the fingerprints of keys assumed to be
441    ultimately trusted.
442
443      S DISP-NAME <name_of_card_holder>
444
445    The name of the card holder as stored on the card; percent
446    escaping takes place, spaces are encoded as '+'
447
448      S PUBKEY-URL <url>
449
450    The URL to be used for locating the entire public key.
451      
452    Note, that this function may be even be used on a locked card.
453 */
454 static int
455 cmd_learn (assuan_context_t ctx, char *line)
456 {
457   ctrl_t ctrl = assuan_get_pointer (ctx);
458   int rc = 0;
459
460   if ((rc = open_card (ctrl, NULL)))
461     return rc;
462
463   /* Unless the force option is used we try a shortcut by identifying
464      the card using a serial number and inquiring the client with
465      that. The client may choose to cancel the operation if he already
466      knows about this card */
467   {
468     char *serial_and_stamp;
469     char *serial;
470     time_t stamp;
471
472     rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
473     if (rc)
474       return map_to_assuan_status (rc);
475     rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
476     xfree (serial);
477     if (rc < 0)
478       return ASSUAN_Out_Of_Core;
479     rc = 0;
480     assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
481
482     if (!has_option (line, "--force"))
483       {
484         char *command;
485
486         rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
487         if (rc < 0)
488           {
489             free (serial_and_stamp);
490             return ASSUAN_Out_Of_Core;
491           }
492         rc = 0;
493         rc = assuan_inquire (ctx, command, NULL, NULL, 0); 
494         free (command);  /* (must use standard free here) */
495         if (rc)
496           {
497             if (rc != ASSUAN_Canceled)
498               log_error ("inquire KNOWNCARDP failed: %s\n",
499                          assuan_strerror (rc));
500             free (serial_and_stamp);
501             return rc; 
502           }
503         /* not canceled, so we have to proceeed */
504       }
505     free (serial_and_stamp);
506   }
507
508   /* Let the application print out its collection of useful status
509      information. */
510   if (!rc)
511     rc = app_write_learn_status (ctrl->app_ctx, ctrl);
512
513   TEST_CARD_REMOVAL (ctrl, rc);
514   return map_to_assuan_status (rc);
515 }
516
517
518 \f
519 /* READCERT <hexified_certid>
520
521    Note, that this function may even be used on a locked card.
522  */
523 static int
524 cmd_readcert (assuan_context_t ctx, char *line)
525 {
526   ctrl_t ctrl = assuan_get_pointer (ctx);
527   int rc;
528   unsigned char *cert;
529   size_t ncert;
530
531   if ((rc = open_card (ctrl, NULL)))
532     return rc;
533
534   line = xstrdup (line); /* Need a copy of the line. */
535   rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
536   if (rc)
537     log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
538   xfree (line);
539   line = NULL;
540   if (!rc)
541     {
542       rc = assuan_send_data (ctx, cert, ncert);
543       xfree (cert);
544       if (rc)
545         return rc;
546     }
547
548   TEST_CARD_REMOVAL (ctrl, rc);
549   return map_to_assuan_status (rc);
550 }
551
552
553 /* READKEY <keyid>
554
555    Return the public key for the given cert or key ID as an standard
556    S-Expression.
557
558    Note, that this function may even be used on a locked card.
559   */
560 static int
561 cmd_readkey (assuan_context_t ctx, char *line)
562 {
563   ctrl_t ctrl = assuan_get_pointer (ctx);
564   int rc;
565   unsigned char *cert = NULL;
566   size_t ncert, n;
567   ksba_cert_t kc = NULL;
568   ksba_sexp_t p;
569   unsigned char *pk;
570   size_t pklen;
571
572   if ((rc = open_card (ctrl, NULL)))
573     return rc;
574
575   line = xstrdup (line); /* Need a copy of the line. */
576   /* If the application supports the READKEY function we use that.
577      Otherwise we use the old way by extracting it from the
578      certificate.  */
579   rc = app_readkey (ctrl->app_ctx, line, &pk, &pklen);
580   if (!rc)
581     { /* Yeah, got that key - send it back.  */
582       rc = assuan_send_data (ctx, pk, pklen);
583       xfree (pk);
584       rc = map_assuan_err (rc);
585       xfree (line);
586       line = NULL;
587       goto leave;
588     }
589
590   if (gpg_err_code (rc) != GPG_ERR_UNSUPPORTED_OPERATION)
591     log_error ("app_readkey failed: %s\n", gpg_strerror (rc));
592   else  
593     {
594       rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
595       if (rc)
596         log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
597     }
598   xfree (line);
599   line = NULL;
600   if (rc)
601     goto leave;
602       
603   rc = ksba_cert_new (&kc);
604   if (rc)
605     {
606       xfree (cert);
607       goto leave;
608     }
609   rc = ksba_cert_init_from_mem (kc, cert, ncert);
610   if (rc)
611     {
612       log_error ("failed to parse the certificate: %s\n", gpg_strerror (rc));
613       goto leave;
614     }
615
616   p = ksba_cert_get_public_key (kc);
617   if (!p)
618     {
619       rc = gpg_error (GPG_ERR_NO_PUBKEY);
620       goto leave;
621     }
622
623   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
624   rc = assuan_send_data (ctx, p, n);
625   rc = map_assuan_err (rc);
626   xfree (p);
627
628
629  leave:
630   ksba_cert_release (kc);
631   xfree (cert);
632   TEST_CARD_REMOVAL (ctrl, rc);
633   return map_to_assuan_status (rc);
634 }
635
636
637 \f
638
639 /* SETDATA <hexstring> 
640
641    The client should use this command to tell us the data he want to
642    sign.  */
643 static int
644 cmd_setdata (assuan_context_t ctx, char *line)
645 {
646   ctrl_t ctrl = assuan_get_pointer (ctx);
647   int n;
648   char *p;
649   unsigned char *buf;
650
651   if (locked_session && locked_session != ctrl->server_local)
652     return gpg_error (GPG_ERR_LOCKED);
653
654   /* Parse the hexstring. */
655   for (p=line,n=0; hexdigitp (p); p++, n++)
656     ;
657   if (*p)
658     return set_error (Parameter_Error, "invalid hexstring");
659   if (!n)
660     return set_error (Parameter_Error, "no data given");
661   if ((n&1))
662     return set_error (Parameter_Error, "odd number of digits");
663   n /= 2;
664   buf = xtrymalloc (n);
665   if (!buf)
666     return ASSUAN_Out_Of_Core;
667
668   ctrl->in_data.value = buf;
669   ctrl->in_data.valuelen = n;
670   for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
671     buf[n] = xtoi_2 (p);
672   return 0;
673 }
674
675
676
677 static gpg_error_t 
678 pin_cb (void *opaque, const char *info, char **retstr)
679 {
680   assuan_context_t ctx = opaque;
681   char *command;
682   int rc;
683   unsigned char *value;
684   size_t valuelen;
685
686   *retstr = NULL;
687   log_debug ("asking for PIN '%s'\n", info);
688
689   rc = asprintf (&command, "NEEDPIN %s", info);
690   if (rc < 0)
691     return gpg_error (gpg_err_code_from_errno (errno));
692
693   /* Fixme: Write an inquire function which returns the result in
694      secure memory and check all further handling of the PIN. */
695   rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
696   free (command);  
697   if (rc)
698     return map_assuan_err (rc);
699
700   if (!valuelen || value[valuelen-1])
701     {
702       /* We require that the returned value is an UTF-8 string */
703       xfree (value);
704       return gpg_error (GPG_ERR_INV_RESPONSE);
705     }
706   *retstr = (char*)value;
707   return 0;
708 }
709
710
711 /* PKSIGN [--hash=[rmd160|sha1|md5]] <hexified_id>
712
713    The --hash option is optional; the default is SHA1.
714
715  */
716 static int
717 cmd_pksign (assuan_context_t ctx, char *line)
718 {
719   ctrl_t ctrl = assuan_get_pointer (ctx);
720   int rc;
721   unsigned char *outdata;
722   size_t outdatalen;
723   char *keyidstr;
724   int hash_algo;
725
726   if (has_option (line, "--hash=rmd160"))
727     hash_algo = GCRY_MD_RMD160;
728   else if (has_option (line, "--hash=sha1"))
729     hash_algo = GCRY_MD_SHA1;
730   else if (has_option (line, "--hash=md5"))
731     hash_algo = GCRY_MD_MD5;
732   else if (!strstr (line, "--"))
733     hash_algo = GCRY_MD_SHA1; 
734   else
735     return set_error (Parameter_Error, "invalid hash algorithm");
736   /* Skip over options. */
737   while ( *line == '-' && line[1] == '-' )
738     {
739       while (*line && !spacep (line))
740         line++;
741       while (spacep (line))
742         line++;
743     }
744
745   if ( IS_LOCKED (ctrl) )
746     return gpg_error (GPG_ERR_LOCKED);
747
748   if ((rc = open_card (ctrl, NULL)))
749     return rc;
750
751   /* We have to use a copy of the key ID because the function may use
752      the pin_cb which in turn uses the assuan line buffer and thus
753      overwriting the original line with the keyid */
754   keyidstr = xtrystrdup (line);
755   if (!keyidstr)
756     return ASSUAN_Out_Of_Core;
757   
758   rc = app_sign (ctrl->app_ctx,
759                  keyidstr, hash_algo,
760                  pin_cb, ctx,
761                  ctrl->in_data.value, ctrl->in_data.valuelen,
762                  &outdata, &outdatalen);
763
764   xfree (keyidstr);
765   if (rc)
766     {
767       log_error ("card_sign failed: %s\n", gpg_strerror (rc));
768     }
769   else
770     {
771       rc = assuan_send_data (ctx, outdata, outdatalen);
772       xfree (outdata);
773       if (rc)
774         return rc; /* that is already an assuan error code */
775     }
776
777   TEST_CARD_REMOVAL (ctrl, rc);
778   return map_to_assuan_status (rc);
779 }
780
781 /* PKAUTH <hexified_id>
782
783  */
784 static int
785 cmd_pkauth (assuan_context_t ctx, char *line)
786 {
787   ctrl_t ctrl = assuan_get_pointer (ctx);
788   int rc;
789   unsigned char *outdata;
790   size_t outdatalen;
791   char *keyidstr;
792
793   if ( IS_LOCKED (ctrl) )
794     return gpg_error (GPG_ERR_LOCKED);
795
796   if ((rc = open_card (ctrl, NULL)))
797     return rc;
798
799   if (!ctrl->app_ctx)
800     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
801
802  /* We have to use a copy of the key ID because the function may use
803      the pin_cb which in turn uses the assuan line buffer and thus
804      overwriting the original line with the keyid */
805   keyidstr = xtrystrdup (line);
806   if (!keyidstr)
807     return ASSUAN_Out_Of_Core;
808   
809   rc = app_auth (ctrl->app_ctx,
810                  keyidstr,
811                  pin_cb, ctx,
812                  ctrl->in_data.value, ctrl->in_data.valuelen,
813                  &outdata, &outdatalen);
814   xfree (keyidstr);
815   if (rc)
816     {
817       log_error ("app_auth_sign failed: %s\n", gpg_strerror (rc));
818     }
819   else
820     {
821       rc = assuan_send_data (ctx, outdata, outdatalen);
822       xfree (outdata);
823       if (rc)
824         return rc; /* that is already an assuan error code */
825     }
826
827   TEST_CARD_REMOVAL (ctrl, rc);
828   return map_to_assuan_status (rc);
829 }
830
831 /* PKDECRYPT <hexified_id>
832
833  */
834 static int
835 cmd_pkdecrypt (assuan_context_t ctx, char *line)
836 {
837   ctrl_t ctrl = assuan_get_pointer (ctx);
838   int rc;
839   unsigned char *outdata;
840   size_t outdatalen;
841   char *keyidstr;
842
843   if ( IS_LOCKED (ctrl) )
844     return gpg_error (GPG_ERR_LOCKED);
845
846   if ((rc = open_card (ctrl, NULL)))
847     return rc;
848
849   keyidstr = xtrystrdup (line);
850   if (!keyidstr)
851     return ASSUAN_Out_Of_Core;
852   rc = app_decipher (ctrl->app_ctx,
853                      keyidstr, 
854                      pin_cb, ctx,
855                      ctrl->in_data.value, ctrl->in_data.valuelen,
856                      &outdata, &outdatalen);
857
858   xfree (keyidstr);
859   if (rc)
860     {
861       log_error ("card_create_signature failed: %s\n", gpg_strerror (rc));
862     }
863   else
864     {
865       rc = assuan_send_data (ctx, outdata, outdatalen);
866       xfree (outdata);
867       if (rc)
868         return rc; /* that is already an assuan error code */
869     }
870
871   TEST_CARD_REMOVAL (ctrl, rc);
872   return map_to_assuan_status (rc);
873 }
874
875
876 /* GETATTR <name>
877
878    This command is used to retrieve data from a smartcard.  The
879    allowed names depend on the currently selected smartcard
880    application.  NAME must be percent and '+' escaped.  The value is
881    returned through status message, see the LEARN command for details.
882
883    However, the current implementation assumes that Name is not escaped;
884    this works as long as noone uses arbitrary escaping. 
885  
886    Note, that this function may even be used on a locked card.
887 */
888 static int
889 cmd_getattr (assuan_context_t ctx, char *line)
890 {
891   ctrl_t ctrl = assuan_get_pointer (ctx);
892   int rc;
893   const char *keyword;
894
895   if ((rc = open_card (ctrl, NULL)))
896     return rc;
897
898   keyword = line;
899   for (; *line && !spacep (line); line++)
900     ;
901   if (*line)
902       *line++ = 0;
903
904   /* (We ignore any garbage for now.) */
905
906   /* FIXME: Applications should not return sensistive data if the card
907      is locked.  */
908   rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
909
910   TEST_CARD_REMOVAL (ctrl, rc);
911   return map_to_assuan_status (rc);
912 }
913
914
915 /* SETATTR <name> <value> 
916
917    This command is used to store data on a a smartcard.  The allowed
918    names and values are depend on the currently selected smartcard
919    application.  NAME and VALUE must be percent and '+' escaped.
920
921    However, the curent implementation assumes that Name is not escaped;
922    this works as long as noone uses arbitrary escaping. 
923  
924    A PIN will be requested for most NAMEs.  See the corresponding
925    setattr function of the actually used application (app-*.c) for
926    details.  */
927 static int
928 cmd_setattr (assuan_context_t ctx, char *orig_line)
929 {
930   ctrl_t ctrl = assuan_get_pointer (ctx);
931   int rc;
932   char *keyword;
933   int keywordlen;
934   size_t nbytes;
935   char *line, *linebuf;
936
937   if ( IS_LOCKED (ctrl) )
938     return gpg_error (GPG_ERR_LOCKED);
939
940   if ((rc = open_card (ctrl, NULL)))
941     return rc;
942
943   /* We need to use a copy of LINE, because PIN_CB uses the same
944      context and thus reuses the Assuan provided LINE. */
945   line = linebuf = xtrystrdup (orig_line);
946   if (!line)
947     return ASSUAN_Out_Of_Core;
948
949   keyword = line;
950   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
951     ;
952   if (*line)
953       *line++ = 0;
954   while (spacep (line))
955     line++;
956   nbytes = percent_plus_unescape ((unsigned char*)line);
957
958   rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx,
959                     (const unsigned char*)line, nbytes);
960   xfree (linebuf);
961
962   TEST_CARD_REMOVAL (ctrl, rc);
963   return map_to_assuan_status (rc);
964 }
965
966
967
968 /* WRITEKEY [--force] <keyid> 
969
970    This command is used to store a secret key on a a smartcard.  The
971    allowed keyids depend on the currently selected smartcard
972    application. The actual keydata is requested using the inquiry
973    "KETDATA" and need to be provided without any protection.  With
974    --force set an existing key under this KEYID will get overwritten.
975    The keydata is expected to be the usual canonical encoded
976    S-expression.
977
978    A PIN will be requested for most NAMEs.  See the corresponding
979    writekey function of the actually used application (app-*.c) for
980    details.  */
981 static int
982 cmd_writekey (assuan_context_t ctx, char *line)
983 {
984   ctrl_t ctrl = assuan_get_pointer (ctx);
985   int rc;
986   char *keyid;
987   int force = has_option (line, "--force");
988   unsigned char *keydata;
989   size_t keydatalen;
990
991   if ( IS_LOCKED (ctrl) )
992     return gpg_error (GPG_ERR_LOCKED);
993
994   /* Skip over options. */
995   while ( *line == '-' && line[1] == '-' )
996     {
997       while (*line && !spacep (line))
998         line++;
999       while (spacep (line))
1000         line++;
1001     }
1002   if (!*line)
1003     return set_error (Parameter_Error, "no keyid given");
1004   keyid = line;
1005   while (*line && !spacep (line))
1006     line++;
1007   *line = 0;
1008
1009   if ((rc = open_card (ctrl, NULL)))
1010     return rc;
1011
1012   if (!ctrl->app_ctx)
1013     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1014
1015   keyid = xtrystrdup (keyid);
1016   if (!keyid)
1017     return ASSUAN_Out_Of_Core;
1018
1019   /* Now get the actual keydata. */
1020   rc = assuan_inquire (ctx, "KEYDATA", &keydata, &keydatalen, MAXLEN_KEYDATA);
1021   if (rc)
1022     {
1023       xfree (keyid);
1024       return rc;
1025     }
1026
1027   /* Write the key to the card. */
1028   rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0,
1029                      pin_cb, ctx, keydata, keydatalen);
1030   xfree (keyid);
1031   xfree (keydata);
1032
1033   TEST_CARD_REMOVAL (ctrl, rc);
1034   return map_to_assuan_status (rc);
1035 }
1036
1037
1038
1039 /* GENKEY [--force] <no>
1040
1041    Generate a key on-card identified by NO, which is application
1042    specific.  Return values are application specific.  For OpenPGP
1043    cards 2 status lines are returned:
1044
1045      S KEY-FPR  <hexstring>
1046      S KEY-CREATED-AT <seconds_since_epoch>
1047      S KEY-DATA [p|n] <hexdata>
1048      
1049
1050    --force is required to overwrite an already existing key.  The
1051    KEY-CREATED-AT is required for further processing because it is
1052    part of the hashed key material for the fingerprint.
1053
1054    The public part of the key can also later be retrieved using the
1055    READKEY command.
1056
1057  */
1058 static int
1059 cmd_genkey (assuan_context_t ctx, char *line)
1060 {
1061   ctrl_t ctrl = assuan_get_pointer (ctx);
1062   int rc;
1063   char *keyno;
1064   int force = has_option (line, "--force");
1065
1066   if ( IS_LOCKED (ctrl) )
1067     return gpg_error (GPG_ERR_LOCKED);
1068
1069   /* Skip over options. */
1070   while ( *line == '-' && line[1] == '-' )
1071     {
1072       while (*line && !spacep (line))
1073         line++;
1074       while (spacep (line))
1075         line++;
1076     }
1077   if (!*line)
1078     return set_error (Parameter_Error, "no key number given");
1079   keyno = line;
1080   while (*line && !spacep (line))
1081     line++;
1082   *line = 0;
1083
1084   if ((rc = open_card (ctrl, NULL)))
1085     return rc;
1086
1087   if (!ctrl->app_ctx)
1088     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1089
1090   keyno = xtrystrdup (keyno);
1091   if (!keyno)
1092     return ASSUAN_Out_Of_Core;
1093   rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx);
1094   xfree (keyno);
1095
1096   TEST_CARD_REMOVAL (ctrl, rc);
1097   return map_to_assuan_status (rc);
1098 }
1099
1100
1101 /* RANDOM <nbytes>
1102
1103    Get NBYTES of random from the card and send them back as data. 
1104
1105    Note, that this function may be even be used on a locked card.
1106 */
1107 static int
1108 cmd_random (assuan_context_t ctx, char *line)
1109 {
1110   ctrl_t ctrl = assuan_get_pointer (ctx);
1111   int rc;
1112   size_t nbytes;
1113   unsigned char *buffer;
1114
1115   if (!*line)
1116     return set_error (Parameter_Error, "number of requested bytes missing");
1117   nbytes = strtoul (line, NULL, 0);
1118
1119   if ((rc = open_card (ctrl, NULL)))
1120     return rc;
1121
1122   if (!ctrl->app_ctx)
1123     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1124
1125   buffer = xtrymalloc (nbytes);
1126   if (!buffer)
1127     return ASSUAN_Out_Of_Core;
1128
1129   rc = app_get_challenge (ctrl->app_ctx, nbytes, buffer);
1130   if (!rc)
1131     {
1132       rc = assuan_send_data (ctx, buffer, nbytes);
1133       xfree (buffer);
1134       return rc; /* that is already an assuan error code */
1135     }
1136   xfree (buffer);
1137
1138   TEST_CARD_REMOVAL (ctrl, rc);
1139   return map_to_assuan_status (rc);
1140 }
1141
1142 \f
1143 /* PASSWD [--reset] <chvno>
1144   
1145    Change the PIN or reset the retry counter of the card holder
1146    verfication vector CHVNO. */
1147 static int
1148 cmd_passwd (assuan_context_t ctx, char *line)
1149 {
1150   ctrl_t ctrl = assuan_get_pointer (ctx);
1151   int rc;
1152   char *chvnostr;
1153   int reset_mode = has_option (line, "--reset");
1154
1155   if ( IS_LOCKED (ctrl) )
1156     return gpg_error (GPG_ERR_LOCKED);
1157
1158   /* Skip over options. */
1159   while (*line == '-' && line[1] == '-')
1160     {
1161       while (*line && !spacep (line))
1162         line++;
1163       while (spacep (line))
1164         line++;
1165     }
1166   if (!*line)
1167     return set_error (Parameter_Error, "no CHV number given");
1168   chvnostr = line;
1169   while (*line && !spacep (line))
1170     line++;
1171   *line = 0;
1172
1173   if ((rc = open_card (ctrl, NULL)))
1174     return rc;
1175
1176   if (!ctrl->app_ctx)
1177     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1178   
1179   chvnostr = xtrystrdup (chvnostr);
1180   if (!chvnostr)
1181     return ASSUAN_Out_Of_Core;
1182   rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, reset_mode, pin_cb, ctx);
1183   if (rc)
1184     log_error ("command passwd failed: %s\n", gpg_strerror (rc));
1185   xfree (chvnostr);
1186
1187   TEST_CARD_REMOVAL (ctrl, rc);
1188   return map_to_assuan_status (rc);
1189 }
1190
1191
1192 /* CHECKPIN <idstr>
1193
1194    Perform a VERIFY operation without doing anything else.  This may
1195    be used to initialize a the PIN cache earlier to long lasting
1196    operations.  Its use is highly application dependent.
1197
1198    For OpenPGP:
1199
1200       Perform a simple verify operation for CHV1 and CHV2, so that
1201       further operations won't ask for CHV2 and it is possible to do a
1202       cheap check on the PIN: If there is something wrong with the PIN
1203       entry system, only the regular CHV will get blocked and not the
1204       dangerous CHV3.  IDSTR is the usual card's serial number in hex
1205       notation; an optional fingerprint part will get ignored.  There
1206       is however a special mode if the IDSTR is sffixed with the
1207       literal string "[CHV3]": In this case the Admin PIN is checked
1208       if and only if the retry counter is still at 3.
1209
1210  */
1211 static int
1212 cmd_checkpin (assuan_context_t ctx, char *line)
1213 {
1214   ctrl_t ctrl = assuan_get_pointer (ctx);
1215   int rc;
1216   char *keyidstr;
1217
1218   if ( IS_LOCKED (ctrl) )
1219     return gpg_error (GPG_ERR_LOCKED);
1220
1221   if ((rc = open_card (ctrl, NULL)))
1222     return rc;
1223
1224   if (!ctrl->app_ctx)
1225     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1226
1227   /* We have to use a copy of the key ID because the function may use
1228      the pin_cb which in turn uses the assuan line buffer and thus
1229      overwriting the original line with the keyid. */
1230   keyidstr = xtrystrdup (line);
1231   if (!keyidstr)
1232     return ASSUAN_Out_Of_Core;
1233   
1234   rc = app_check_pin (ctrl->app_ctx,
1235                       keyidstr,
1236                       pin_cb, ctx);
1237   xfree (keyidstr);
1238   if (rc)
1239     log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
1240
1241   TEST_CARD_REMOVAL (ctrl, rc);
1242   return map_to_assuan_status (rc);
1243 }
1244
1245
1246 /* LOCK [--wait]
1247
1248    Grant exclusive card access to this session.  Note that there is
1249    no lock counter used and a second lock from the same session will
1250    be ignored.  A single unlock (or RESET) unlocks the session.
1251    Return GPG_ERR_LOCKED if another session has locked the reader.
1252
1253    If the option --wait is given the command will wait until a
1254    lock has been released.
1255  */
1256 static int
1257 cmd_lock (assuan_context_t ctx, char *line)
1258 {
1259   ctrl_t ctrl = assuan_get_pointer (ctx);
1260   int rc = 0;
1261
1262  retry:
1263   if (locked_session)
1264     {
1265       if (locked_session != ctrl->server_local)
1266         rc = gpg_error (GPG_ERR_LOCKED);
1267     }
1268   else
1269     locked_session = ctrl->server_local;
1270
1271 #ifdef USE_GNU_PTH
1272   if (rc && has_option (line, "--wait"))
1273     {
1274       rc = 0;
1275       pth_sleep (1); /* Better implement an event mechanism. However,
1276                         for card operations this should be
1277                         sufficient. */
1278       /* FIXME: Need to check that the connection is still alive.
1279          This can be done by issuing status messages. */
1280       goto retry;
1281     }
1282 #endif /*USE_GNU_PTH*/
1283   
1284   if (rc)
1285     log_error ("cmd_lock failed: %s\n", gpg_strerror (rc));
1286   return map_to_assuan_status (rc);
1287 }
1288
1289
1290 /* UNLOCK
1291
1292    Release exclusive card access.
1293  */
1294 static int
1295 cmd_unlock (assuan_context_t ctx, char *line)
1296 {
1297   ctrl_t ctrl = assuan_get_pointer (ctx);
1298   int rc = 0;
1299
1300   if (locked_session)
1301     {
1302       if (locked_session != ctrl->server_local)
1303         rc = gpg_error (GPG_ERR_LOCKED);
1304       else
1305         locked_session = NULL;
1306     }
1307   else
1308     rc = gpg_error (GPG_ERR_NOT_LOCKED);
1309
1310   if (rc)
1311     log_error ("cmd_unlock failed: %s\n", gpg_strerror (rc));
1312   return map_to_assuan_status (rc);
1313 }
1314
1315
1316 /* GETINFO <what>
1317
1318    Multi purpose command to return certain information.  
1319    Supported values of WHAT are:
1320
1321    socket_name - Return the name of the socket.
1322
1323 */
1324
1325 static int
1326 cmd_getinfo (assuan_context_t ctx, char *line)
1327 {
1328   int rc = 0;
1329
1330   if (!strcmp (line, "socket_name"))
1331     {
1332       const char *s = scd_get_socket_name ();
1333
1334       if (s)
1335         rc = assuan_send_data (ctx, s, strlen (s));
1336       else
1337         rc = gpg_error (GPG_ERR_NO_DATA);
1338     }
1339   else
1340     rc = set_error (Parameter_Error, "unknown value for WHAT");
1341   return rc;
1342 }
1343
1344
1345 /* RESTART
1346
1347    Restart the current connection; this is a kind of warm reset.  It
1348    deletes the context used by this connection but does not send a
1349    RESET to the card.  Thus the card itself won't get reset. 
1350
1351    This is used by gpg-agent to reuse a primary pipe connection and
1352    may be used by clients to backup from a conflict in the serial
1353    command; i.e. to select another application. 
1354 */
1355
1356 static int
1357 cmd_restart (assuan_context_t ctx, char *line)
1358 {
1359   ctrl_t ctrl = assuan_get_pointer (ctx);
1360
1361   if (ctrl->app_ctx)
1362     {
1363       release_application (ctrl->app_ctx);
1364       ctrl->app_ctx = NULL;
1365     }
1366   if (locked_session && ctrl->server_local == locked_session)
1367     {
1368       locked_session = NULL;
1369       log_info ("implicitly unlocking due to RESTART\n");
1370     }
1371   return 0;
1372 }
1373
1374
1375
1376 \f
1377 /* Tell the assuan library about our commands */
1378 static int
1379 register_commands (assuan_context_t ctx)
1380 {
1381   static struct {
1382     const char *name;
1383     int (*handler)(assuan_context_t, char *line);
1384   } table[] = {
1385     { "SERIALNO",     cmd_serialno },
1386     { "LEARN",        cmd_learn },
1387     { "READCERT",     cmd_readcert },
1388     { "READKEY",      cmd_readkey },
1389     { "SETDATA",      cmd_setdata },
1390     { "PKSIGN",       cmd_pksign },
1391     { "PKAUTH",       cmd_pkauth },
1392     { "PKDECRYPT",    cmd_pkdecrypt },
1393     { "INPUT",        NULL }, 
1394     { "OUTPUT",       NULL }, 
1395     { "GETATTR",      cmd_getattr },
1396     { "SETATTR",      cmd_setattr },
1397     { "WRITEKEY",     cmd_writekey },
1398     { "GENKEY",       cmd_genkey },
1399     { "RANDOM",       cmd_random },
1400     { "PASSWD",       cmd_passwd },
1401     { "CHECKPIN",     cmd_checkpin },
1402     { "LOCK",         cmd_lock },
1403     { "UNLOCK",       cmd_unlock },
1404     { "GETINFO",      cmd_getinfo },
1405     { "RESTART",      cmd_restart },
1406     { NULL }
1407   };
1408   int i, rc;
1409
1410   for (i=0; table[i].name; i++)
1411     {
1412       rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1413       if (rc)
1414         return rc;
1415     } 
1416   assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
1417
1418   assuan_register_reset_notify (ctx, reset_notify);
1419   assuan_register_option_handler (ctx, option_handler);
1420   return 0;
1421 }
1422
1423
1424 /* Startup the server.  If FD is given as -1 this is simple pipe
1425    server, otherwise it is a regular server. */
1426 void
1427 scd_command_handler (int fd)
1428 {
1429   int rc;
1430   assuan_context_t ctx;
1431   struct server_control_s ctrl;
1432
1433   memset (&ctrl, 0, sizeof ctrl);
1434   scd_init_default_ctrl (&ctrl);
1435   
1436   if (fd == -1)
1437     {
1438       int filedes[2];
1439
1440       filedes[0] = 0;
1441       filedes[1] = 1;
1442       rc = assuan_init_pipe_server (&ctx, filedes);
1443     }
1444   else
1445     {
1446       rc = assuan_init_connected_socket_server (&ctx, fd);
1447     }
1448   if (rc)
1449     {
1450       log_error ("failed to initialize the server: %s\n",
1451                  assuan_strerror(rc));
1452       scd_exit (2);
1453     }
1454   rc = register_commands (ctx);
1455   if (rc)
1456     {
1457       log_error ("failed to register commands with Assuan: %s\n",
1458                  assuan_strerror(rc));
1459       scd_exit (2);
1460     }
1461   assuan_set_pointer (ctx, &ctrl);
1462
1463   /* Allocate and initialize the server object.  Put it into the list
1464      of active sessions. */
1465   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1466   ctrl.server_local->next_session = session_list;
1467   session_list = ctrl.server_local;
1468   ctrl.server_local->ctrl_backlink = &ctrl;
1469   ctrl.server_local->assuan_ctx = ctx;
1470
1471   if (DBG_ASSUAN)
1472     assuan_set_log_stream (ctx, log_get_stream ());
1473
1474   /* We open the reader right at startup so that the ticker is able to
1475      update the status file. */
1476   if (ctrl.reader_slot == -1)
1477     {
1478       ctrl.reader_slot = get_reader_slot ();
1479     }
1480
1481   /* Command processing loop. */
1482   for (;;)
1483     {
1484       rc = assuan_accept (ctx);
1485       if (rc == -1)
1486         {
1487           break;
1488         }
1489       else if (rc)
1490         {
1491           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
1492           break;
1493         }
1494       
1495       rc = assuan_process (ctx);
1496       if (rc)
1497         {
1498           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
1499           continue;
1500         }
1501     }
1502
1503   /* Cleanup.  */
1504   do_reset (&ctrl, 0); 
1505
1506   /* Release the server object.  */
1507   if (session_list == ctrl.server_local)
1508     session_list = ctrl.server_local->next_session;
1509   else
1510     {
1511       struct server_local_s *sl;
1512       
1513       for (sl=session_list; sl->next_session; sl = sl->next_session)
1514         if (sl->next_session == ctrl.server_local)
1515           break;
1516       if (!sl->next_session)
1517           BUG ();
1518       sl->next_session = ctrl.server_local->next_session;
1519     }
1520   xfree (ctrl.server_local);
1521
1522   /* Release the Assuan context.  */
1523   assuan_deinit_server (ctx);
1524 }
1525
1526
1527 /* Send a line with status information via assuan and escape all given
1528    buffers. The variable elements are pairs of (char *, size_t),
1529    terminated with a (NULL, 0). */
1530 void
1531 send_status_info (ctrl_t ctrl, const char *keyword, ...)
1532 {
1533   va_list arg_ptr;
1534   const unsigned char *value;
1535   size_t valuelen;
1536   char buf[950], *p;
1537   size_t n;
1538   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1539   
1540   va_start (arg_ptr, keyword);
1541
1542   p = buf; 
1543   n = 0;
1544   while ( (value = va_arg (arg_ptr, const unsigned char *)) )
1545     {
1546       valuelen = va_arg (arg_ptr, size_t);
1547       if (!valuelen)
1548         continue; /* empty buffer */
1549       if (n)
1550         {
1551           *p++ = ' ';
1552           n++;
1553         }
1554       for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
1555         {
1556           if (*value < ' ' || *value == '+')
1557             {
1558               sprintf (p, "%%%02X", *value);
1559               p += 3;
1560             }
1561           else if (*value == ' ')
1562             *p++ = '+';
1563           else
1564             *p++ = *value;
1565         }
1566     }
1567   *p = 0;
1568   assuan_write_status (ctx, keyword, buf);
1569
1570   va_end (arg_ptr);
1571 }
1572
1573
1574 /* This is the core of scd_update_reader_status_file but the caller
1575    needs to take care of the locking. */
1576 static void
1577 update_reader_status_file (void)
1578 {
1579   int idx;
1580   unsigned int status, changed;
1581
1582   /* Note, that we only try to get the status, because it does not
1583      make sense to wait here for a operation to complete.  If we are
1584      busy working with a card, delays in the status file update should
1585      be acceptable. */
1586   for (idx=0; idx < DIM(slot_table); idx++)
1587     {
1588       struct slot_status_s *ss = slot_table + idx;
1589
1590       if (!ss->valid || ss->slot == -1)
1591         continue; /* Not valid or reader not yet open. */
1592       
1593       if ( apdu_get_status (ss->slot, 0, &status, &changed) )
1594         continue; /* Get status failed. */
1595
1596       if (!ss->any || ss->status != status || ss->changed != changed )
1597         {
1598           char *fname;
1599           char templ[50];
1600           FILE *fp;
1601           struct server_local_s *sl;
1602
1603           log_info ("updating status of slot %d to 0x%04X\n",
1604                     ss->slot, status);
1605             
1606           sprintf (templ, "reader_%d.status", ss->slot);
1607           fname = make_filename (opt.homedir, templ, NULL );
1608           fp = fopen (fname, "w");
1609           if (fp)
1610             {
1611               fprintf (fp, "%s\n",
1612                        (status & 1)? "USABLE":
1613                        (status & 4)? "ACTIVE":
1614                        (status & 2)? "PRESENT": "NOCARD");
1615               fclose (fp);
1616             }
1617           xfree (fname);
1618             
1619           /* Set the card removed flag for all current sessions.  We
1620              will set this on any card change because a reset or
1621              SERIALNO request must be done in any case.  */
1622           if (ss->any)
1623             update_card_removed (ss->slot, 1);
1624           
1625           ss->any = 1;
1626           ss->status = status;
1627           ss->changed = changed;
1628
1629           /* Send a signal to all clients who applied for it.  */
1630           for (sl=session_list; sl; sl = sl->next_session)
1631             if (sl->event_signal && sl->assuan_ctx)
1632               {
1633                 pid_t pid = assuan_get_pid (sl->assuan_ctx);
1634                 int signo = sl->event_signal;
1635                 
1636                 log_info ("client pid is %d, sending signal %d\n",
1637                           pid, signo);
1638 #ifndef HAVE_W32_SYSTEM
1639                 if (pid != (pid_t)(-1) && pid && signo > 0)
1640                   kill (pid, signo);
1641 #endif
1642               }
1643         }
1644     }
1645 }
1646
1647 /* This function is called by the ticker thread to check for changes
1648    of the reader stati.  It updates the reader status files and if
1649    requested by the caller also send a signal to the caller.  */
1650 void
1651 scd_update_reader_status_file (void)
1652 {
1653   if (!pth_mutex_acquire (&status_file_update_lock, 1, NULL))
1654     return; /* locked - give up. */
1655   update_reader_status_file ();
1656   if (!pth_mutex_release (&status_file_update_lock))
1657     log_error ("failed to release status_file_update lock\n");
1658 }