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 status 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"
350 " NKS = NetKey card\n"
352 "are implemented. These strings are aliases for the AID\n"
354 " S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>\n"
356 "If there is no certificate yet stored on the card a single 'X' is\n"
357 "returned as the keygrip. In addition to the keypair info, information\n"
358 "about all certificates stored on the card is also returned:\n"
360 " S CERTINFO <certtype> <hexstring_with_id>\n"
362 "Where CERTTYPE is a number indicating the type of certificate:\n"
364 " 100 := Regular X.509 cert\n"
365 " 101 := Trusted X.509 cert\n"
366 " 102 := Useful X.509 cert\n"
367 " 110 := Root CA cert in a special format (e.g. DINSIG)\n"
368 " 111 := Root CA cert as standard X509 cert.\n"
370 "For certain cards, more information will be returned:\n"
372 " S KEY-FPR <no> <hexstring>\n"
374 "For OpenPGP cards this returns the stored fingerprints of the\n"
375 "keys. This can be used check whether a key is available on the\n"
376 "card. NO may be 1, 2 or 3.\n"
378 " S CA-FPR <no> <hexstring>\n"
380 "Similar to above, these are the fingerprints of keys assumed to be\n"
381 "ultimately trusted.\n"
383 " S DISP-NAME <name_of_card_holder>\n"
385 "The name of the card holder as stored on the card; percent\n"
386 "escaping takes place, spaces are encoded as '+'\n"
388 " S PUBKEY-URL <url>\n"
390 "The URL to be used for locating the entire public key.\n"
392 "Note, that this function may even be used on a locked card.";
394 cmd_learn (assuan_context_t ctx, char *line)
396 ctrl_t ctrl = assuan_get_pointer (ctx);
398 int only_keypairinfo = has_option (line, "--keypairinfo");
400 if ((rc = open_card (ctrl)))
403 /* Unless the force option is used we try a shortcut by identifying
404 the card using a serial number and inquiring the client with
405 that. The client may choose to cancel the operation if he already
406 knows about this card */
407 if (!only_keypairinfo)
411 app_t app = ctrl->app_ctx;
414 return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
416 reader = apdu_get_reader_name (app->slot);
418 return out_of_core ();
419 send_status_direct (ctrl, "READER", reader);
420 /* No need to free the string of READER. */
422 serial = app_get_serialno (ctrl->app_ctx);
424 return gpg_error (GPG_ERR_INV_VALUE);
426 rc = assuan_write_status (ctx, "SERIALNO", serial);
430 return out_of_core ();
433 if (!has_option (line, "--force"))
437 rc = gpgrt_asprintf (&command, "KNOWNCARDP %s", serial);
441 return out_of_core ();
443 rc = assuan_inquire (ctx, command, NULL, NULL, 0);
447 if (gpg_err_code (rc) != GPG_ERR_ASS_CANCELED)
448 log_error ("inquire KNOWNCARDP failed: %s\n",
453 /* Not canceled, so we have to proceed. */
458 /* Let the application print out its collection of useful status
461 rc = app_write_learn_status (ctrl->app_ctx, ctrl, only_keypairinfo);
468 static const char hlp_readcert[] =
469 "READCERT <hexified_certid>|<keyid>\n"
471 "Note, that this function may even be used on a locked card.";
473 cmd_readcert (assuan_context_t ctx, char *line)
475 ctrl_t ctrl = assuan_get_pointer (ctx);
480 if ((rc = open_card (ctrl)))
483 line = xstrdup (line); /* Need a copy of the line. */
484 rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert);
486 log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
491 rc = assuan_send_data (ctx, cert, ncert);
501 static const char hlp_readkey[] =
502 "READKEY [--advanced] <keyid>\n"
504 "Return the public key for the given cert or key ID as a standard\n"
506 "In --advanced mode it returns the S-expression in advanced format.\n"
508 "Note that this function may even be used on a locked card.";
510 cmd_readkey (assuan_context_t ctx, char *line)
512 ctrl_t ctrl = assuan_get_pointer (ctx);
515 unsigned char *cert = NULL;
517 ksba_cert_t kc = NULL;
522 if ((rc = open_card (ctrl)))
525 if (has_option (line, "--advanced"))
528 line = skip_options (line);
530 line = xstrdup (line); /* Need a copy of the line. */
531 /* If the application supports the READKEY function we use that.
532 Otherwise we use the old way by extracting it from the
534 rc = app_readkey (ctrl->app_ctx, ctrl, advanced, line, &pk, &pklen);
536 { /* Yeah, got that key - send it back. */
537 rc = assuan_send_data (ctx, pk, pklen);
544 if (gpg_err_code (rc) != GPG_ERR_UNSUPPORTED_OPERATION)
545 log_error ("app_readkey failed: %s\n", gpg_strerror (rc));
548 rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert);
550 log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
557 rc = ksba_cert_new (&kc);
561 rc = ksba_cert_init_from_mem (kc, cert, ncert);
564 log_error ("failed to parse the certificate: %s\n", gpg_strerror (rc));
568 p = ksba_cert_get_public_key (kc);
571 rc = gpg_error (GPG_ERR_NO_PUBKEY);
575 n = gcry_sexp_canon_len (p, 0, NULL, NULL);
576 rc = assuan_send_data (ctx, p, n);
581 ksba_cert_release (kc);
588 static const char hlp_setdata[] =
589 "SETDATA [--append] <hexstring>\n"
591 "The client should use this command to tell us the data he want to sign.\n"
592 "With the option --append, the data is appended to the data set by a\n"
593 "previous SETDATA command.";
595 cmd_setdata (assuan_context_t ctx, char *line)
597 ctrl_t ctrl = assuan_get_pointer (ctx);
603 append = (ctrl->in_data.value && has_option (line, "--append"));
605 line = skip_options (line);
607 if (locked_session && locked_session != ctrl->server_local)
608 return gpg_error (GPG_ERR_LOCKED);
610 /* Parse the hexstring. */
611 for (p=line,n=0; hexdigitp (p); p++, n++)
614 return set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
616 return set_error (GPG_ERR_ASS_PARAMETER, "no data given");
618 return set_error (GPG_ERR_ASS_PARAMETER, "odd number of digits");
622 if (ctrl->in_data.valuelen + n > MAXLEN_SETDATA)
623 return set_error (GPG_ERR_TOO_LARGE,
624 "limit on total size of data reached");
625 buf = xtrymalloc (ctrl->in_data.valuelen + n);
628 buf = xtrymalloc (n);
630 return out_of_core ();
634 memcpy (buf, ctrl->in_data.value, ctrl->in_data.valuelen);
635 off = ctrl->in_data.valuelen;
639 for (p=line, i=0; i < n; p += 2, i++)
640 buf[off+i] = xtoi_2 (p);
642 xfree (ctrl->in_data.value);
643 ctrl->in_data.value = buf;
644 ctrl->in_data.valuelen = off+n;
651 pin_cb (void *opaque, const char *info, char **retstr)
653 assuan_context_t ctx = opaque;
656 unsigned char *value;
661 /* We prompt for pinpad entry. To make sure that the popup has
662 been show we use an inquire and not just a status message.
663 We ignore any value returned. */
666 log_debug ("prompting for pinpad entry '%s'\n", info);
667 rc = gpgrt_asprintf (&command, "POPUPPINPADPROMPT %s", info);
669 return gpg_error (gpg_err_code_from_errno (errno));
670 rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN);
675 log_debug ("dismiss pinpad entry prompt\n");
676 rc = assuan_inquire (ctx, "DISMISSPINPADPROMPT",
677 &value, &valuelen, MAXLEN_PIN);
685 log_debug ("asking for PIN '%s'\n", info);
687 rc = gpgrt_asprintf (&command, "NEEDPIN %s", info);
689 return gpg_error (gpg_err_code_from_errno (errno));
691 /* Fixme: Write an inquire function which returns the result in
692 secure memory and check all further handling of the PIN. */
693 rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN);
698 if (!valuelen || value[valuelen-1])
700 /* We require that the returned value is an UTF-8 string */
702 return gpg_error (GPG_ERR_INV_RESPONSE);
704 *retstr = (char*)value;
709 static const char hlp_pksign[] =
710 "PKSIGN [--hash=[rmd160|sha{1,224,256,384,512}|md5]] <hexified_id>\n"
712 "The --hash option is optional; the default is SHA1.";
714 cmd_pksign (assuan_context_t ctx, char *line)
716 ctrl_t ctrl = assuan_get_pointer (ctx);
718 unsigned char *outdata;
723 if (has_option (line, "--hash=rmd160"))
724 hash_algo = GCRY_MD_RMD160;
725 else if (has_option (line, "--hash=sha1"))
726 hash_algo = GCRY_MD_SHA1;
727 else if (has_option (line, "--hash=sha224"))
728 hash_algo = GCRY_MD_SHA224;
729 else if (has_option (line, "--hash=sha256"))
730 hash_algo = GCRY_MD_SHA256;
731 else if (has_option (line, "--hash=sha384"))
732 hash_algo = GCRY_MD_SHA384;
733 else if (has_option (line, "--hash=sha512"))
734 hash_algo = GCRY_MD_SHA512;
735 else if (has_option (line, "--hash=md5"))
736 hash_algo = GCRY_MD_MD5;
737 else if (!strstr (line, "--"))
738 hash_algo = GCRY_MD_SHA1;
740 return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
742 line = skip_options (line);
744 if ((rc = open_card (ctrl)))
747 /* We have to use a copy of the key ID because the function may use
748 the pin_cb which in turn uses the assuan line buffer and thus
749 overwriting the original line with the keyid */
750 keyidstr = xtrystrdup (line);
752 return out_of_core ();
754 rc = app_sign (ctrl->app_ctx, ctrl,
757 ctrl->in_data.value, ctrl->in_data.valuelen,
758 &outdata, &outdatalen);
763 log_error ("app_sign failed: %s\n", gpg_strerror (rc));
767 rc = assuan_send_data (ctx, outdata, outdatalen);
770 return rc; /* that is already an assuan error code */
777 static const char hlp_pkauth[] =
778 "PKAUTH <hexified_id>";
780 cmd_pkauth (assuan_context_t ctx, char *line)
782 ctrl_t ctrl = assuan_get_pointer (ctx);
784 unsigned char *outdata;
788 if ((rc = open_card (ctrl)))
792 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
794 /* We have to use a copy of the key ID because the function may use
795 the pin_cb which in turn uses the assuan line buffer and thus
796 overwriting the original line with the keyid */
797 keyidstr = xtrystrdup (line);
799 return out_of_core ();
801 rc = app_auth (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx,
802 ctrl->in_data.value, ctrl->in_data.valuelen,
803 &outdata, &outdatalen);
807 log_error ("app_auth failed: %s\n", gpg_strerror (rc));
811 rc = assuan_send_data (ctx, outdata, outdatalen);
814 return rc; /* that is already an assuan error code */
821 static const char hlp_pkdecrypt[] =
822 "PKDECRYPT <hexified_id>";
824 cmd_pkdecrypt (assuan_context_t ctx, char *line)
826 ctrl_t ctrl = assuan_get_pointer (ctx);
828 unsigned char *outdata;
831 unsigned int infoflags;
833 if ((rc = open_card (ctrl)))
836 keyidstr = xtrystrdup (line);
838 return out_of_core ();
839 rc = app_decipher (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx,
840 ctrl->in_data.value, ctrl->in_data.valuelen,
841 &outdata, &outdatalen, &infoflags);
846 log_error ("app_decipher failed: %s\n", gpg_strerror (rc));
850 /* If the card driver told us that there is no padding, send a
851 status line. If there is a padding it is assumed that the
852 caller knows what padding is used. It would have been better
853 to always send that information but for backward
854 compatibility we can't do that. */
855 if ((infoflags & APP_DECIPHER_INFO_NOPAD))
856 send_status_direct (ctrl, "PADDING", "0");
857 rc = assuan_send_data (ctx, outdata, outdatalen);
860 return rc; /* that is already an assuan error code */
867 static const char hlp_getattr[] =
870 "This command is used to retrieve data from a smartcard. The\n"
871 "allowed names depend on the currently selected smartcard\n"
872 "application. NAME must be percent and '+' escaped. The value is\n"
873 "returned through status message, see the LEARN command for details.\n"
875 "However, the current implementation assumes that Name is not escaped;\n"
876 "this works as long as no one uses arbitrary escaping. \n"
878 "Note, that this function may even be used on a locked card.";
880 cmd_getattr (assuan_context_t ctx, char *line)
882 ctrl_t ctrl = assuan_get_pointer (ctx);
886 if ((rc = open_card (ctrl)))
890 for (; *line && !spacep (line); line++)
895 /* (We ignore any garbage for now.) */
897 /* FIXME: Applications should not return sensitive data if the card
899 rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
905 static const char hlp_setattr[] =
906 "SETATTR <name> <value> \n"
908 "This command is used to store data on a smartcard. The allowed\n"
909 "names and values are depend on the currently selected smartcard\n"
910 "application. NAME and VALUE must be percent and '+' escaped.\n"
912 "However, the current implementation assumes that NAME is not\n"
913 "escaped; this works as long as no one uses arbitrary escaping.\n"
915 "A PIN will be requested for most NAMEs. See the corresponding\n"
916 "setattr function of the actually used application (app-*.c) for\n"
919 cmd_setattr (assuan_context_t ctx, char *orig_line)
921 ctrl_t ctrl = assuan_get_pointer (ctx);
926 char *line, *linebuf;
928 if ((rc = open_card (ctrl)))
931 /* We need to use a copy of LINE, because PIN_CB uses the same
932 context and thus reuses the Assuan provided LINE. */
933 line = linebuf = xtrystrdup (orig_line);
935 return out_of_core ();
938 for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
942 while (spacep (line))
944 nbytes = percent_plus_unescape_inplace (line, 0);
946 rc = app_setattr (ctrl->app_ctx, ctrl, keyword, pin_cb, ctx,
947 (const unsigned char*)line, nbytes);
954 static const char hlp_writecert[] =
955 "WRITECERT <hexified_certid>\n"
957 "This command is used to store a certifciate on a smartcard. The\n"
958 "allowed certids depend on the currently selected smartcard\n"
959 "application. The actual certifciate is requested using the inquiry\n"
960 "\"CERTDATA\" and needs to be provided in its raw (e.g. DER) form.\n"
962 "In almost all cases a PIN will be requested. See the related\n"
963 "writecert function of the actually used application (app-*.c) for\n"
966 cmd_writecert (assuan_context_t ctx, char *line)
968 ctrl_t ctrl = assuan_get_pointer (ctx);
971 unsigned char *certdata;
974 line = skip_options (line);
977 return set_error (GPG_ERR_ASS_PARAMETER, "no certid given");
979 while (*line && !spacep (line))
983 if ((rc = open_card (ctrl)))
987 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
989 certid = xtrystrdup (certid);
991 return out_of_core ();
993 /* Now get the actual keydata. */
994 rc = assuan_inquire (ctx, "CERTDATA",
995 &certdata, &certdatalen, MAXLEN_CERTDATA);
1002 /* Write the certificate to the card. */
1003 rc = app_writecert (ctrl->app_ctx, ctrl, certid,
1004 pin_cb, ctx, certdata, certdatalen);
1012 static const char hlp_writekey[] =
1013 "WRITEKEY [--force] <keyid> \n"
1015 "This command is used to store a secret key on a smartcard. The\n"
1016 "allowed keyids depend on the currently selected smartcard\n"
1017 "application. The actual keydata is requested using the inquiry\n"
1018 "\"KEYDATA\" and need to be provided without any protection. With\n"
1019 "--force set an existing key under this KEYID will get overwritten.\n"
1020 "The keydata is expected to be the usual canonical encoded\n"
1023 "A PIN will be requested for most NAMEs. See the corresponding\n"
1024 "writekey function of the actually used application (app-*.c) for\n"
1027 cmd_writekey (assuan_context_t ctx, char *line)
1029 ctrl_t ctrl = assuan_get_pointer (ctx);
1032 int force = has_option (line, "--force");
1033 unsigned char *keydata;
1036 line = skip_options (line);
1039 return set_error (GPG_ERR_ASS_PARAMETER, "no keyid given");
1041 while (*line && !spacep (line))
1045 if ((rc = open_card (ctrl)))
1049 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1051 keyid = xtrystrdup (keyid);
1053 return out_of_core ();
1055 /* Now get the actual keydata. */
1056 assuan_begin_confidential (ctx);
1057 rc = assuan_inquire (ctx, "KEYDATA", &keydata, &keydatalen, MAXLEN_KEYDATA);
1058 assuan_end_confidential (ctx);
1065 /* Write the key to the card. */
1066 rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0,
1067 pin_cb, ctx, keydata, keydatalen);
1075 static const char hlp_genkey[] =
1076 "GENKEY [--force] [--timestamp=<isodate>] <no>\n"
1078 "Generate a key on-card identified by NO, which is application\n"
1079 "specific. Return values are application specific. For OpenPGP\n"
1080 "cards 3 status lines are returned:\n"
1082 " S KEY-FPR <hexstring>\n"
1083 " S KEY-CREATED-AT <seconds_since_epoch>\n"
1084 " S KEY-DATA [-|p|n] <hexdata>\n"
1086 " 'p' and 'n' are the names of the RSA parameters; '-' is used to\n"
1087 " indicate that HEXDATA is the first chunk of a parameter given\n"
1088 " by the next KEY-DATA.\n"
1090 "--force is required to overwrite an already existing key. The\n"
1091 "KEY-CREATED-AT is required for further processing because it is\n"
1092 "part of the hashed key material for the fingerprint.\n"
1094 "If --timestamp is given an OpenPGP key will be created using this\n"
1095 "value. The value needs to be in ISO Format; e.g.\n"
1096 "\"--timestamp=20030316T120000\" and after 1970-01-01 00:00:00.\n"
1098 "The public part of the key can also later be retrieved using the\n"
1101 cmd_genkey (assuan_context_t ctx, char *line)
1103 ctrl_t ctrl = assuan_get_pointer (ctx);
1110 force = has_option (line, "--force");
1112 if ((s=has_option_name (line, "--timestamp")))
1115 return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
1116 timestamp = isotime2epoch (s+1);
1118 return set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
1124 line = skip_options (line);
1126 return set_error (GPG_ERR_ASS_PARAMETER, "no key number given");
1128 while (*line && !spacep (line))
1132 if ((rc = open_card (ctrl)))
1136 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1138 keyno = xtrystrdup (keyno);
1140 return out_of_core ();
1141 rc = app_genkey (ctrl->app_ctx, ctrl, keyno, NULL,
1142 force? APP_GENKEY_FLAG_FORCE : 0,
1143 timestamp, pin_cb, ctx);
1150 static const char hlp_random[] =
1153 "Get NBYTES of random from the card and send them back as data.\n"
1154 "This usually involves EEPROM write on the card and thus excessive\n"
1155 "use of this command may destroy the card.\n"
1157 "Note, that this function may be even be used on a locked card.";
1159 cmd_random (assuan_context_t ctx, char *line)
1161 ctrl_t ctrl = assuan_get_pointer (ctx);
1164 unsigned char *buffer;
1167 return set_error (GPG_ERR_ASS_PARAMETER,
1168 "number of requested bytes missing");
1169 nbytes = strtoul (line, NULL, 0);
1171 if ((rc = open_card (ctrl)))
1175 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1177 buffer = xtrymalloc (nbytes);
1179 return out_of_core ();
1181 rc = app_get_challenge (ctrl->app_ctx, ctrl, nbytes, buffer);
1184 rc = assuan_send_data (ctx, buffer, nbytes);
1186 return rc; /* that is already an assuan error code */
1195 static const char hlp_passwd[] =
1196 "PASSWD [--reset] [--nullpin] [--clear] <chvno>\n"
1198 "Change the PIN or, if --reset is given, reset the retry counter of\n"
1199 "the card holder verification vector CHVNO. The option --nullpin is\n"
1200 "used for TCOS cards to set the initial PIN. The option --clear clears\n"
1201 "the security status associated with the PIN so that the PIN needs to\n"
1202 "be presented again. The format of CHVNO depends on the card application.";
1204 cmd_passwd (assuan_context_t ctx, char *line)
1206 ctrl_t ctrl = assuan_get_pointer (ctx);
1209 unsigned int flags = 0;
1211 if (has_option (line, "--reset"))
1212 flags |= APP_CHANGE_FLAG_RESET;
1213 if (has_option (line, "--nullpin"))
1214 flags |= APP_CHANGE_FLAG_NULLPIN;
1215 if (has_option (line, "--clear"))
1216 flags |= APP_CHANGE_FLAG_CLEAR;
1218 line = skip_options (line);
1221 return set_error (GPG_ERR_ASS_PARAMETER, "no CHV number given");
1223 while (*line && !spacep (line))
1227 /* Do not allow other flags aside of --clear. */
1228 if ((flags & APP_CHANGE_FLAG_CLEAR) && (flags & ~APP_CHANGE_FLAG_CLEAR))
1229 return set_error (GPG_ERR_UNSUPPORTED_OPERATION,
1230 "--clear used with other options");
1232 if ((rc = open_card (ctrl)))
1236 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1238 chvnostr = xtrystrdup (chvnostr);
1240 return out_of_core ();
1241 rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
1243 log_error ("command passwd failed: %s\n", gpg_strerror (rc));
1250 static const char hlp_checkpin[] =
1251 "CHECKPIN <idstr>\n"
1253 "Perform a VERIFY operation without doing anything else. This may\n"
1254 "be used to initialize a the PIN cache earlier to long lasting\n"
1255 "operations. Its use is highly application dependent.\n"
1259 " Perform a simple verify operation for CHV1 and CHV2, so that\n"
1260 " further operations won't ask for CHV2 and it is possible to do a\n"
1261 " cheap check on the PIN: If there is something wrong with the PIN\n"
1262 " entry system, only the regular CHV will get blocked and not the\n"
1263 " dangerous CHV3. IDSTR is the usual card's serial number in hex\n"
1264 " notation; an optional fingerprint part will get ignored. There\n"
1265 " is however a special mode if the IDSTR is sffixed with the\n"
1266 " literal string \"[CHV3]\": In this case the Admin PIN is checked\n"
1267 " if and only if the retry counter is still at 3.\n"
1271 " Any of the valid PIN Ids may be used. These are the strings:\n"
1273 " PW1.CH - Global password 1\n"
1274 " PW2.CH - Global password 2\n"
1275 " PW1.CH.SIG - SigG password 1\n"
1276 " PW2.CH.SIG - SigG password 2\n"
1278 " For a definitive list, see the implementation in app-nks.c.\n"
1279 " Note that we call a PW2.* PIN a \"PUK\" despite that since TCOS\n"
1280 " 3.0 they are technically alternative PINs used to mutally\n"
1281 " unblock each other.";
1283 cmd_checkpin (assuan_context_t ctx, char *line)
1285 ctrl_t ctrl = assuan_get_pointer (ctx);
1289 if ((rc = open_card (ctrl)))
1293 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1295 /* We have to use a copy of the key ID because the function may use
1296 the pin_cb which in turn uses the assuan line buffer and thus
1297 overwriting the original line with the keyid. */
1298 idstr = xtrystrdup (line);
1300 return out_of_core ();
1302 rc = app_check_pin (ctrl->app_ctx, ctrl, idstr, pin_cb, ctx);
1305 log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
1311 static const char hlp_lock[] =
1314 "Grant exclusive card access to this session. Note that there is\n"
1315 "no lock counter used and a second lock from the same session will\n"
1316 "be ignored. A single unlock (or RESET) unlocks the session.\n"
1317 "Return GPG_ERR_LOCKED if another session has locked the reader.\n"
1319 "If the option --wait is given the command will wait until a\n"
1320 "lock has been released.";
1322 cmd_lock (assuan_context_t ctx, char *line)
1324 ctrl_t ctrl = assuan_get_pointer (ctx);
1330 if (locked_session != ctrl->server_local)
1331 rc = gpg_error (GPG_ERR_LOCKED);
1334 locked_session = ctrl->server_local;
1337 if (rc && has_option (line, "--wait"))
1340 npth_sleep (1); /* Better implement an event mechanism. However,
1341 for card operations this should be
1343 /* FIXME: Need to check that the connection is still alive.
1344 This can be done by issuing status messages. */
1350 log_error ("cmd_lock failed: %s\n", gpg_strerror (rc));
1355 static const char hlp_unlock[] =
1358 "Release exclusive card access.";
1360 cmd_unlock (assuan_context_t ctx, char *line)
1362 ctrl_t ctrl = assuan_get_pointer (ctx);
1369 if (locked_session != ctrl->server_local)
1370 rc = gpg_error (GPG_ERR_LOCKED);
1372 locked_session = NULL;
1375 rc = gpg_error (GPG_ERR_NOT_LOCKED);
1378 log_error ("cmd_unlock failed: %s\n", gpg_strerror (rc));
1383 static const char hlp_getinfo[] =
1386 "Multi purpose command to return certain information. \n"
1387 "Supported values of WHAT are:\n"
1389 " version - Return the version of the program.\n"
1390 " pid - Return the process id of the server.\n"
1391 " socket_name - Return the name of the socket.\n"
1392 " connections - Return number of active connections.\n"
1393 " status - Return the status of the current reader (in the future,\n"
1394 " may also return the status of all readers). The status\n"
1395 " is a list of one-character flags. The following flags\n"
1396 " are currently defined:\n"
1397 " 'u' Usable card present.\n"
1398 " 'r' Card removed. A reset is necessary.\n"
1399 " These flags are exclusive.\n"
1400 " reader_list - Return a list of detected card readers. Does\n"
1401 " currently only work with the internal CCID driver.\n"
1402 " deny_admin - Returns OK if admin commands are not allowed or\n"
1403 " GPG_ERR_GENERAL if admin commands are allowed.\n"
1404 " app_list - Return a list of supported applications. One\n"
1405 " application per line, fields delimited by colons,\n"
1406 " first field is the name.\n"
1407 " card_list - Return a list of serial numbers of active cards,\n"
1408 " using a status response.";
1410 cmd_getinfo (assuan_context_t ctx, char *line)
1414 if (!strcmp (line, "version"))
1416 const char *s = VERSION;
1417 rc = assuan_send_data (ctx, s, strlen (s));
1419 else if (!strcmp (line, "pid"))
1423 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1424 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1426 else if (!strcmp (line, "socket_name"))
1428 const char *s = scd_get_socket_name ();
1431 rc = assuan_send_data (ctx, s, strlen (s));
1433 rc = gpg_error (GPG_ERR_NO_DATA);
1435 else if (!strcmp (line, "connections"))
1439 snprintf (numbuf, sizeof numbuf, "%d", get_active_connection_count ());
1440 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1442 else if (!strcmp (line, "status"))
1444 ctrl_t ctrl = assuan_get_pointer (ctx);
1447 if (open_card (ctrl))
1452 rc = assuan_send_data (ctx, &flag, 1);
1454 else if (!strcmp (line, "reader_list"))
1457 char *s = ccid_get_reader_list ();
1463 rc = assuan_send_data (ctx, s, strlen (s));
1465 rc = gpg_error (GPG_ERR_NO_DATA);
1468 else if (!strcmp (line, "deny_admin"))
1469 rc = opt.allow_admin? gpg_error (GPG_ERR_GENERAL) : 0;
1470 else if (!strcmp (line, "app_list"))
1472 char *s = get_supported_applications ();
1474 rc = assuan_send_data (ctx, s, strlen (s));
1479 else if (!strcmp (line, "card_list"))
1481 ctrl_t ctrl = assuan_get_pointer (ctx);
1483 app_send_card_list (ctrl);
1486 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1491 static const char hlp_restart[] =
1494 "Restart the current connection; this is a kind of warm reset. It\n"
1495 "deletes the context used by this connection but does not send a\n"
1496 "RESET to the card. Thus the card itself won't get reset. \n"
1498 "This is used by gpg-agent to reuse a primary pipe connection and\n"
1499 "may be used by clients to backup from a conflict in the serial\n"
1500 "command; i.e. to select another application.";
1502 cmd_restart (assuan_context_t ctx, char *line)
1504 ctrl_t ctrl = assuan_get_pointer (ctx);
1505 app_t app = ctrl->app_ctx;
1511 ctrl->app_ctx = NULL;
1512 release_application (app, 0);
1514 if (locked_session && ctrl->server_local == locked_session)
1516 locked_session = NULL;
1517 log_info ("implicitly unlocking due to RESTART\n");
1523 static const char hlp_disconnect[] =
1526 "Disconnect the card if the backend supports a disconnect operation.";
1528 cmd_disconnect (assuan_context_t ctx, char *line)
1530 ctrl_t ctrl = assuan_get_pointer (ctx);
1535 return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
1537 apdu_disconnect (ctrl->app_ctx->slot);
1543 static const char hlp_apdu[] =
1544 "APDU [--[dump-]atr] [--more] [--exlen[=N]] [hexstring]\n"
1546 "Send an APDU to the current reader. This command bypasses the high\n"
1547 "level functions and sends the data directly to the card. HEXSTRING\n"
1548 "is expected to be a proper APDU. If HEXSTRING is not given no\n"
1549 "commands are set to the card but the command will implictly check\n"
1550 "whether the card is ready for use. \n"
1552 "Using the option \"--atr\" returns the ATR of the card as a status\n"
1553 "message before any data like this:\n"
1554 " S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1\n"
1556 "Using the option --more handles the card status word MORE_DATA\n"
1557 "(61xx) and concatenates all responses to one block.\n"
1559 "Using the option \"--exlen\" the returned APDU may use extended\n"
1560 "length up to N bytes. If N is not given a default value is used\n"
1561 "(currently 4096).";
1563 cmd_apdu (assuan_context_t ctx, char *line)
1565 ctrl_t ctrl = assuan_get_pointer (ctx);
1568 unsigned char *apdu;
1575 if (has_option (line, "--dump-atr"))
1578 with_atr = has_option (line, "--atr");
1579 handle_more = has_option (line, "--more");
1581 if ((s=has_option_name (line, "--exlen")))
1584 exlen = strtoul (s+1, NULL, 0);
1591 line = skip_options (line);
1593 if ((rc = open_card (ctrl)))
1596 app = ctrl->app_ctx;
1598 return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
1606 atr = apdu_get_atr (app->slot, &atrlen);
1607 if (!atr || atrlen > sizeof hexbuf - 2 )
1609 rc = gpg_error (GPG_ERR_INV_CARD);
1614 char *string, *p, *pend;
1616 string = atr_dump (atr, atrlen);
1619 for (rc=0, p=string; !rc && (pend = strchr (p, '\n')); p = pend+1)
1621 rc = assuan_send_data (ctx, p, pend - p + 1);
1623 rc = assuan_send_data (ctx, NULL, 0);
1626 rc = assuan_send_data (ctx, p, strlen (p));
1634 bin2hex (atr, atrlen, hexbuf);
1635 send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
1640 apdu = hex_to_buffer (line, &apdulen);
1643 rc = gpg_error_from_syserror ();
1648 unsigned char *result = NULL;
1651 rc = apdu_send_direct (app->slot, exlen,
1652 apdu, apdulen, handle_more,
1653 NULL, &result, &resultlen);
1655 log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));
1658 rc = assuan_send_data (ctx, result, resultlen);
1669 static const char hlp_killscd[] =
1674 cmd_killscd (assuan_context_t ctx, char *line)
1676 ctrl_t ctrl = assuan_get_pointer (ctx);
1680 ctrl->server_local->stopme = 1;
1681 assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
1687 /* Tell the assuan library about our commands */
1689 register_commands (assuan_context_t ctx)
1693 assuan_handler_t handler;
1694 const char * const help;
1696 { "SERIALNO", cmd_serialno, hlp_serialno },
1697 { "LEARN", cmd_learn, hlp_learn },
1698 { "READCERT", cmd_readcert, hlp_readcert },
1699 { "READKEY", cmd_readkey, hlp_readkey },
1700 { "SETDATA", cmd_setdata, hlp_setdata },
1701 { "PKSIGN", cmd_pksign, hlp_pksign },
1702 { "PKAUTH", cmd_pkauth, hlp_pkauth },
1703 { "PKDECRYPT", cmd_pkdecrypt,hlp_pkdecrypt },
1706 { "GETATTR", cmd_getattr, hlp_getattr },
1707 { "SETATTR", cmd_setattr, hlp_setattr },
1708 { "WRITECERT", cmd_writecert,hlp_writecert },
1709 { "WRITEKEY", cmd_writekey, hlp_writekey },
1710 { "GENKEY", cmd_genkey, hlp_genkey },
1711 { "RANDOM", cmd_random, hlp_random },
1712 { "PASSWD", cmd_passwd, hlp_passwd },
1713 { "CHECKPIN", cmd_checkpin, hlp_checkpin },
1714 { "LOCK", cmd_lock, hlp_lock },
1715 { "UNLOCK", cmd_unlock, hlp_unlock },
1716 { "GETINFO", cmd_getinfo, hlp_getinfo },
1717 { "RESTART", cmd_restart, hlp_restart },
1718 { "DISCONNECT", cmd_disconnect,hlp_disconnect },
1719 { "APDU", cmd_apdu, hlp_apdu },
1720 { "KILLSCD", cmd_killscd, hlp_killscd },
1725 for (i=0; table[i].name; i++)
1727 rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1732 assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
1734 assuan_register_reset_notify (ctx, reset_notify);
1735 assuan_register_option_handler (ctx, option_handler);
1740 /* Startup the server. If FD is given as -1 this is simple pipe
1741 server, otherwise it is a regular server. Returns true if there
1742 are no more active asessions. */
1744 scd_command_handler (ctrl_t ctrl, int fd)
1747 assuan_context_t ctx = NULL;
1750 rc = assuan_new (&ctx);
1753 log_error ("failed to allocate assuan context: %s\n",
1760 assuan_fd_t filedes[2];
1762 filedes[0] = assuan_fdopen (0);
1763 filedes[1] = assuan_fdopen (1);
1764 rc = assuan_init_pipe_server (ctx, filedes);
1768 rc = assuan_init_socket_server (ctx, INT2FD(fd),
1769 ASSUAN_SOCKET_SERVER_ACCEPTED);
1773 log_error ("failed to initialize the server: %s\n",
1777 rc = register_commands (ctx);
1780 log_error ("failed to register commands with Assuan: %s\n",
1784 assuan_set_pointer (ctx, ctrl);
1786 /* Allocate and initialize the server object. Put it into the list
1787 of active sessions. */
1788 ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
1789 ctrl->server_local->next_session = session_list;
1790 session_list = ctrl->server_local;
1791 ctrl->server_local->ctrl_backlink = ctrl;
1792 ctrl->server_local->assuan_ctx = ctx;
1794 /* Command processing loop. */
1797 rc = assuan_accept (ctx);
1804 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1808 rc = assuan_process (ctx);
1811 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1816 /* Cleanup. We don't send an explicit reset to the card. */
1819 /* Release the server object. */
1820 if (session_list == ctrl->server_local)
1821 session_list = ctrl->server_local->next_session;
1824 struct server_local_s *sl;
1826 for (sl=session_list; sl->next_session; sl = sl->next_session)
1827 if (sl->next_session == ctrl->server_local)
1829 if (!sl->next_session)
1831 sl->next_session = ctrl->server_local->next_session;
1833 stopme = ctrl->server_local->stopme;
1834 xfree (ctrl->server_local);
1835 ctrl->server_local = NULL;
1837 /* Release the Assuan context. */
1838 assuan_release (ctx);
1843 /* If there are no more sessions return true. */
1844 return !session_list;
1848 /* Send a line with status information via assuan and escape all given
1849 buffers. The variable elements are pairs of (char *, size_t),
1850 terminated with a (NULL, 0). */
1852 send_status_info (ctrl_t ctrl, const char *keyword, ...)
1855 const unsigned char *value;
1859 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1861 va_start (arg_ptr, keyword);
1865 while ( (value = va_arg (arg_ptr, const unsigned char *))
1866 && n < DIM (buf)-2 )
1868 valuelen = va_arg (arg_ptr, size_t);
1870 continue; /* empty buffer */
1876 for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
1878 if (*value == '+' || *value == '\"' || *value == '%'
1881 sprintf (p, "%%%02X", *value);
1885 else if (*value == ' ')
1892 assuan_write_status (ctx, keyword, buf);
1898 /* Send a ready formatted status line via assuan. */
1900 send_status_direct (ctrl_t ctrl, const char *keyword, const char *args)
1902 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1904 if (strchr (args, '\n'))
1905 log_error ("error: LF detected in status line - not sending\n");
1907 assuan_write_status (ctx, keyword, args);
1911 /* This status functions expects a printf style format string. No
1912 * filtering of the data is done instead the orintf formatted data is
1913 * send using assuan_send_status. */
1915 send_status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...)
1919 assuan_context_t ctx;
1921 if (!ctrl || !ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx))
1924 va_start (arg_ptr, format);
1925 err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
1932 popup_prompt (void *opaque, int on)
1934 ctrl_t ctrl = opaque;
1938 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1944 unsigned char *value;
1948 cmd = "POPUPPINPADPROMPT --ack";
1950 cmd = "DISMISSPINPADPROMPT";
1951 err = assuan_inquire (ctx, cmd, &value, &valuelen, 100);
1959 /* Helper to send the clients a status change notification. */
1961 send_client_notifications (app_t app, int removal)
1965 #ifdef HAVE_W32_SYSTEM
1973 struct server_local_s *sl;
1975 for (sl=session_list; sl; sl = sl->next_session)
1976 if (sl->ctrl_backlink && sl->ctrl_backlink->app_ctx == app)
1979 #ifdef HAVE_W32_SYSTEM
1987 sl->ctrl_backlink->app_ctx = NULL;
1988 sl->card_removed = 1;
1989 release_application (app, 1);
1992 if (!sl->event_signal || !sl->assuan_ctx)
1995 pid = assuan_get_pid (sl->assuan_ctx);
1997 #ifdef HAVE_W32_SYSTEM
1998 handle = sl->event_signal;
1999 for (kidx=0; kidx < killidx; kidx++)
2000 if (killed[kidx].pid == pid
2001 && killed[kidx].handle == handle)
2004 log_info ("event %p (%p) already triggered for client %d\n",
2005 sl->event_signal, handle, (int)pid);
2008 log_info ("triggering event %p (%p) for client %d\n",
2009 sl->event_signal, handle, (int)pid);
2010 if (!SetEvent (handle))
2011 log_error ("SetEvent(%p) failed: %s\n",
2012 sl->event_signal, w32_strerror (-1));
2013 if (killidx < DIM (killed))
2015 killed[killidx].pid = pid;
2016 killed[killidx].handle = handle;
2020 #else /*!HAVE_W32_SYSTEM*/
2021 signo = sl->event_signal;
2023 if (pid != (pid_t)(-1) && pid && signo > 0)
2025 for (kidx=0; kidx < killidx; kidx++)
2026 if (killed[kidx].pid == pid
2027 && killed[kidx].signo == signo)
2030 log_info ("signal %d already sent to client %d\n",
2034 log_info ("sending signal %d to client %d\n",
2037 if (killidx < DIM (killed))
2039 killed[killidx].pid = pid;
2040 killed[killidx].signo = signo;
2045 #endif /*!HAVE_W32_SYSTEM*/