1 /* command.c - SCdaemon command handler
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005,
3 * 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <https://www.gnu.org/licenses/>.
36 #include "app-common.h"
38 #include "apdu.h" /* Required for apdu_*_reader (). */
41 #include "ccid-driver.h"
43 #include "../common/asshelp.h"
44 #include "../common/server-help.h"
46 /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
47 #define MAXLEN_PIN 100
49 /* Maximum allowed size of key data as used in inquiries. */
50 #define MAXLEN_KEYDATA 4096
52 /* Maximum allowed total data size for SETDATA. */
53 #define MAXLEN_SETDATA 4096
55 /* Maximum allowed size of certificate data as used in inquiries. */
56 #define MAXLEN_CERTDATA 16384
59 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
61 #define IS_LOCKED(c) (locked_session && locked_session != (c)->server_local)
64 /* Data used to associate an Assuan context with local server data.
65 This object describes the local properties of one session. */
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;
72 /* This object is usually assigned to a CTRL object (which is
73 globally visible). While enumerating all sessions we sometimes
74 need to access data of the CTRL object; thus we keep a
78 /* The Assuan context used by this session/server. */
79 assuan_context_t assuan_ctx;
81 #ifdef HAVE_W32_SYSTEM
82 void *event_signal; /* Or NULL if not used. */
84 int event_signal; /* Or 0 if not used. */
87 /* True if the card has been removed and a reset is required to
88 continue operation. */
91 /* If set to true we will be terminate ourself at the end of the
98 /* To keep track of all running sessions, we link all active server
99 contexts and the anchor in this variable. */
100 static struct server_local_s *session_list;
102 /* If a session has been locked we store a link to its server object
104 static struct server_local_s *locked_session;
107 /* Convert the STRING into a newly allocated buffer while translating
108 the hex numbers. Stops at the first invalid character. Blanks and
109 colons are allowed to separate the hex digits. Returns NULL on
110 error or a newly malloced buffer and its length in LENGTH. */
111 static unsigned char *
112 hex_to_buffer (const char *string, size_t *r_length)
114 unsigned char *buffer;
118 buffer = xtrymalloc (strlen (string)+1);
121 for (s=string, n=0; *s; s++)
123 if (spacep (s) || *s == ':')
125 if (hexdigitp (s) && hexdigitp (s+1))
127 buffer[n++] = xtoi_2 (s);
139 /* Reset the card and free the application context. With SEND_RESET
140 set to true actually send a RESET to the reader; this is the normal
141 way of calling the function. */
143 do_reset (ctrl_t ctrl, int send_reset)
145 app_t app = ctrl->app_ctx;
148 app_reset (app, ctrl, IS_LOCKED (ctrl)? 0: send_reset);
150 /* If we hold a lock, unlock now. */
151 if (locked_session && ctrl->server_local == locked_session)
153 locked_session = NULL;
154 log_info ("implicitly unlocking due to RESET\n");
159 reset_notify (assuan_context_t ctx, char *line)
161 ctrl_t ctrl = assuan_get_pointer (ctx);
171 option_handler (assuan_context_t ctx, const char *key, const char *value)
173 ctrl_t ctrl = assuan_get_pointer (ctx);
175 if (!strcmp (key, "event-signal"))
177 /* A value of 0 is allowed to reset the event signal. */
178 #ifdef HAVE_W32_SYSTEM
180 return gpg_error (GPG_ERR_ASS_PARAMETER);
182 ctrl->server_local->event_signal = (void *)strtoull (value, NULL, 16);
184 ctrl->server_local->event_signal = (void *)strtoul (value, NULL, 16);
187 int i = *value? atoi (value) : -1;
189 return gpg_error (GPG_ERR_ASS_PARAMETER);
190 ctrl->server_local->event_signal = i;
198 /* If the card has not yet been opened, do it. */
200 open_card (ctrl_t ctrl)
202 /* If we ever got a card not present error code, return that. Only
203 the SERIALNO command and a reset are able to clear from that
205 if (ctrl->server_local->card_removed)
206 return gpg_error (GPG_ERR_CARD_REMOVED);
208 if ( IS_LOCKED (ctrl) )
209 return gpg_error (GPG_ERR_LOCKED);
214 return select_application (ctrl, NULL, &ctrl->app_ctx, 0, NULL, 0);
217 /* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */
219 open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno)
222 unsigned char *serialno_bin = NULL;
223 size_t serialno_bin_len = 0;
224 app_t app = ctrl->app_ctx;
226 /* If we are already initialized for one specific application we
227 need to check that the client didn't requested a specific
228 application different from the one in use before we continue. */
229 if (apptype && ctrl->app_ctx)
230 return check_application_conflict (apptype, ctrl->app_ctx);
232 /* Re-scan USB devices. Release APP, before the scan. */
233 ctrl->app_ctx = NULL;
234 release_application (app, 0);
237 serialno_bin = hex_to_buffer (serialno, &serialno_bin_len);
239 err = select_application (ctrl, apptype, &ctrl->app_ctx, 1,
240 serialno_bin, serialno_bin_len);
241 xfree (serialno_bin);
247 static const char hlp_serialno[] =
248 "SERIALNO [--demand=<serialno>] [<apptype>]\n"
250 "Return the serial number of the card using a status response. This\n"
251 "function should be used to check for the presence of a card.\n"
253 "If --demand is given, an application on the card with SERIALNO is\n"
254 "selected and an error is returned if no such card available.\n"
256 "If APPTYPE is given, an application of that type is selected and an\n"
257 "error is returned if the application is not supported or available.\n"
258 "The default is to auto-select the application using a hardwired\n"
259 "preference system. Note, that a future extension to this function\n"
260 "may enable specifying a list and order of applications to try.\n"
262 "This function is special in that it can be used to reset the card.\n"
263 "Most other functions will return an error when a card change has\n"
264 "been detected and the use of this function is therefore required.\n"
266 "Background: We want to keep the client clear of handling card\n"
267 "changes between operations; i.e. the client can assume that all\n"
268 "operations are done on the same card unless he calls this function.";
270 cmd_serialno (assuan_context_t ctx, char *line)
272 ctrl_t ctrl = assuan_get_pointer (ctx);
273 struct server_local_s *sl;
278 if ( IS_LOCKED (ctrl) )
279 return gpg_error (GPG_ERR_LOCKED);
281 if ((demand = has_option_name (line, "--demand")))
284 return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
285 line = (char *)++demand;
286 for (; *line && !spacep (line); line++)
294 /* Clear the remove flag so that the open_card is able to reread it. */
295 if (ctrl->server_local->card_removed)
296 ctrl->server_local->card_removed = 0;
298 if ((rc = open_card_with_request (ctrl, *line? line:NULL, demand)))
300 ctrl->server_local->card_removed = 1;
304 /* Success, clear the card_removed flag for all sessions. */
305 for (sl=session_list; sl; sl = sl->next_session)
307 ctrl_t c = sl->ctrl_backlink;
310 c->server_local->card_removed = 0;
313 serial = app_get_serialno (ctrl->app_ctx);
315 return gpg_error (GPG_ERR_INV_VALUE);
317 rc = assuan_write_status (ctx, "SERIALNO", serial);
323 static const char hlp_learn[] =
324 "LEARN [--force] [--keypairinfo]\n"
326 "Learn all useful information of the currently inserted card. When\n"
327 "used without the force options, the command might do an INQUIRE\n"
330 " INQUIRE KNOWNCARDP <hexstring_with_serialNumber>\n"
332 "The client should just send an \"END\" if the processing should go on\n"
333 "or a \"CANCEL\" to force the function to terminate with a Cancel\n"
336 "With the option --keypairinfo only KEYPARIINFO lstatus lines are\n"
339 "The response of this command is a list of status lines formatted as\n"
342 " S APPTYPE <apptype>\n"
344 "This returns the type of the application, currently the strings:\n"
346 " P15 = PKCS-15 structure used\n"
347 " DINSIG = DIN SIG\n"
348 " OPENPGP = OpenPGP card\n"
349 " NKS = NetKey card\n"
351 "are implemented. These strings are aliases for the AID\n"
353 " S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>\n"
355 "If there is no certificate yet stored on the card a single 'X' is\n"
356 "returned as the keygrip. In addition to the keypair info, information\n"
357 "about all certificates stored on the card is also returned:\n"
359 " S CERTINFO <certtype> <hexstring_with_id>\n"
361 "Where CERTTYPE is a number indicating the type of certificate:\n"
363 " 100 := Regular X.509 cert\n"
364 " 101 := Trusted X.509 cert\n"
365 " 102 := Useful X.509 cert\n"
366 " 110 := Root CA cert in a special format (e.g. DINSIG)\n"
367 " 111 := Root CA cert as standard X509 cert.\n"
369 "For certain cards, more information will be returned:\n"
371 " S KEY-FPR <no> <hexstring>\n"
373 "For OpenPGP cards this returns the stored fingerprints of the\n"
374 "keys. This can be used check whether a key is available on the\n"
375 "card. NO may be 1, 2 or 3.\n"
377 " S CA-FPR <no> <hexstring>\n"
379 "Similar to above, these are the fingerprints of keys assumed to be\n"
380 "ultimately trusted.\n"
382 " S DISP-NAME <name_of_card_holder>\n"
384 "The name of the card holder as stored on the card; percent\n"
385 "escaping takes place, spaces are encoded as '+'\n"
387 " S PUBKEY-URL <url>\n"
389 "The URL to be used for locating the entire public key.\n"
391 "Note, that this function may even be used on a locked card.";
393 cmd_learn (assuan_context_t ctx, char *line)
395 ctrl_t ctrl = assuan_get_pointer (ctx);
397 int only_keypairinfo = has_option (line, "--keypairinfo");
399 if ((rc = open_card (ctrl)))
402 /* Unless the force option is used we try a shortcut by identifying
403 the card using a serial number and inquiring the client with
404 that. The client may choose to cancel the operation if he already
405 knows about this card */
406 if (!only_keypairinfo)
410 app_t app = ctrl->app_ctx;
413 return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
415 reader = apdu_get_reader_name (app->slot);
417 return out_of_core ();
418 send_status_direct (ctrl, "READER", reader);
419 /* No need to free the string of READER. */
421 serial = app_get_serialno (ctrl->app_ctx);
423 return gpg_error (GPG_ERR_INV_VALUE);
425 rc = assuan_write_status (ctx, "SERIALNO", serial);
429 return out_of_core ();
432 if (!has_option (line, "--force"))
436 rc = gpgrt_asprintf (&command, "KNOWNCARDP %s", serial);
440 return out_of_core ();
442 rc = assuan_inquire (ctx, command, NULL, NULL, 0);
446 if (gpg_err_code (rc) != GPG_ERR_ASS_CANCELED)
447 log_error ("inquire KNOWNCARDP failed: %s\n",
452 /* Not canceled, so we have to proceed. */
457 /* Let the application print out its collection of useful status
460 rc = app_write_learn_status (ctrl->app_ctx, ctrl, only_keypairinfo);
467 static const char hlp_readcert[] =
468 "READCERT <hexified_certid>|<keyid>\n"
470 "Note, that this function may even be used on a locked card.";
472 cmd_readcert (assuan_context_t ctx, char *line)
474 ctrl_t ctrl = assuan_get_pointer (ctx);
479 if ((rc = open_card (ctrl)))
482 line = xstrdup (line); /* Need a copy of the line. */
483 rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert);
485 log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
490 rc = assuan_send_data (ctx, cert, ncert);
500 static const char hlp_readkey[] =
501 "READKEY [--advanced] <keyid>\n"
503 "Return the public key for the given cert or key ID as a standard\n"
505 "In --advanced mode it returns the S-expression in advanced format.\n"
507 "Note that this function may even be used on a locked card.";
509 cmd_readkey (assuan_context_t ctx, char *line)
511 ctrl_t ctrl = assuan_get_pointer (ctx);
514 unsigned char *cert = NULL;
516 ksba_cert_t kc = NULL;
521 if ((rc = open_card (ctrl)))
524 if (has_option (line, "--advanced"))
527 line = skip_options (line);
529 line = xstrdup (line); /* Need a copy of the line. */
530 /* If the application supports the READKEY function we use that.
531 Otherwise we use the old way by extracting it from the
533 rc = app_readkey (ctrl->app_ctx, ctrl, advanced, line, &pk, &pklen);
535 { /* Yeah, got that key - send it back. */
536 rc = assuan_send_data (ctx, pk, pklen);
543 if (gpg_err_code (rc) != GPG_ERR_UNSUPPORTED_OPERATION)
544 log_error ("app_readkey failed: %s\n", gpg_strerror (rc));
547 rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert);
549 log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
556 rc = ksba_cert_new (&kc);
560 rc = ksba_cert_init_from_mem (kc, cert, ncert);
563 log_error ("failed to parse the certificate: %s\n", gpg_strerror (rc));
567 p = ksba_cert_get_public_key (kc);
570 rc = gpg_error (GPG_ERR_NO_PUBKEY);
574 n = gcry_sexp_canon_len (p, 0, NULL, NULL);
575 rc = assuan_send_data (ctx, p, n);
580 ksba_cert_release (kc);
587 static const char hlp_setdata[] =
588 "SETDATA [--append] <hexstring>\n"
590 "The client should use this command to tell us the data he want to sign.\n"
591 "With the option --append, the data is appended to the data set by a\n"
592 "previous SETDATA command.";
594 cmd_setdata (assuan_context_t ctx, char *line)
596 ctrl_t ctrl = assuan_get_pointer (ctx);
602 append = (ctrl->in_data.value && has_option (line, "--append"));
604 line = skip_options (line);
606 if (locked_session && locked_session != ctrl->server_local)
607 return gpg_error (GPG_ERR_LOCKED);
609 /* Parse the hexstring. */
610 for (p=line,n=0; hexdigitp (p); p++, n++)
613 return set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
615 return set_error (GPG_ERR_ASS_PARAMETER, "no data given");
617 return set_error (GPG_ERR_ASS_PARAMETER, "odd number of digits");
621 if (ctrl->in_data.valuelen + n > MAXLEN_SETDATA)
622 return set_error (GPG_ERR_TOO_LARGE,
623 "limit on total size of data reached");
624 buf = xtrymalloc (ctrl->in_data.valuelen + n);
627 buf = xtrymalloc (n);
629 return out_of_core ();
633 memcpy (buf, ctrl->in_data.value, ctrl->in_data.valuelen);
634 off = ctrl->in_data.valuelen;
638 for (p=line, i=0; i < n; p += 2, i++)
639 buf[off+i] = xtoi_2 (p);
641 xfree (ctrl->in_data.value);
642 ctrl->in_data.value = buf;
643 ctrl->in_data.valuelen = off+n;
650 pin_cb (void *opaque, const char *info, char **retstr)
652 assuan_context_t ctx = opaque;
655 unsigned char *value;
660 /* We prompt for pinpad entry. To make sure that the popup has
661 been show we use an inquire and not just a status message.
662 We ignore any value returned. */
665 log_debug ("prompting for pinpad entry '%s'\n", info);
666 rc = gpgrt_asprintf (&command, "POPUPPINPADPROMPT %s", info);
668 return gpg_error (gpg_err_code_from_errno (errno));
669 rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN);
674 log_debug ("dismiss pinpad entry prompt\n");
675 rc = assuan_inquire (ctx, "DISMISSPINPADPROMPT",
676 &value, &valuelen, MAXLEN_PIN);
684 log_debug ("asking for PIN '%s'\n", info);
686 rc = gpgrt_asprintf (&command, "NEEDPIN %s", info);
688 return gpg_error (gpg_err_code_from_errno (errno));
690 /* Fixme: Write an inquire function which returns the result in
691 secure memory and check all further handling of the PIN. */
692 rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN);
697 if (!valuelen || value[valuelen-1])
699 /* We require that the returned value is an UTF-8 string */
701 return gpg_error (GPG_ERR_INV_RESPONSE);
703 *retstr = (char*)value;
708 static const char hlp_pksign[] =
709 "PKSIGN [--hash=[rmd160|sha{1,224,256,384,512}|md5]] <hexified_id>\n"
711 "The --hash option is optional; the default is SHA1.";
713 cmd_pksign (assuan_context_t ctx, char *line)
715 ctrl_t ctrl = assuan_get_pointer (ctx);
717 unsigned char *outdata;
722 if (has_option (line, "--hash=rmd160"))
723 hash_algo = GCRY_MD_RMD160;
724 else if (has_option (line, "--hash=sha1"))
725 hash_algo = GCRY_MD_SHA1;
726 else if (has_option (line, "--hash=sha224"))
727 hash_algo = GCRY_MD_SHA224;
728 else if (has_option (line, "--hash=sha256"))
729 hash_algo = GCRY_MD_SHA256;
730 else if (has_option (line, "--hash=sha384"))
731 hash_algo = GCRY_MD_SHA384;
732 else if (has_option (line, "--hash=sha512"))
733 hash_algo = GCRY_MD_SHA512;
734 else if (has_option (line, "--hash=md5"))
735 hash_algo = GCRY_MD_MD5;
736 else if (!strstr (line, "--"))
737 hash_algo = GCRY_MD_SHA1;
739 return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
741 line = skip_options (line);
743 if ((rc = open_card (ctrl)))
746 /* We have to use a copy of the key ID because the function may use
747 the pin_cb which in turn uses the assuan line buffer and thus
748 overwriting the original line with the keyid */
749 keyidstr = xtrystrdup (line);
751 return out_of_core ();
753 rc = app_sign (ctrl->app_ctx, ctrl,
756 ctrl->in_data.value, ctrl->in_data.valuelen,
757 &outdata, &outdatalen);
762 log_error ("app_sign failed: %s\n", gpg_strerror (rc));
766 rc = assuan_send_data (ctx, outdata, outdatalen);
769 return rc; /* that is already an assuan error code */
776 static const char hlp_pkauth[] =
777 "PKAUTH <hexified_id>";
779 cmd_pkauth (assuan_context_t ctx, char *line)
781 ctrl_t ctrl = assuan_get_pointer (ctx);
783 unsigned char *outdata;
787 if ((rc = open_card (ctrl)))
791 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
793 /* We have to use a copy of the key ID because the function may use
794 the pin_cb which in turn uses the assuan line buffer and thus
795 overwriting the original line with the keyid */
796 keyidstr = xtrystrdup (line);
798 return out_of_core ();
800 rc = app_auth (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx,
801 ctrl->in_data.value, ctrl->in_data.valuelen,
802 &outdata, &outdatalen);
806 log_error ("app_auth failed: %s\n", gpg_strerror (rc));
810 rc = assuan_send_data (ctx, outdata, outdatalen);
813 return rc; /* that is already an assuan error code */
820 static const char hlp_pkdecrypt[] =
821 "PKDECRYPT <hexified_id>";
823 cmd_pkdecrypt (assuan_context_t ctx, char *line)
825 ctrl_t ctrl = assuan_get_pointer (ctx);
827 unsigned char *outdata;
830 unsigned int infoflags;
832 if ((rc = open_card (ctrl)))
835 keyidstr = xtrystrdup (line);
837 return out_of_core ();
838 rc = app_decipher (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx,
839 ctrl->in_data.value, ctrl->in_data.valuelen,
840 &outdata, &outdatalen, &infoflags);
845 log_error ("app_decipher failed: %s\n", gpg_strerror (rc));
849 /* If the card driver told us that there is no padding, send a
850 status line. If there is a padding it is assumed that the
851 caller knows what padding is used. It would have been better
852 to always send that information but for backward
853 compatibility we can't do that. */
854 if ((infoflags & APP_DECIPHER_INFO_NOPAD))
855 send_status_direct (ctrl, "PADDING", "0");
856 rc = assuan_send_data (ctx, outdata, outdatalen);
859 return rc; /* that is already an assuan error code */
866 static const char hlp_getattr[] =
869 "This command is used to retrieve data from a smartcard. The\n"
870 "allowed names depend on the currently selected smartcard\n"
871 "application. NAME must be percent and '+' escaped. The value is\n"
872 "returned through status message, see the LEARN command for details.\n"
874 "However, the current implementation assumes that Name is not escaped;\n"
875 "this works as long as no one uses arbitrary escaping. \n"
877 "Note, that this function may even be used on a locked card.";
879 cmd_getattr (assuan_context_t ctx, char *line)
881 ctrl_t ctrl = assuan_get_pointer (ctx);
885 if ((rc = open_card (ctrl)))
889 for (; *line && !spacep (line); line++)
894 /* (We ignore any garbage for now.) */
896 /* FIXME: Applications should not return sensitive data if the card
898 rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
904 static const char hlp_setattr[] =
905 "SETATTR <name> <value> \n"
907 "This command is used to store data on a smartcard. The allowed\n"
908 "names and values are depend on the currently selected smartcard\n"
909 "application. NAME and VALUE must be percent and '+' escaped.\n"
911 "However, the current implementation assumes that NAME is not\n"
912 "escaped; this works as long as no one uses arbitrary escaping.\n"
914 "A PIN will be requested for most NAMEs. See the corresponding\n"
915 "setattr function of the actually used application (app-*.c) for\n"
918 cmd_setattr (assuan_context_t ctx, char *orig_line)
920 ctrl_t ctrl = assuan_get_pointer (ctx);
925 char *line, *linebuf;
927 if ((rc = open_card (ctrl)))
930 /* We need to use a copy of LINE, because PIN_CB uses the same
931 context and thus reuses the Assuan provided LINE. */
932 line = linebuf = xtrystrdup (orig_line);
934 return out_of_core ();
937 for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
941 while (spacep (line))
943 nbytes = percent_plus_unescape_inplace (line, 0);
945 rc = app_setattr (ctrl->app_ctx, ctrl, keyword, pin_cb, ctx,
946 (const unsigned char*)line, nbytes);
953 static const char hlp_writecert[] =
954 "WRITECERT <hexified_certid>\n"
956 "This command is used to store a certifciate on a smartcard. The\n"
957 "allowed certids depend on the currently selected smartcard\n"
958 "application. The actual certifciate is requested using the inquiry\n"
959 "\"CERTDATA\" and needs to be provided in its raw (e.g. DER) form.\n"
961 "In almost all cases a PIN will be requested. See the related\n"
962 "writecert function of the actually used application (app-*.c) for\n"
965 cmd_writecert (assuan_context_t ctx, char *line)
967 ctrl_t ctrl = assuan_get_pointer (ctx);
970 unsigned char *certdata;
973 line = skip_options (line);
976 return set_error (GPG_ERR_ASS_PARAMETER, "no certid given");
978 while (*line && !spacep (line))
982 if ((rc = open_card (ctrl)))
986 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
988 certid = xtrystrdup (certid);
990 return out_of_core ();
992 /* Now get the actual keydata. */
993 rc = assuan_inquire (ctx, "CERTDATA",
994 &certdata, &certdatalen, MAXLEN_CERTDATA);
1001 /* Write the certificate to the card. */
1002 rc = app_writecert (ctrl->app_ctx, ctrl, certid,
1003 pin_cb, ctx, certdata, certdatalen);
1011 static const char hlp_writekey[] =
1012 "WRITEKEY [--force] <keyid> \n"
1014 "This command is used to store a secret key on a smartcard. The\n"
1015 "allowed keyids depend on the currently selected smartcard\n"
1016 "application. The actual keydata is requested using the inquiry\n"
1017 "\"KEYDATA\" and need to be provided without any protection. With\n"
1018 "--force set an existing key under this KEYID will get overwritten.\n"
1019 "The keydata is expected to be the usual canonical encoded\n"
1022 "A PIN will be requested for most NAMEs. See the corresponding\n"
1023 "writekey function of the actually used application (app-*.c) for\n"
1026 cmd_writekey (assuan_context_t ctx, char *line)
1028 ctrl_t ctrl = assuan_get_pointer (ctx);
1031 int force = has_option (line, "--force");
1032 unsigned char *keydata;
1035 line = skip_options (line);
1038 return set_error (GPG_ERR_ASS_PARAMETER, "no keyid given");
1040 while (*line && !spacep (line))
1044 if ((rc = open_card (ctrl)))
1048 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1050 keyid = xtrystrdup (keyid);
1052 return out_of_core ();
1054 /* Now get the actual keydata. */
1055 assuan_begin_confidential (ctx);
1056 rc = assuan_inquire (ctx, "KEYDATA", &keydata, &keydatalen, MAXLEN_KEYDATA);
1057 assuan_end_confidential (ctx);
1064 /* Write the key to the card. */
1065 rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0,
1066 pin_cb, ctx, keydata, keydatalen);
1074 static const char hlp_genkey[] =
1075 "GENKEY [--force] [--timestamp=<isodate>] <no>\n"
1077 "Generate a key on-card identified by NO, which is application\n"
1078 "specific. Return values are application specific. For OpenPGP\n"
1079 "cards 3 status lines are returned:\n"
1081 " S KEY-FPR <hexstring>\n"
1082 " S KEY-CREATED-AT <seconds_since_epoch>\n"
1083 " S KEY-DATA [-|p|n] <hexdata>\n"
1085 " 'p' and 'n' are the names of the RSA parameters; '-' is used to\n"
1086 " indicate that HEXDATA is the first chunk of a parameter given\n"
1087 " by the next KEY-DATA.\n"
1089 "--force is required to overwrite an already existing key. The\n"
1090 "KEY-CREATED-AT is required for further processing because it is\n"
1091 "part of the hashed key material for the fingerprint.\n"
1093 "If --timestamp is given an OpenPGP key will be created using this\n"
1094 "value. The value needs to be in ISO Format; e.g.\n"
1095 "\"--timestamp=20030316T120000\" and after 1970-01-01 00:00:00.\n"
1097 "The public part of the key can also later be retrieved using the\n"
1100 cmd_genkey (assuan_context_t ctx, char *line)
1102 ctrl_t ctrl = assuan_get_pointer (ctx);
1109 force = has_option (line, "--force");
1111 if ((s=has_option_name (line, "--timestamp")))
1114 return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
1115 timestamp = isotime2epoch (s+1);
1117 return set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
1123 line = skip_options (line);
1125 return set_error (GPG_ERR_ASS_PARAMETER, "no key number given");
1127 while (*line && !spacep (line))
1131 if ((rc = open_card (ctrl)))
1135 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1137 keyno = xtrystrdup (keyno);
1139 return out_of_core ();
1140 rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0,
1141 timestamp, pin_cb, ctx);
1148 static const char hlp_random[] =
1151 "Get NBYTES of random from the card and send them back as data.\n"
1152 "This usually involves EEPROM write on the card and thus excessive\n"
1153 "use of this command may destroy the card.\n"
1155 "Note, that this function may be even be used on a locked card.";
1157 cmd_random (assuan_context_t ctx, char *line)
1159 ctrl_t ctrl = assuan_get_pointer (ctx);
1162 unsigned char *buffer;
1165 return set_error (GPG_ERR_ASS_PARAMETER,
1166 "number of requested bytes missing");
1167 nbytes = strtoul (line, NULL, 0);
1169 if ((rc = open_card (ctrl)))
1173 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1175 buffer = xtrymalloc (nbytes);
1177 return out_of_core ();
1179 rc = app_get_challenge (ctrl->app_ctx, ctrl, nbytes, buffer);
1182 rc = assuan_send_data (ctx, buffer, nbytes);
1184 return rc; /* that is already an assuan error code */
1193 static const char hlp_passwd[] =
1194 "PASSWD [--reset] [--nullpin] <chvno>\n"
1196 "Change the PIN or, if --reset is given, reset the retry counter of\n"
1197 "the card holder verification vector CHVNO. The option --nullpin is\n"
1198 "used for TCOS cards to set the initial PIN. The format of CHVNO\n"
1199 "depends on the card application.";
1201 cmd_passwd (assuan_context_t ctx, char *line)
1203 ctrl_t ctrl = assuan_get_pointer (ctx);
1206 unsigned int flags = 0;
1208 if (has_option (line, "--reset"))
1209 flags |= APP_CHANGE_FLAG_RESET;
1210 if (has_option (line, "--nullpin"))
1211 flags |= APP_CHANGE_FLAG_NULLPIN;
1213 line = skip_options (line);
1216 return set_error (GPG_ERR_ASS_PARAMETER, "no CHV number given");
1218 while (*line && !spacep (line))
1222 if ((rc = open_card (ctrl)))
1226 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1228 chvnostr = xtrystrdup (chvnostr);
1230 return out_of_core ();
1231 rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
1233 log_error ("command passwd failed: %s\n", gpg_strerror (rc));
1240 static const char hlp_checkpin[] =
1241 "CHECKPIN <idstr>\n"
1243 "Perform a VERIFY operation without doing anything else. This may\n"
1244 "be used to initialize a the PIN cache earlier to long lasting\n"
1245 "operations. Its use is highly application dependent.\n"
1249 " Perform a simple verify operation for CHV1 and CHV2, so that\n"
1250 " further operations won't ask for CHV2 and it is possible to do a\n"
1251 " cheap check on the PIN: If there is something wrong with the PIN\n"
1252 " entry system, only the regular CHV will get blocked and not the\n"
1253 " dangerous CHV3. IDSTR is the usual card's serial number in hex\n"
1254 " notation; an optional fingerprint part will get ignored. There\n"
1255 " is however a special mode if the IDSTR is sffixed with the\n"
1256 " literal string \"[CHV3]\": In this case the Admin PIN is checked\n"
1257 " if and only if the retry counter is still at 3.\n"
1261 " Any of the valid PIN Ids may be used. These are the strings:\n"
1263 " PW1.CH - Global password 1\n"
1264 " PW2.CH - Global password 2\n"
1265 " PW1.CH.SIG - SigG password 1\n"
1266 " PW2.CH.SIG - SigG password 2\n"
1268 " For a definitive list, see the implementation in app-nks.c.\n"
1269 " Note that we call a PW2.* PIN a \"PUK\" despite that since TCOS\n"
1270 " 3.0 they are technically alternative PINs used to mutally\n"
1271 " unblock each other.";
1273 cmd_checkpin (assuan_context_t ctx, char *line)
1275 ctrl_t ctrl = assuan_get_pointer (ctx);
1279 if ((rc = open_card (ctrl)))
1283 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1285 /* We have to use a copy of the key ID because the function may use
1286 the pin_cb which in turn uses the assuan line buffer and thus
1287 overwriting the original line with the keyid. */
1288 idstr = xtrystrdup (line);
1290 return out_of_core ();
1292 rc = app_check_pin (ctrl->app_ctx, ctrl, idstr, pin_cb, ctx);
1295 log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
1301 static const char hlp_lock[] =
1304 "Grant exclusive card access to this session. Note that there is\n"
1305 "no lock counter used and a second lock from the same session will\n"
1306 "be ignored. A single unlock (or RESET) unlocks the session.\n"
1307 "Return GPG_ERR_LOCKED if another session has locked the reader.\n"
1309 "If the option --wait is given the command will wait until a\n"
1310 "lock has been released.";
1312 cmd_lock (assuan_context_t ctx, char *line)
1314 ctrl_t ctrl = assuan_get_pointer (ctx);
1320 if (locked_session != ctrl->server_local)
1321 rc = gpg_error (GPG_ERR_LOCKED);
1324 locked_session = ctrl->server_local;
1327 if (rc && has_option (line, "--wait"))
1330 npth_sleep (1); /* Better implement an event mechanism. However,
1331 for card operations this should be
1333 /* FIXME: Need to check that the connection is still alive.
1334 This can be done by issuing status messages. */
1340 log_error ("cmd_lock failed: %s\n", gpg_strerror (rc));
1345 static const char hlp_unlock[] =
1348 "Release exclusive card access.";
1350 cmd_unlock (assuan_context_t ctx, char *line)
1352 ctrl_t ctrl = assuan_get_pointer (ctx);
1359 if (locked_session != ctrl->server_local)
1360 rc = gpg_error (GPG_ERR_LOCKED);
1362 locked_session = NULL;
1365 rc = gpg_error (GPG_ERR_NOT_LOCKED);
1368 log_error ("cmd_unlock failed: %s\n", gpg_strerror (rc));
1373 static const char hlp_getinfo[] =
1376 "Multi purpose command to return certain information. \n"
1377 "Supported values of WHAT are:\n"
1379 " version - Return the version of the program.\n"
1380 " pid - Return the process id of the server.\n"
1381 " socket_name - Return the name of the socket.\n"
1382 " connections - Return number of active connections.\n"
1383 " status - Return the status of the current reader (in the future,\n"
1384 " may also return the status of all readers). The status\n"
1385 " is a list of one-character flags. The following flags\n"
1386 " are currently defined:\n"
1387 " 'u' Usable card present.\n"
1388 " 'r' Card removed. A reset is necessary.\n"
1389 " These flags are exclusive.\n"
1390 " reader_list - Return a list of detected card readers. Does\n"
1391 " currently only work with the internal CCID driver.\n"
1392 " deny_admin - Returns OK if admin commands are not allowed or\n"
1393 " GPG_ERR_GENERAL if admin commands are allowed.\n"
1394 " app_list - Return a list of supported applications. One\n"
1395 " application per line, fields delimited by colons,\n"
1396 " first field is the name.\n"
1397 " card_list - Return a list of serial numbers of active cards,\n"
1398 " using a status response.";
1400 cmd_getinfo (assuan_context_t ctx, char *line)
1404 if (!strcmp (line, "version"))
1406 const char *s = VERSION;
1407 rc = assuan_send_data (ctx, s, strlen (s));
1409 else if (!strcmp (line, "pid"))
1413 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1414 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1416 else if (!strcmp (line, "socket_name"))
1418 const char *s = scd_get_socket_name ();
1421 rc = assuan_send_data (ctx, s, strlen (s));
1423 rc = gpg_error (GPG_ERR_NO_DATA);
1425 else if (!strcmp (line, "connections"))
1429 snprintf (numbuf, sizeof numbuf, "%d", get_active_connection_count ());
1430 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1432 else if (!strcmp (line, "status"))
1434 ctrl_t ctrl = assuan_get_pointer (ctx);
1437 if (open_card (ctrl))
1442 rc = assuan_send_data (ctx, &flag, 1);
1444 else if (!strcmp (line, "reader_list"))
1447 char *s = ccid_get_reader_list ();
1453 rc = assuan_send_data (ctx, s, strlen (s));
1455 rc = gpg_error (GPG_ERR_NO_DATA);
1458 else if (!strcmp (line, "deny_admin"))
1459 rc = opt.allow_admin? gpg_error (GPG_ERR_GENERAL) : 0;
1460 else if (!strcmp (line, "app_list"))
1462 char *s = get_supported_applications ();
1464 rc = assuan_send_data (ctx, s, strlen (s));
1469 else if (!strcmp (line, "card_list"))
1471 ctrl_t ctrl = assuan_get_pointer (ctx);
1473 app_send_card_list (ctrl);
1476 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1481 static const char hlp_restart[] =
1484 "Restart the current connection; this is a kind of warm reset. It\n"
1485 "deletes the context used by this connection but does not send a\n"
1486 "RESET to the card. Thus the card itself won't get reset. \n"
1488 "This is used by gpg-agent to reuse a primary pipe connection and\n"
1489 "may be used by clients to backup from a conflict in the serial\n"
1490 "command; i.e. to select another application.";
1492 cmd_restart (assuan_context_t ctx, char *line)
1494 ctrl_t ctrl = assuan_get_pointer (ctx);
1495 app_t app = ctrl->app_ctx;
1501 ctrl->app_ctx = NULL;
1502 release_application (app, 0);
1504 if (locked_session && ctrl->server_local == locked_session)
1506 locked_session = NULL;
1507 log_info ("implicitly unlocking due to RESTART\n");
1513 static const char hlp_disconnect[] =
1516 "Disconnect the card if the backend supports a disconnect operation.";
1518 cmd_disconnect (assuan_context_t ctx, char *line)
1520 ctrl_t ctrl = assuan_get_pointer (ctx);
1525 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1527 apdu_disconnect (ctrl->app_ctx->slot);
1533 static const char hlp_apdu[] =
1534 "APDU [--[dump-]atr] [--more] [--exlen[=N]] [hexstring]\n"
1536 "Send an APDU to the current reader. This command bypasses the high\n"
1537 "level functions and sends the data directly to the card. HEXSTRING\n"
1538 "is expected to be a proper APDU. If HEXSTRING is not given no\n"
1539 "commands are set to the card but the command will implictly check\n"
1540 "whether the card is ready for use. \n"
1542 "Using the option \"--atr\" returns the ATR of the card as a status\n"
1543 "message before any data like this:\n"
1544 " S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1\n"
1546 "Using the option --more handles the card status word MORE_DATA\n"
1547 "(61xx) and concatenates all responses to one block.\n"
1549 "Using the option \"--exlen\" the returned APDU may use extended\n"
1550 "length up to N bytes. If N is not given a default value is used\n"
1551 "(currently 4096).";
1553 cmd_apdu (assuan_context_t ctx, char *line)
1555 ctrl_t ctrl = assuan_get_pointer (ctx);
1558 unsigned char *apdu;
1565 if (has_option (line, "--dump-atr"))
1568 with_atr = has_option (line, "--atr");
1569 handle_more = has_option (line, "--more");
1571 if ((s=has_option_name (line, "--exlen")))
1574 exlen = strtoul (s+1, NULL, 0);
1581 line = skip_options (line);
1583 if ((rc = open_card (ctrl)))
1586 app = ctrl->app_ctx;
1588 return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
1596 atr = apdu_get_atr (app->slot, &atrlen);
1597 if (!atr || atrlen > sizeof hexbuf - 2 )
1599 rc = gpg_error (GPG_ERR_INV_CARD);
1604 char *string, *p, *pend;
1606 string = atr_dump (atr, atrlen);
1609 for (rc=0, p=string; !rc && (pend = strchr (p, '\n')); p = pend+1)
1611 rc = assuan_send_data (ctx, p, pend - p + 1);
1613 rc = assuan_send_data (ctx, NULL, 0);
1616 rc = assuan_send_data (ctx, p, strlen (p));
1624 bin2hex (atr, atrlen, hexbuf);
1625 send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
1630 apdu = hex_to_buffer (line, &apdulen);
1633 rc = gpg_error_from_syserror ();
1638 unsigned char *result = NULL;
1641 rc = apdu_send_direct (app->slot, exlen,
1642 apdu, apdulen, handle_more,
1643 &result, &resultlen);
1645 log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));
1648 rc = assuan_send_data (ctx, result, resultlen);
1659 static const char hlp_killscd[] =
1664 cmd_killscd (assuan_context_t ctx, char *line)
1666 ctrl_t ctrl = assuan_get_pointer (ctx);
1670 ctrl->server_local->stopme = 1;
1671 assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
1677 /* Tell the assuan library about our commands */
1679 register_commands (assuan_context_t ctx)
1683 assuan_handler_t handler;
1684 const char * const help;
1686 { "SERIALNO", cmd_serialno, hlp_serialno },
1687 { "LEARN", cmd_learn, hlp_learn },
1688 { "READCERT", cmd_readcert, hlp_readcert },
1689 { "READKEY", cmd_readkey, hlp_readkey },
1690 { "SETDATA", cmd_setdata, hlp_setdata },
1691 { "PKSIGN", cmd_pksign, hlp_pksign },
1692 { "PKAUTH", cmd_pkauth, hlp_pkauth },
1693 { "PKDECRYPT", cmd_pkdecrypt,hlp_pkdecrypt },
1696 { "GETATTR", cmd_getattr, hlp_getattr },
1697 { "SETATTR", cmd_setattr, hlp_setattr },
1698 { "WRITECERT", cmd_writecert,hlp_writecert },
1699 { "WRITEKEY", cmd_writekey, hlp_writekey },
1700 { "GENKEY", cmd_genkey, hlp_genkey },
1701 { "RANDOM", cmd_random, hlp_random },
1702 { "PASSWD", cmd_passwd, hlp_passwd },
1703 { "CHECKPIN", cmd_checkpin, hlp_checkpin },
1704 { "LOCK", cmd_lock, hlp_lock },
1705 { "UNLOCK", cmd_unlock, hlp_unlock },
1706 { "GETINFO", cmd_getinfo, hlp_getinfo },
1707 { "RESTART", cmd_restart, hlp_restart },
1708 { "DISCONNECT", cmd_disconnect,hlp_disconnect },
1709 { "APDU", cmd_apdu, hlp_apdu },
1710 { "KILLSCD", cmd_killscd, hlp_killscd },
1715 for (i=0; table[i].name; i++)
1717 rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1722 assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
1724 assuan_register_reset_notify (ctx, reset_notify);
1725 assuan_register_option_handler (ctx, option_handler);
1730 /* Startup the server. If FD is given as -1 this is simple pipe
1731 server, otherwise it is a regular server. Returns true if there
1732 are no more active asessions. */
1734 scd_command_handler (ctrl_t ctrl, int fd)
1737 assuan_context_t ctx = NULL;
1740 rc = assuan_new (&ctx);
1743 log_error ("failed to allocate assuan context: %s\n",
1750 assuan_fd_t filedes[2];
1752 filedes[0] = assuan_fdopen (0);
1753 filedes[1] = assuan_fdopen (1);
1754 rc = assuan_init_pipe_server (ctx, filedes);
1758 rc = assuan_init_socket_server (ctx, INT2FD(fd),
1759 ASSUAN_SOCKET_SERVER_ACCEPTED);
1763 log_error ("failed to initialize the server: %s\n",
1767 rc = register_commands (ctx);
1770 log_error ("failed to register commands with Assuan: %s\n",
1774 assuan_set_pointer (ctx, ctrl);
1776 /* Allocate and initialize the server object. Put it into the list
1777 of active sessions. */
1778 ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
1779 ctrl->server_local->next_session = session_list;
1780 session_list = ctrl->server_local;
1781 ctrl->server_local->ctrl_backlink = ctrl;
1782 ctrl->server_local->assuan_ctx = ctx;
1784 /* Command processing loop. */
1787 rc = assuan_accept (ctx);
1794 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1798 rc = assuan_process (ctx);
1801 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1806 /* Cleanup. We don't send an explicit reset to the card. */
1809 /* Release the server object. */
1810 if (session_list == ctrl->server_local)
1811 session_list = ctrl->server_local->next_session;
1814 struct server_local_s *sl;
1816 for (sl=session_list; sl->next_session; sl = sl->next_session)
1817 if (sl->next_session == ctrl->server_local)
1819 if (!sl->next_session)
1821 sl->next_session = ctrl->server_local->next_session;
1823 stopme = ctrl->server_local->stopme;
1824 xfree (ctrl->server_local);
1825 ctrl->server_local = NULL;
1827 /* Release the Assuan context. */
1828 assuan_release (ctx);
1833 /* If there are no more sessions return true. */
1834 return !session_list;
1838 /* Send a line with status information via assuan and escape all given
1839 buffers. The variable elements are pairs of (char *, size_t),
1840 terminated with a (NULL, 0). */
1842 send_status_info (ctrl_t ctrl, const char *keyword, ...)
1845 const unsigned char *value;
1849 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1851 va_start (arg_ptr, keyword);
1855 while ( (value = va_arg (arg_ptr, const unsigned char *))
1856 && n < DIM (buf)-2 )
1858 valuelen = va_arg (arg_ptr, size_t);
1860 continue; /* empty buffer */
1866 for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
1868 if (*value == '+' || *value == '\"' || *value == '%'
1871 sprintf (p, "%%%02X", *value);
1875 else if (*value == ' ')
1882 assuan_write_status (ctx, keyword, buf);
1888 /* Send a ready formatted status line via assuan. */
1890 send_status_direct (ctrl_t ctrl, const char *keyword, const char *args)
1892 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1894 if (strchr (args, '\n'))
1895 log_error ("error: LF detected in status line - not sending\n");
1897 assuan_write_status (ctx, keyword, args);
1901 /* Helper to send the clients a status change notification. */
1903 send_client_notifications (app_t app, int removal)
1907 #ifdef HAVE_W32_SYSTEM
1915 struct server_local_s *sl;
1917 for (sl=session_list; sl; sl = sl->next_session)
1918 if (sl->ctrl_backlink && sl->ctrl_backlink->app_ctx == app)
1921 #ifdef HAVE_W32_SYSTEM
1929 sl->ctrl_backlink->app_ctx = NULL;
1930 sl->card_removed = 1;
1931 release_application (app, 1);
1934 if (!sl->event_signal || !sl->assuan_ctx)
1937 pid = assuan_get_pid (sl->assuan_ctx);
1939 #ifdef HAVE_W32_SYSTEM
1940 handle = sl->event_signal;
1941 for (kidx=0; kidx < killidx; kidx++)
1942 if (killed[kidx].pid == pid
1943 && killed[kidx].handle == handle)
1946 log_info ("event %p (%p) already triggered for client %d\n",
1947 sl->event_signal, handle, (int)pid);
1950 log_info ("triggering event %p (%p) for client %d\n",
1951 sl->event_signal, handle, (int)pid);
1952 if (!SetEvent (handle))
1953 log_error ("SetEvent(%p) failed: %s\n",
1954 sl->event_signal, w32_strerror (-1));
1955 if (killidx < DIM (killed))
1957 killed[killidx].pid = pid;
1958 killed[killidx].handle = handle;
1962 #else /*!HAVE_W32_SYSTEM*/
1963 signo = sl->event_signal;
1965 if (pid != (pid_t)(-1) && pid && signo > 0)
1967 for (kidx=0; kidx < killidx; kidx++)
1968 if (killed[kidx].pid == pid
1969 && killed[kidx].signo == signo)
1972 log_info ("signal %d already sent to client %d\n",
1976 log_info ("sending signal %d to client %d\n",
1979 if (killidx < DIM (killed))
1981 killed[killidx].pid = pid;
1982 killed[killidx].signo = signo;
1987 #endif /*!HAVE_W32_SYSTEM*/