diff options
author | Werner Koch <[email protected]> | 2024-03-12 15:00:55 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2024-03-12 15:00:55 +0000 |
commit | 4485930f9fd9ff02ca5c8472cf6aed3fdb1280cf (patch) | |
tree | 683140a4a33b0f3accf5b1f2455274d251581970 /scd | |
parent | gpg: Fix a possible segv due to an uninitialized gcrypt context. (diff) | |
parent | Post release updates (diff) | |
download | gnupg-4485930f9fd9ff02ca5c8472cf6aed3fdb1280cf.tar.gz gnupg-4485930f9fd9ff02ca5c8472cf6aed3fdb1280cf.zip |
Merge branch 'STABLE-BRANCH-2-4'
--
Resolved conflicts:
NEWS
common/exechelp-w32.c
configure.ac
Diffstat (limited to 'scd')
-rw-r--r-- | scd/app-nks.c | 2 | ||||
-rw-r--r-- | scd/app-openpgp.c | 17 | ||||
-rw-r--r-- | scd/app-p15.c | 97 | ||||
-rw-r--r-- | scd/ccid-driver.c | 153 | ||||
-rw-r--r-- | scd/ccid-driver.h | 2 | ||||
-rw-r--r-- | scd/scdaemon.c | 19 | ||||
-rw-r--r-- | scd/scdaemon.h | 8 |
7 files changed, 179 insertions, 119 deletions
diff --git a/scd/app-nks.c b/scd/app-nks.c index cdbdde8fb..c207fd500 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -1613,7 +1613,7 @@ verify_pin (app_t app, int pwid, const char *desc, memset (&pininfo, 0, sizeof pininfo); pininfo.fixedlen = -1; - /* FIXME: TCOS allows to read the min. and max. values - do this. */ + /* FIXME: TCOS allows one to read the min. and max. values - do this. */ if (app->appversion == 15) { if (app->app_local->active_nks_app == NKS_APP_NKS && pwid == 0x03) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 3bc709602..1f5d64e6a 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -3306,6 +3306,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, char *pinvalue = NULL; int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET); int set_resetcode = 0; + int use_resetcode = 0; pininfo_t pininfo; int use_pinpad = 0; int minlen = 6; @@ -3458,7 +3459,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, } rc = pincb (pincb_arg, - _("||Please enter the Reset Code for the card"), + _("|R|Please enter the Reset Code for the card"), &resetcode); if (rc) { @@ -3473,13 +3474,14 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, rc = gpg_error (GPG_ERR_BAD_RESET_CODE); goto leave; } + use_resetcode = 1; } else { rc = gpg_error (GPG_ERR_INV_ID); goto leave; } - } + } /* End version 2 cards. */ if (chvno == 3) app->did_chv3 = 0; @@ -3511,6 +3513,17 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, goto leave; } } + else if (use_resetcode) + { + minlen = 6; /* Reset from the RC value to the PIN value. */ + if (strlen (pinvalue) < minlen) + { + log_info (_("PIN for CHV%d is too short;" + " minimum length is %d\n"), 1, minlen); + rc = gpg_error (GPG_ERR_BAD_PIN); + goto leave; + } + } else { if (chvno == 3) diff --git a/scd/app-p15.c b/scd/app-p15.c index 2bb90beaa..6af10b46b 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -305,7 +305,7 @@ struct prkdf_object_s keyaccess_flags_t accessflags; /* Extended key usage flags. Only used if .valid is set. This - * information is computed from an associated certificate15. */ + * information is computed from an associated certificate. */ struct { unsigned int valid:1; unsigned int sign:1; @@ -520,6 +520,9 @@ struct app_local_s /* Information on all useful certificates. */ cdf_object_t useful_certificate_info; + /* Counter to make object ids of certificates unique. */ + unsigned int cdf_dup_counter; + /* Information on all public keys. */ prkdf_object_t public_key_info; @@ -2419,6 +2422,22 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result) } +/* Return true id CDFLIST has the given object id. */ +static int +objid_in_cdflist_p (cdf_object_t cdflist, + const unsigned char *objid, size_t objidlen) +{ + cdf_object_t cdf; + + if (!objid || !objidlen) + return 0; + for (cdf = cdflist; cdf; cdf = cdf->next) + if (cdf->objidlen == objidlen && !memcmp (cdf->objid, objid, objidlen)) + return 1; + return 0; +} + + /* Read and parse the Certificate Directory Files identified by FID. On success a newlist of CDF object gets stored at RESULT and the caller is then responsible of releasing this list. On error a @@ -2464,6 +2483,7 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result) unsigned long ul; const unsigned char *objid; size_t objidlen; + int objidextralen; err = parse_ber_header (&p, &n, &class, &tag, &constructed, &ndef, &objlen, &hdrlen); @@ -2588,8 +2608,19 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result) label = NULL; } - cdf->objidlen = objidlen; - cdf->objid = xtrymalloc (objidlen); + /* Card's have been found in the wild which do not have unique + * IDs for their certificate objects. If we detect this we + * append a counter to the ID. */ + objidextralen = + (objid_in_cdflist_p (cdflist, objid, objidlen) + || objid_in_cdflist_p (app->app_local->certificate_info, + objid, objidlen) + || objid_in_cdflist_p (app->app_local->trusted_certificate_info, + objid, objidlen) + || objid_in_cdflist_p (app->app_local->useful_certificate_info, + objid, objidlen)); + cdf->objidlen = objidlen + objidextralen; + cdf->objid = xtrymalloc (objidlen + objidextralen); if (!cdf->objid) { err = gpg_error_from_syserror (); @@ -2597,6 +2628,16 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result) goto leave; } memcpy (cdf->objid, objid, objidlen); + if (objidextralen) + { + if (app->app_local->cdf_dup_counter == 255) + { + log_error ("p15: too many duplicate certificate ids\n"); + err = gpg_error (GPG_ERR_TOO_MANY); + goto parse_error; + } + cdf->objid[objidlen] = ++app->app_local->cdf_dup_counter; + } cdf->pathlen = objlen/2; for (i=0; i < cdf->pathlen; i++, pp += 2, nn -= 2) @@ -3664,6 +3705,7 @@ read_p15_info (app_t app) log_assert (!app->app_local->certificate_info); log_assert (!app->app_local->trusted_certificate_info); log_assert (!app->app_local->useful_certificate_info); + app->app_local->cdf_dup_counter = 0; err = read_ef_cdf (app, app->app_local->odf.certificates, 'c', &app->app_local->certificate_info); if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA) @@ -4214,7 +4256,8 @@ set_usage_string (char usage[5], prkdf_object_t prkdf) && (!prkdf->extusage.valid || prkdf->extusage.sign)) usage[usagelen++] = 'c'; if ((prkdf->usageflags.decrypt - || prkdf->usageflags.unwrap) + || prkdf->usageflags.unwrap + || prkdf->usageflags.derive) && (!prkdf->extusage.valid || prkdf->extusage.encr)) usage[usagelen++] = 'e'; if ((prkdf->usageflags.sign @@ -4661,7 +4704,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) /* We return the ID of the first private key capable of the * requested action. If any gpgusage flag has been set for the - * card we consult the gpgusage flags and not the regualr usage + * card we consult the gpgusage flags and not the regular usage * flags. */ /* FIXME: This changed: Note that we do not yet return @@ -4683,7 +4726,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) if ((name[1] == 'A' && (prkdf->usageflags.sign || prkdf->usageflags.sign_recover)) || (name[1] == 'E' && (prkdf->usageflags.decrypt - || prkdf->usageflags.unwrap)) + || prkdf->usageflags.unwrap + || prkdf->usageflags.derive)) || (name[1] == 'S' && (prkdf->usageflags.sign || prkdf->usageflags.sign_recover))) break; @@ -4892,7 +4936,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) } else { - if (prkdf->usageflags.decrypt || prkdf->usageflags.unwrap) + if (prkdf->usageflags.decrypt || prkdf->usageflags.unwrap + || prkdf->usageflags.derive) break; } } @@ -5784,9 +5829,8 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, { if (prkdf->is_ecc) { - /* Not implemented due to lacking test hardware. */ - log_info ("Note: ECC is not yet implemented for DTRUST 4 cards\n"); - err = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + err = iso7816_manage_security_env (app_get_slot (app), + 0xf3, 0x21, NULL, 0); } else { @@ -5927,7 +5971,8 @@ do_auth (app_t app, ctrl_t ctrl, const char *keyidstr, err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf); if (err) return err; - if (!(prkdf->usageflags.sign || prkdf->gpgusage.auth)) + if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover + || prkdf->gpgusage.auth)) { log_error ("p15: key %s may not be used for authentication\n", keyidstr); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); @@ -5970,6 +6015,7 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr, return err; if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap + || prkdf->usageflags.derive || prkdf->gpgusage.encr )) { log_error ("p15: key %s may not be used for decryption\n", keyidstr); @@ -5979,17 +6025,18 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr, /* Find the authentication object to this private key object. */ if (!prkdf->authid) { - log_error ("p15: no authentication object defined for %s\n", keyidstr); - /* fixme: we might want to go ahead and do without PIN - verification. */ - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + log_info ("p15: no authentication object defined for %s\n", keyidstr); + aodf = NULL; + } + else + { + for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next) + if (aodf->objidlen == prkdf->authidlen + && !memcmp (aodf->objid, prkdf->authid, prkdf->authidlen)) + break; + if (!aodf) + log_info ("p15: no authentication for %s needed\n", keyidstr); } - for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next) - if (aodf->objidlen == prkdf->authidlen - && !memcmp (aodf->objid, prkdf->authid, prkdf->authidlen)) - break; - if (!aodf) - log_info ("p15: no authentication for %s needed\n", keyidstr); /* We need some more info about the key - get the keygrip to * populate these fields. */ @@ -6042,9 +6089,8 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr, { if (prkdf->is_ecc) { - /* Not implemented due to lacking test hardware. */ - log_info ("Note: ECC is not yet implemented for DTRUST 4 cards\n"); - err = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + err = iso7816_manage_security_env (app_get_slot (app), + 0xF3, 0x39, NULL, 0); } else { @@ -6274,7 +6320,8 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action, } else if (capability == GCRY_PK_USAGE_ENCR) { - if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap)) + if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap + || prkdf->usageflags.derive)) continue; } else if (capability == GCRY_PK_USAGE_AUTH) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index ad1e16a12..0fcd5a3d8 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -298,6 +298,23 @@ static int send_escape_cmd (ccid_driver_t handle, const unsigned char *data, size_t resultmax, size_t *resultlen); +static void +my_npth_unprotect (void) +{ +#ifdef USE_NPTH + npth_unprotect (); +#endif +} + +static void +my_npth_protect (void) +{ +#ifdef USE_NPTH + npth_protect (); +#endif +} + + static int map_libusb_error (int usberr) { @@ -984,31 +1001,23 @@ get_escaped_usb_string (libusb_device_handle *idev, int idx, /* First get the list of supported languages and use the first one. If we do don't find it we try to use English. Note that this is all in a 2 bute Unicode encoding using little endian. */ -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); rc = libusb_control_transfer (idev, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8), 0, buf, sizeof buf, 1000 /* ms timeout */); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); if (rc < 4) langid = 0x0409; /* English. */ else langid = (buf[3] << 8) | buf[2]; -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); rc = libusb_control_transfer (idev, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) + idx, langid, buf, sizeof buf, 1000 /* ms timeout */); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); if (rc < 2 || buf[1] != LIBUSB_DT_STRING) return NULL; /* Error or not a string. */ len = buf[0]; @@ -1345,13 +1354,9 @@ ccid_vendor_specific_setup (ccid_driver_t handle) { if (handle->id_vendor == VENDOR_SCM && handle->id_product == SCM_SPR532) { -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); libusb_clear_halt (handle->idev, handle->ep_intr); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); } return 0; } @@ -1660,13 +1665,9 @@ ccid_usb_thread (void *arg) while (ccid_usb_thread_is_alive) { -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); libusb_handle_events_completed (ctx, NULL); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); } return NULL; @@ -1776,36 +1777,42 @@ ccid_open_usb_reader (const char *spec_reader_name, goto leave; } -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); + if (!(opt.compat_flags & COMPAT_CCID_NO_AUTO_DETACH)) + { + rc = libusb_set_auto_detach_kernel_driver (idev, 1); + if (rc) + { + my_npth_protect (); + DEBUGOUT_1 ("note: set_auto_detach_kernel_driver failed: %d\n", rc); + my_npth_unprotect (); + } + } rc = libusb_claim_interface (idev, ifc_no); if (rc) { -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); rc = map_libusb_error (rc); goto leave; } /* Submit SET_INTERFACE control transfer which can reset the device. */ - rc = libusb_set_interface_alt_setting (idev, ifc_no, set_no); + if ((*handle)->id_vendor == VENDOR_ACR && (*handle)->id_product == ACR_122U) + rc = 0; /* Not supported by this reader. */ + else + rc = libusb_set_interface_alt_setting (idev, ifc_no, set_no); if (rc) { -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); DEBUGOUT_1 ("usb_set_interface_alt_setting failed: %d\n", rc); rc = map_libusb_error (rc); goto leave; } -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); + /* Perform any vendor specific intialization. */ rc = ccid_vendor_specific_init (*handle); leave: @@ -1939,13 +1946,9 @@ do_close_reader (ccid_driver_t handle) while (!handle->powered_off) { DEBUGOUT ("libusb_handle_events_completed\n"); -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); libusb_handle_events_completed (NULL, &handle->powered_off); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); } } @@ -2076,15 +2079,11 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen, } } -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_out, msg, msglen, &transferred, 5000 /* ms timeout */); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); if (rc == 0 && transferred == msglen) return 0; @@ -2124,14 +2123,10 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, memset (buffer, 0, length); retry: -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in, buffer, length, &msglen, bwi*timeout); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); if (rc) { DEBUGOUT_1 ("usb_bulk_read error: %s\n", libusb_error_name (rc)); @@ -2280,9 +2275,7 @@ abort_cmd (ccid_driver_t handle, int seqno, int init) /* Send the abort command to the control pipe. Note that we don't need to keep track of sent abort commands because there should never be another thread using the same slot concurrently. */ -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); rc = libusb_control_transfer (handle->idev, 0x21,/* bmRequestType: host-to-device, class specific, to interface. */ @@ -2291,9 +2284,7 @@ abort_cmd (ccid_driver_t handle, int seqno, int init) handle->ifc_no, dummybuf, 0, 1000 /* ms timeout */); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); if (rc) { DEBUGOUT_1 ("usb_control_msg error: %s\n", libusb_error_name (rc)); @@ -2319,15 +2310,11 @@ abort_cmd (ccid_driver_t handle, int seqno, int init) msglen = 10; set_msg_len (msg, 0); -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_out, msg, msglen, &transferred, init? 100: 5000 /* ms timeout */); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); if (rc == 0 && transferred == msglen) rc = 0; else if (rc) @@ -2337,15 +2324,11 @@ abort_cmd (ccid_driver_t handle, int seqno, int init) if (rc) return map_libusb_error (rc); -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in, msg, sizeof msg, &msglen, init? 100: 5000 /*ms timeout*/); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); if (rc) { DEBUGOUT_1 ("usb_bulk_read error in abort_cmd: %s\n", @@ -2559,14 +2542,10 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits, int on_wire) if (!retries) { DEBUGOUT ("USB: CALLING USB_CLEAR_HALT\n"); -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); libusb_clear_halt (handle->idev, handle->ep_bulk_in); libusb_clear_halt (handle->idev, handle->ep_bulk_out); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); } else DEBUGOUT ("USB: RETRYING bulk_in AGAIN\n"); @@ -3335,13 +3314,9 @@ ccid_transceive (ccid_driver_t handle, if (tpdulen < 4) { -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); libusb_clear_halt (handle->idev, handle->ep_bulk_in); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); return CCID_DRIVER_ERR_ABORTED; } @@ -3793,13 +3768,9 @@ ccid_transceive_secure (ccid_driver_t handle, if (tpdulen < 4) { -#ifdef USE_NPTH - npth_unprotect (); -#endif + my_npth_unprotect (); libusb_clear_halt (handle->idev, handle->ep_bulk_in); -#ifdef USE_NPTH - npth_protect (); -#endif + my_npth_protect (); return CCID_DRIVER_ERR_ABORTED; } if (debug_level > 1) diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 18cbc87f0..bac5fac07 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -70,6 +70,7 @@ enum { VENDOR_FSIJ = 0x234b, VENDOR_VASCO = 0x1a44, VENDOR_NXP = 0x1fc9, + VENDOR_ACR = 0x072f }; @@ -88,6 +89,7 @@ enum { #define VEGA_ALPHA 0x0008 #define CYBERJACK_GO 0x0504 #define CRYPTOUCAN 0x81e6 +#define ACR_122U 0x2200 /* NFC Reader */ #endif /*CCID_DRIVER_INCLUDE_USB_IDS*/ diff --git a/scd/scdaemon.c b/scd/scdaemon.c index e49b2ce42..2a9b0923c 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -104,6 +104,7 @@ enum cmd_and_opt_values oDisableApplication, oApplicationPriority, oEnablePinpadVarlen, + oCompatibilityFlags, oListenBacklog }; @@ -172,6 +173,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oDisableApplication, "disable-application", "@"), ARGPARSE_s_s (oApplicationPriority, "application-priority", N_("|LIST|change the application priority to LIST")), + ARGPARSE_s_s (oCompatibilityFlags, "compatibility-flags", "@"), ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"), @@ -204,6 +206,14 @@ static struct debug_flags_s debug_flags [] = }; +/* The list of compatibility flags. */ +static struct compatibility_flags_s compatibility_flags [] = + { + { COMPAT_CCID_NO_AUTO_DETACH, "ccid-no-auto-detach" }, + { 0, NULL } + }; + + /* The card driver we use by default for PC/SC. */ #if defined(HAVE_W32_SYSTEM) || defined(__CYGWIN__) #define DEFAULT_PCSC_DRIVER "winscard.dll" @@ -628,6 +638,15 @@ main (int argc, char **argv ) case oEnablePinpadVarlen: opt.enable_pinpad_varlen = 1; break; + case oCompatibilityFlags: + if (parse_compatibility_flags (pargs.r.ret_str, &opt.compat_flags, + compatibility_flags)) + { + pargs.r_opt = ARGPARSE_INVALID_ARG; + pargs.err = ARGPARSE_PRINT_WARNING; + } + break; + case oListenBacklog: listen_backlog = pargs.r.ret_int; break; diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 7b82d1b21..16873c54b 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -67,6 +67,9 @@ struct want to use. */ unsigned long card_timeout; /* Disconnect after N seconds of inactivity. */ int debug_allow_pin_logging; /* Allow PINs in debug output. */ + + /* Compatibility flags (COMPAT_FLAG_xxxx). */ + unsigned int compat_flags; } opt; @@ -92,6 +95,11 @@ struct #define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE) #define DBG_READER (opt.debug & DBG_READER_VALUE) + +#define COMPAT_CCID_NO_AUTO_DETACH 1 + + + struct server_local_s; struct card_ctx_s; struct app_ctx_s; |