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