diff -Nru acsccid-1.0.8/aclocal.m4 acsccid-1.1.0/aclocal.m4 --- acsccid-1.0.8/aclocal.m4 2014-07-03 02:07:52.000000000 +0000 +++ acsccid-1.1.0/aclocal.m4 2014-12-10 08:34:11.000000000 +0000 @@ -271,6 +271,66 @@ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) +# Copyright (C) 2011-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_AR([ACT-IF-FAIL]) +# ------------------------- +# Try to determine the archiver interface, and trigger the ar-lib wrapper +# if it is needed. If the detection of archiver interface fails, run +# ACT-IF-FAIL (default is to abort configure with a proper error message). +AC_DEFUN([AM_PROG_AR], +[AC_BEFORE([$0], [LT_INIT])dnl +AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([ar-lib])dnl +AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) +: ${AR=ar} + +AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], + [AC_LANG_PUSH([C]) + am_cv_ar_interface=ar + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], + [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + ]) + AC_LANG_POP([C])]) + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + m4_default([$1], + [AC_MSG_ERROR([could not determine $AR interface])]) + ;; +esac +AC_SUBST([AR])dnl +]) + # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. @@ -318,10 +378,9 @@ # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], -[dnl Rely on autoconf to set up CDPATH properly. -AC_PREREQ([2.50])dnl -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- @@ -1001,35 +1060,6 @@ fi ]) -# -*- Autoconf -*- -# Obsolete and "removed" macros, that must however still report explicit -# error messages when used, to smooth transition. -# -# Copyright (C) 1996-2013 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -AC_DEFUN([AM_CONFIG_HEADER], -[AC_DIAGNOSE([obsolete], -['$0': this macro is obsolete. -You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl -AC_CONFIG_HEADERS($@)]) - -AC_DEFUN([AM_PROG_CC_STDC], -[AC_PROG_CC -am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc -AC_DIAGNOSE([obsolete], -['$0': this macro is obsolete. -You should simply use the 'AC][_PROG_CC' macro instead. -Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', -but upon 'ac_cv_prog_cc_stdc'.])]) - -AC_DEFUN([AM_C_PROTOTYPES], - [AC_FATAL([automatic de-ANSI-fication support has been removed])]) -AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) - # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. diff -Nru acsccid-1.0.8/ChangeLog acsccid-1.1.0/ChangeLog --- acsccid-1.0.8/ChangeLog 2014-07-03 02:09:51.000000000 +0000 +++ acsccid-1.1.0/ChangeLog 2014-12-10 08:34:49.000000000 +0000 @@ -1,3 +1,892 @@ +2014-12-08 Godfrey Chung + + * README: Update README for v1.1.0. + +2014-12-10 Godfrey Chung + + * src/ccid_usb.c: Convert ACR38 card status message in + Multi_PollingProc(). + +2014-12-08 Godfrey Chung + + * src/Makefile.am: Remove the files from EXTRA_DIST in + src/Makefile.am. pcscd_acsccid.rules 92_pcscd_acsccid_group.rules + +2014-12-08 Godfrey Chung + + * src/92_pcscd_acsccid_group.rules: Remove + src/92_pcscd_acsccid_group.rules. + +2014-12-08 Godfrey Chung + + * src/pcscd_acsccid.rules: Remove src/pcscd_acsccid.rules. + +2014-12-08 Godfrey Chung + + * INSTALL: Remove libusb version from INSTALL. + +2014-12-08 Godfrey Chung + + * NEWS: Import NEWS from ccid 1.4.18. + +2014-12-08 Godfrey Chung + + * configure.ac: Update the version to 1.1.0 in configure.ac. + +2014-12-08 Godfrey Chung + + * src/ccid.c: Disable InterruptRead() on Mac OS X in + ccid_open_hack_pre(). + +2014-12-08 Godfrey Chung + + * src/ccid.c: Enable InterruptRead() for ACR38 in + ccid_open_hack_pre(). + +2014-12-05 Godfrey Chung + + * MacOSX/configure: Add ppc to CFLAGS if Mac OS X 10.6 SDK exists in + MacOSX/configure. + +2014-12-05 Godfrey Chung + + * MacOSX/configure: Remove -isysroot from CFLAGS in + MacOSX/configure. + +2014-12-05 Godfrey Chung + + * src/commands.c: Update the copyright in src/commands.c. + +2014-12-05 Godfrey Chung + + * src/ccid_ifdhandler.h: Update the copyright in + src/ccid_ifdhandler.h. + +2014-12-05 Godfrey Chung + + * src/acr38cmd.c: Update the copyright in src/acr38cmd.c. + +2014-12-05 Godfrey Chung + + * src/ccid.c: Update the copyright in src/ccid.c. + +2014-12-05 Godfrey Chung + + * src/ccid_usb.c: Disable multislot extension for ACR85 in + OpenUSBByName(). + +2014-12-05 Godfrey Chung + + * src/ccid_usb.c: Replace InterruptRead() in CardDetectionThread(). + +2014-12-05 Godfrey Chung + + * src/ccid_usb.c: Cancel the transfer and free transfer lock in + CloseUSB(). + +2014-12-08 Godfrey Chung + + * src/ccid_usb.c: Initialize the pointer to libusb transfer in + OpenUSBByName(). + +2014-12-05 Godfrey Chung + + * src/ccid_usb.c: Create transfer lock in OpenUSBByName(). + +2014-12-08 Godfrey Chung + + * src/ccid_usb.c: Add the pointer to libusb transfer to _usbDevice + in src/ccid_usb.c. + +2014-12-05 Godfrey Chung + + * src/ccid_usb.c: Add libusb transfer lock to _usbDevice in + src/ccid_usb.c. + +2014-12-05 Godfrey Chung + + * src/ccid_usb.c: Disable multislot extension on Mac OS X in + OpenUSBByName(). + +2014-12-05 Godfrey Chung + + * src/ccid_usb.c: Remove bStatus lock/unlock from InterruptRead(). + +2014-12-04 Godfrey Chung + + * src/ccid_usb.c: Check rv < 0 for libusb_submit_transfer() in + Multi_PollingProc(). + +2014-12-04 Godfrey Chung + + * src/ccid_usb.c: Add missing libusb_free_transfer() to + Multi_PollingProc(). + +2014-12-03 Godfrey Chung + + * src/ifdhandler.c: Fix parentheses warning in IFDHICCPresence(). + +2014-12-03 Godfrey Chung + + * src/ifdhandler.c: Fix parentheses warning in IFDHPowerICC(). + +2014-12-03 Godfrey Chung + + * src/ifdhandler.c: Fix parentheses warning in + IFDHSetProtocolParameters(). + +2014-12-03 Godfrey Chung + + * src/acr38cmd.c: Remove IFD_ERROR_INSUFFICIENT_BUFFER from + src/acr38cmd.c. + +2014-12-03 Godfrey Chung + + * src/ccid_usb.c: Include in src/ccid_usb.c. + +2014-12-03 Godfrey Chung + + * src/ifdhandler.c: Fix data type warning in init_driver(). + +2014-12-03 Godfrey Chung + + * src/ifdhandler.c: Fix data type warning in + IFDHSetProtocolParameters(). + +2014-12-03 Godfrey Chung + + * src/acr38cmd.c: Fix data type warning in ACR38_SetCardType(). + +2014-12-03 Godfrey Chung + + * src/acr38cmd.c: Remove unused ccid_descriptor from + ACR38_GetFirmwareVersion(). + +2014-12-03 Godfrey Chung + + * src/acr38cmd.c: Update the included headers in src/acr38cmd.c. + +2014-12-03 Godfrey Chung + + * src/ifdhandler.c: Remove unused slot_index from + IFDHTransmitToICC(). + +2014-12-03 Godfrey Chung + + * src/ccid_usb.c: Remove unused tempLen from ReadUSB(). + +2014-12-03 Godfrey Chung + + * src/ccid.c: Fix incorrect data type for responseLen in + EnablePicc(). + +2014-12-03 Godfrey Chung + + * src/ifdhandler.c: Replace DEBUG_INFO with DEBUG_INFO1 in + IFDHICCPresence(). + +2014-12-03 Godfrey Chung + + * src/ccid.c: Replace DEBUG_INFO with DEBUG_INFO1 in + ccid_open_hack_post(). + +2014-12-01 Godfrey Chung + + * src/ifdhandler.c: Enable polling thread for ACR38 in + IFDHGetCapabilities(). + +2014-11-28 Godfrey Chung + + * src/ifdhandler.c: Remove InterruptRead() from IFDHICCPresence(). + +2014-11-28 Godfrey Chung + + * src/ifdhandler.c: Return the properties for ACR83, APG8201 and + APG8201Z in IFDHControl(). bMinPINSize, bMaxPINSize and bEntryValidationCondition. + +2014-11-28 Godfrey Chung + + * src/ifdhandler.c: Enable bPPDUSupport in IFDHControl(). + +2014-11-28 Godfrey Chung + + * src/ifdhandler.c: Use IOCTL_CCID_ESCAPE for + FEATURE_CCID_ESC_COMMAND in IFDHControl(). + +2014-11-28 Godfrey Chung + + * src/commands.c: Set infinite timeout in CmdEscape(). + +2014-11-28 Godfrey Chung + + * src/Info.plist.src, src/ccid_ifdhandler.h, src/ifdhandler.c: Move + REMOVE_PUPI_FROM_ATR and DISABLE_PICC to ifdACSDriverOptions. + +2014-11-27 Godfrey Chung + + * src/Info.plist.src: Merge src/Info.plist.src from ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ccid.c: Set the timeout to zero in + ACR1222_GetFirmwareVersion(). + +2014-11-27 Godfrey Chung + + * src/ccid.c: Set the timeout to zero in ACR83_DisplayLcdMessage(). + +2014-11-27 Godfrey Chung + + * src/ccid.c: Set the timeout to zero in ACR83_GetFirmwareVersion(). + +2014-11-27 Godfrey Chung + + * src/ccid.c: Set the timeout to zero in EnablePicc(). + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Merge T1_card_timeout() in src/ifdhandler.c from + ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Merge T0_card_timeout() in src/ifdhandler.c from + ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Merge extra_egt() in src/ifdhandler.c from ccid + 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Merge init_driver() in src/ifdhandler.c from + ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHICCPresence() in src/ifdhandler.c from + ccid 1.4.18. + +2014-12-02 Godfrey Chung + + * src/ifdhandler.c: Allow 7 records for CM_IOCTL_GET_FEATURE_REQUEST + in IFDHControl(). + +2014-12-02 Godfrey Chung + + * src/ifdhandler.c: Set the timeout in IFDHControl(). + +2014-12-02 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHControl() in src/ifdhandler.c from + ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Remove the checking of PROTOCOL_ACR38 from + IFDHControl(). + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHTransmitToICC() in src/ifdhandler.c + from ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHPowerICC() in src/ifdhandler.c from + ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHSetProtocolParameters() in + src/ifdhandler.c from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHSetCapabilities() in src/ifdhandler.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHGetCapabilities() in src/ifdhandler.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Add IFDHStopPolling() in src/ifdhandler.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHSleep() in src/ifdhandler.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHPolling() in src/ifdhandler.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHCloseChannel() in src/ifdhandler.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHCreateChannel() in src/ifdhandler.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Merge IFDHCreateChannelByName() in + src/ifdhandler.c from ccid 1.4.18. + +2014-12-01 Godfrey Chung + + * src/ifdhandler.c: Remove the prototypes from src/ifdhandler.c. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Remove IFD_ERROR_INSUFFICIENT_BUFFER from + src/ifdhandler.c. + +2014-12-01 Godfrey Chung + + * src/ifdhandler.c: Merge the included headers in src/ifdhandler.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ifdhandler.c: Merge the copyright in src/ifdhandler.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.h: Import src/commands.h from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Add bei2i() to src/commands.c from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge SetParameters() in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge CmdXfrBlockCHAR_T0() in src/commands.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge T0ProcACK() in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge CmdXfrBlockAPDU_extended() in src/commands.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge CCID_Receive() in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge CCID_Transmit() in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Remove space character from CmdXfrBlock(). + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge CmdGetSlotStatus() in src/commands.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge CmdPowerOff() in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge CmdEscape() in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge SecurePINModify() in src/commands.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Add has_gemalto_modify_pin_bug() to src/commands.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge SecurePINVerify() in src/commands.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge CmdPowerOn() in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge prototypes in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge the macros in src/commands.c from ccid + 1.4.18. + +2014-12-01 Godfrey Chung + + * src/commands.c: Merge the included headers in src/commands.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/commands.c: Merge the copyright in src/commands.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.h: Import src/ccid_usb.h from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Add Multi_CreateNextSlot() to src/ccid_usb.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Add Multi_CreateFirstSlot() to src/ccid_usb.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Add Multi_InterruptStop() to src/ccid_usb.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Add Multi_InterruptRead() to src/ccid_usb.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Add Multi_PollingTerminate() to src/ccid_usb.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Add Multi_PollingProc() to src/ccid_usb.c from + ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ccid_usb.c: Add InterruptStop() to src/ccid_usb.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge InterruptRead() in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Add bulk_transfer_cb() to src/ccid_usb.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge ControlUSB() in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge get_data_rates() in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge ccid_check_firmware() in src/ccid_usb.c from + ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge get_ccid_usb_interface() in src/ccid_usb.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge get_end_points() in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Add get_ccid_device_descriptor() to src/ccid_usb.c + from ccid 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge CloseUSB() in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge ReadUSB() in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-26 Godfrey Chung + + * src/ccid_usb.c: Merge WriteUSB() in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Merge the changes to OpenUSBByName(). + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Import OpenUSBByName() to src/ccid_usb.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Merge OpenUSB() in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Add close_libusb_if_needed() to src/ccid_usb.c + from ccid 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Merge Bogus_firmwares in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Merge the macros in src/ccid_usb.c from ccid + 1.4.18. PCSCLITE_MANUKEY_NAME, PCSCLITE_PRODKEY_NAME and + PCSCLITE_NAMEKEY_NAME. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Merge prototypes in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Merge _usbDevice in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Add usbDevice_MultiSlot_Extension to + src/ccid_usb.c from ccid 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Add CCID_INTERRUPT_SIZE to src/ccid_usb.c from + ccid 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Add libusb context to src/ccid_usb.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Merge the macros in src/ccid_usb.c from ccid + 1.4.18. USB_WRITE_TIMEOUT and ALLOW_PROPRIETARY_CLASS. + +2014-12-01 Godfrey Chung + + * src/ccid_usb.c: Merge the included headers in src/ccid_usb.c from + ccid 1.4.18. + +2014-11-27 Godfrey Chung + + * src/ccid_usb.c: Merge the copyright in src/ccid_usb.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid_usb.c: Revert "Abort the interrupt pipe on Mac OS X." This reverts commit 15c6aa0addd7d41ab179d30c60ab343dc8b53599. + +2014-11-25 Godfrey Chung + + * src/ccid_ifdhandler.h: Merge src/ccid_ifdhandler.h from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid.h: Merge src/ccid.h from ccid 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid.c: Add NO_LOG to acr38_error(). + +2014-11-25 Godfrey Chung + + * src/ccid.c: Merge ccid_error() from ccid 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid.c: Merge ccid_open_hack_post() from ccid 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid.c: Add set_gemalto_firmware_features() to src/ccid.c from + ccid 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid.c: Add dump_gemalto_firmware_features() to src/ccid.c + from ccid 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid.c: Merge ccid_open_hack_pre() from ccid 1.4.18. + +2014-12-01 Godfrey Chung + + * src/ccid.c: Merge the included headers in src/ccid.c from ccid + 1.4.18. + +2014-11-25 Godfrey Chung + + * src/ccid.c: Merge the copyright in src/ccid.c from ccid 1.4.18. + +2014-11-24 Godfrey Chung + + * src/Makefile.am: Add simclist.c and simclist.h to TOKEN_PARSER in + src/Makefile.am. + +2014-11-24 Godfrey Chung + + * src/defs.h: Merge src/defs.h from ccid 1.4.18. + +2014-11-24 Godfrey Chung + + * Makefile.am: Rename reader.h.in to reader.h in Makefile.am. + +2014-11-21 Godfrey Chung + + * MacOSX/configure: Import MacOSX/configure from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * MacOSX/reader.h.in: Remove MacOSX/reader.h.in. + +2014-11-21 Godfrey Chung + + * MacOSX/reader.h: Import MacOSX/reader.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * MacOSX/ifdhandler.h: Import MacOSX/ifdhandler.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * MacOSX/debuglog.h: Import MacOSX/debuglog.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/towitoko/pps.c: Merge src/towitoko/pps.c from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/towitoko/defines.h: Import src/towitoko/defines.h from ccid + 1.4.18. + +2014-11-21 Godfrey Chung + + * src/towitoko/atr.h: Import src/towitoko/atr.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/towitoko/atr.c: Import src/towitoko/atr.c from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/openct/proto-t1.h: Import src/openct/proto-t1.h from ccid + 1.4.18. + +2014-11-21 Godfrey Chung + + * src/openct/proto-t1.c: Merge src/openct/proto-t1.c from ccid + 1.4.18. + +2014-11-21 Godfrey Chung + + * src/openct/checksum.h: Import src/openct/checksum.h from ccid + 1.4.18. + +2014-11-21 Godfrey Chung + + * src/openct/checksum.c: Import src/openct/checksum.c from ccid + 1.4.18. + +2014-11-21 Godfrey Chung + + * src/openct/buffer.h: Import src/openct/buffer.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/openct/buffer.c: Import src/openct/buffer.c from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/utils.h: Import src/utils.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/utils.c: Import src/utils.c from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/tokenparser.l: Import src/tokenparser.l from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/strlcpycat.h: Import src/strlcpycat.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/simclist.h: Import src/simclist.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/simclist.c: Import src/simclist.c from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/parser.h: Import src/parser.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/misc.h: Import src/misc.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/debug.h: Import src/debug.h from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/debug.c: Import src/debug.c from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/create_Info_plist.pl: Import src/create_Info_plist.pl from + ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/convert_version.pl: Import src/convert_version.pl from ccid + 1.4.18. + +2014-11-21 Godfrey Chung + + * m4/ax_pthread.m4: Import m4/ax_pthread.m4 from ccid 1.4.18. + +2014-11-21 Godfrey Chung + + * src/Makefile.am: Remove --ifdCapabilities and --bundle from + src/Makefile.am. + +2014-11-21 Godfrey Chung + + * src/Makefile.am: Remove UDEV from src/Makefile.am. + +2014-11-21 Godfrey Chung + + * configure.ac: Remove udev from configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Remove use_usb_interrupt from configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Add --enable-embedded option to configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Remove --enable-udev option from configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Replace ACX_PTHREAD with AX_PTHREAD in configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Replace AC_HELP_STRING with AS_HELP_STRING in + configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Replace libusb 0.1.12 with 1.0.8 in configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Use uname to return OS in configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Add stdio.h to AC_CHECK_HEADERS in configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Update PCSC_NEEDED_VERSION to 1.8.3 in configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Add AM_PROG_AR to configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Replace AM_CONFIG_HEADER with AC_CONFIG_HEADERS in + configure.ac. + +2014-11-21 Godfrey Chung + + * configure.ac: Update AC_PREREQ to 2.69 in configure.ac. + +2014-08-15 Godfrey Chung + + * src/supported_readers.txt: Add supported readers. ACR1255U-J1 PICC Reader. + +2014-09-10 Godfrey Chung + + * src/ccid.c: Fix the PICC detection problem in ACR1281 2S CL + Reader. + +2014-08-15 Godfrey Chung + + * src/supported_readers.txt: Correct the product code in + src/supported_readers.txt. + +2014-08-15 Godfrey Chung + + * README: Correct the product code in README. + +2014-07-04 Godfrey Chung + + * README: Correct the reader name in README. + 2014-07-03 Godfrey Chung * README: Update README for v1.0.8. diff -Nru acsccid-1.0.8/config/ar-lib acsccid-1.1.0/config/ar-lib --- acsccid-1.0.8/config/ar-lib 1970-01-01 00:00:00.000000000 +0000 +++ acsccid-1.1.0/config/ar-lib 2014-12-10 08:34:13.000000000 +0000 @@ -0,0 +1,270 @@ +#! /bin/sh +# Wrapper for Microsoft lib.exe + +me=ar-lib +scriptversion=2012-03-01.08; # UTC + +# Copyright (C) 2010-2013 Free Software Foundation, Inc. +# Written by Peter Rosin . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + + +# func_error message +func_error () +{ + echo "$me: $1" 1>&2 + exit 1 +} + +file_conv= + +# func_file_conv build_file +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv in + mingw) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_at_file at_file operation archive +# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE +# for each of them. +# When interpreting the content of the @FILE, do NOT use func_file_conv, +# since the user would need to supply preconverted file names to +# binutils ar, at least for MinGW. +func_at_file () +{ + operation=$2 + archive=$3 + at_file_contents=`cat "$1"` + eval set x "$at_file_contents" + shift + + for member + do + $AR -NOLOGO $operation:"$member" "$archive" || exit $? + done +} + +case $1 in + '') + func_error "no command. Try '$0 --help' for more information." + ;; + -h | --h*) + cat < header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBUSB_H + /* Define to 1 if you have the `memcpy' function. */ #undef HAVE_MEMCPY @@ -27,6 +30,9 @@ /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD +/* Have PTHREAD_PRIO_INHERIT. */ +#undef HAVE_PTHREAD_PRIO_INHERIT + /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT @@ -36,6 +42,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H @@ -72,16 +81,13 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H -/* Define if usb_detach_kernel_driver_np() is available */ -#undef HAVE_USB_DETACH_KERNEL_DRIVER_NP - -/* Define to 1 if you have the header file. */ -#undef HAVE_USB_H - /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR +/* Disable logging support */ +#undef NO_LOG + /* Name of package */ #undef PACKAGE @@ -119,9 +125,6 @@ /* composite device are seen as multi-slots */ #undef USE_COMPOSITE_AS_MULTISLOT -/* use libusb usb_interrupt_read() instead of polling */ -#undef USE_USB_INTERRUPT - /* Version number of package */ #undef VERSION diff -Nru acsccid-1.0.8/configure acsccid-1.1.0/configure --- acsccid-1.0.8/configure 2014-07-03 02:07:53.000000000 +0000 +++ acsccid-1.1.0/configure 2014-12-10 08:34:12.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for acsccid 1.0.8. +# Generated by GNU Autoconf 2.69 for acsccid 1.1.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ # Identity of this package. PACKAGE_NAME='acsccid' PACKAGE_TARNAME='acsccid' -PACKAGE_VERSION='1.0.8' -PACKAGE_STRING='acsccid 1.0.8' +PACKAGE_VERSION='1.1.0' +PACKAGE_STRING='acsccid 1.1.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -638,8 +638,6 @@ bundle ac_aux_dir NOCLASS -UDEV_FALSE -UDEV_TRUE WITHOUT_PCSC_FALSE WITHOUT_PCSC_TRUE PTHREAD_CFLAGS @@ -647,7 +645,8 @@ PTHREAD_CC ax_pthread_config SYMBOL_VISIBILITY -LIBUSBCONFIG +WITH_LIBUSB_FALSE +WITH_LIBUSB_TRUE LIBUSB_LIBS LIBUSB_CFLAGS DYN_LIB_EXT @@ -660,8 +659,6 @@ DSYMUTIL MANIFEST_TOOL RANLIB -ac_ct_AR -AR DLLTOOL OBJDUMP NM @@ -678,6 +675,8 @@ PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG +ac_ct_AR +AR LEXLIB LEX_OUTPUT_ROOT LEX @@ -789,12 +788,12 @@ with_gnu_ld with_sysroot enable_libtool_lock -enable_usb_interrupt +enable_libusb enable_composite_as_multislot enable_multi_thread enable_usbdropdir enable_pcsclite -enable_udev +enable_embedded ' ac_precious_vars='build_alias host_alias @@ -1352,7 +1351,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures acsccid 1.0.8 to adapt to many kinds of systems. +\`configure' configures acsccid 1.1.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1422,7 +1421,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of acsccid 1.0.8:";; + short | recursive ) echo "Configuration of acsccid 1.1.0:";; esac cat <<\_ACEOF @@ -1444,15 +1443,15 @@ --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) - --enable-usb-interrupt force the use of USB interrupt even with an old - libusb + --disable-libusb do not use libusb --enable-composite-as-multislot composite device are seen as multi-slots --disable-multi-thread disable multi threading --enable-usbdropdir=DIR directory containing USB drivers (default to pcscd config or $(prefix)/pcsc/drivers) --disable-pcsclite do not use pcsc-lite debug support - --enable-udev udev support for pcscd hotplug + --enable-embedded limit RAM and CPU ressources by disabling features + (log) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1549,7 +1548,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -acsccid configure 1.0.8 +acsccid configure 1.1.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1968,7 +1967,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by acsccid $as_me 1.0.8, which was +It was created by acsccid $as_me 1.1.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2518,8 +2517,8 @@ ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in @@ -2832,7 +2831,7 @@ # Define the identity of the package. PACKAGE='acsccid' - VERSION='1.0.8' + VERSION='1.1.0' cat >>confdefs.h <<_ACEOF @@ -4457,6 +4456,177 @@ if test "$LEX" = :; then LEX=${am_missing_run}flex fi +if test -n "$ac_tool_prefix"; then + for ac_prog in ar lib "link -lib" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar lib "link -lib" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 +$as_echo_n "checking the archiver ($AR) interface... " >&6; } +if ${am_cv_ar_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + am_cv_ar_interface=ar + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int some_variable = 0; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 + (eval $am_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 + (eval $am_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 +$as_echo "$am_cv_ar_interface" >&6; } + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + as_fn_error $? "could not determine $AR interface" "$LINENO" 5 + ;; +esac + @@ -4579,7 +4749,7 @@ fi # check pcsc-lite version -PCSC_NEEDED_VERSION="1.3.3" +PCSC_NEEDED_VERSION="1.8.3" if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcsclite\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpcsclite") 2>&5 @@ -12194,7 +12364,7 @@ fi -for ac_header in errno.h fcntl.h stdlib.h unistd.h termios.h string.h sys/time.h sys/types.h stdarg.h arpa/inet.h +for ac_header in errno.h fcntl.h stdlib.h unistd.h termios.h string.h sys/time.h sys/types.h stdarg.h arpa/inet.h stdio.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -12356,37 +12526,33 @@ # Select OS specific versions of source files. -case "$host" in -*-*-darwin*) - BUNDLE_HOST="MacOS" +BUNDLE_HOST=`uname | sed -e s,/,_,` +DYN_LIB_EXT="so" +case "$BUNDLE_HOST" in +Darwin) + BUNDLE_HOST=MacOS DYN_LIB_EXT="dylib" ;; -*-*-freebsd*) - BUNDLE_HOST="FreeBSD" - DYN_LIB_EXT="so" - ;; -*-*-openbsd*) - BUNDLE_HOST="OpenBSD" - DYN_LIB_EXT="so.0.0" +SunOS) + BUNDLE_HOST=Solaris ;; -*-*-solaris*) - BUNDLE_HOST="Solaris" - DYN_LIB_EXT="so" - ;; -*-*-dragonfly*) - BUNDLE_HOST="DragonFly" - DYN_LIB_EXT="so" - ;; -*) - BUNDLE_HOST="Linux" - DYN_LIB_EXT="so" -esac + esac -use_usb_interrupt=no +# --disable-libusb +# Check whether --enable-libusb was given. +if test "${enable_libusb+set}" = set; then : + enableval=$enable_libusb; use_libusb="${enableval}" +else + use_libusb=yes +fi -if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libusb") 2>&5 + +# check if libusb is used +LIBUSB_NEEDED_VERSION="1.0.8" +if test "x$use_libusb" != xno ; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libusb-1.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then @@ -12400,12 +12566,12 @@ pkg_cv_LIBUSB_CFLAGS="$LIBUSB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libusb") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0 >= \$LIBUSB_NEEDED_VERSION\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libusb-1.0 >= $LIBUSB_NEEDED_VERSION") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_LIBUSB_CFLAGS=`$PKG_CONFIG --cflags "libusb" 2>/dev/null` + pkg_cv_LIBUSB_CFLAGS=`$PKG_CONFIG --cflags "libusb-1.0 >= $LIBUSB_NEEDED_VERSION" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -12417,12 +12583,12 @@ pkg_cv_LIBUSB_LIBS="$LIBUSB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libusb") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0 >= \$LIBUSB_NEEDED_VERSION\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libusb-1.0 >= $LIBUSB_NEEDED_VERSION") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_LIBUSB_LIBS=`$PKG_CONFIG --libs "libusb" 2>/dev/null` + pkg_cv_LIBUSB_LIBS=`$PKG_CONFIG --libs "libusb-1.0 >= $LIBUSB_NEEDED_VERSION" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -12443,110 +12609,198 @@ _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - LIBUSB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libusb" 2>&1` + LIBUSB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libusb-1.0 >= $LIBUSB_NEEDED_VERSION" 2>&1` else - LIBUSB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libusb" 2>&1` + LIBUSB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libusb-1.0 >= $LIBUSB_NEEDED_VERSION" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBUSB_PKG_ERRORS" >&5 - # Extract the first word of "libusb-config", so it can be a program name with args. -set dummy libusb-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_LIBUSBCONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$LIBUSBCONFIG"; then - ac_cv_prog_LIBUSBCONFIG="$LIBUSBCONFIG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_LIBUSBCONFIG="yes" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: install libusb $LIBUSB_NEEDED_VERSION or later" >&5 +$as_echo "$as_me: WARNING: install libusb $LIBUSB_NEEDED_VERSION or later" >&2;} + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBUSB" >&5 +$as_echo_n "checking for LIBUSB... " >&6; } +if test -n "$LIBUSB_CFLAGS"; then + pkg_cv_LIBUSB_CFLAGS="$LIBUSB_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libusb-1.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBUSB_CFLAGS=`$PKG_CONFIG --cflags "libusb-1.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes fi + else + pkg_failed=untried fi -LIBUSBCONFIG=$ac_cv_prog_LIBUSBCONFIG -if test -n "$LIBUSBCONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBUSBCONFIG" >&5 -$as_echo "$LIBUSBCONFIG" >&6; } +if test -n "$LIBUSB_LIBS"; then + pkg_cv_LIBUSB_LIBS="$LIBUSB_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libusb-1.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBUSB_LIBS=`$PKG_CONFIG --libs "libusb-1.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no fi + if test $_pkg_short_errors_supported = yes; then + LIBUSB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libusb-1.0" 2>&1` + else + LIBUSB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libusb-1.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBUSB_PKG_ERRORS" >&5 + as_fn_error $? "Package requirements (libusb-1.0) were not met: +$LIBUSB_PKG_ERRORS - if test "$LIBUSBCONFIG" = "yes" ; then - LIBUSB_CFLAGS="$LIBUSB_CFLAGS `libusb-config --cflags`" - LIBUSB_LIBS="$LIBUSB_LIBS `libusb-config --libs`" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libusb-config not found." >&5 -$as_echo "$as_me: WARNING: libusb-config not found." >&2;} - fi +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. +Alternatively, you may set the environment variables LIBUSB_CFLAGS +and LIBUSB_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables LIBUSB_CFLAGS +and LIBUSB_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. - # Extract the first word of "libusb-config", so it can be a program name with args. -set dummy libusb-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_LIBUSBCONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$LIBUSBCONFIG"; then - ac_cv_prog_LIBUSBCONFIG="$LIBUSBCONFIG" # Let the user override the test. +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_LIBUSBCONFIG="yes" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS + LIBUSB_CFLAGS=$pkg_cv_LIBUSB_CFLAGS + LIBUSB_LIBS=$pkg_cv_LIBUSB_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } fi + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: install libusb $LIBUSB_NEEDED_VERSION or later" >&5 +$as_echo "$as_me: WARNING: install libusb $LIBUSB_NEEDED_VERSION or later" >&2;} + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBUSB" >&5 +$as_echo_n "checking for LIBUSB... " >&6; } + +if test -n "$LIBUSB_CFLAGS"; then + pkg_cv_LIBUSB_CFLAGS="$LIBUSB_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libusb-1.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBUSB_CFLAGS=`$PKG_CONFIG --cflags "libusb-1.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes fi -LIBUSBCONFIG=$ac_cv_prog_LIBUSBCONFIG -if test -n "$LIBUSBCONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBUSBCONFIG" >&5 -$as_echo "$LIBUSBCONFIG" >&6; } + else + pkg_failed=untried +fi +if test -n "$LIBUSB_LIBS"; then + pkg_cv_LIBUSB_LIBS="$LIBUSB_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libusb-1.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBUSB_LIBS=`$PKG_CONFIG --libs "libusb-1.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no fi + if test $_pkg_short_errors_supported = yes; then + LIBUSB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libusb-1.0" 2>&1` + else + LIBUSB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libusb-1.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBUSB_PKG_ERRORS" >&5 + as_fn_error $? "Package requirements (libusb-1.0) were not met: +$LIBUSB_PKG_ERRORS - if test "$LIBUSBCONFIG" = "yes" ; then - LIBUSB_CFLAGS="$LIBUSB_CFLAGS `libusb-config --cflags`" - LIBUSB_LIBS="$LIBUSB_LIBS `libusb-config --libs`" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libusb-config not found." >&5 -$as_echo "$as_me: WARNING: libusb-config not found." >&2;} - fi +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables LIBUSB_CFLAGS +and LIBUSB_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables LIBUSB_CFLAGS +and LIBUSB_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } else LIBUSB_CFLAGS=$pkg_cv_LIBUSB_CFLAGS LIBUSB_LIBS=$pkg_cv_LIBUSB_LIBS @@ -12555,32 +12809,40 @@ fi +else + LIBUSB_CFLAGS=$pkg_cv_LIBUSB_CFLAGS + LIBUSB_LIBS=$pkg_cv_LIBUSB_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi -saved_CPPFLAGS="$CPPFLAGS" -saved_LIBS="$LIBS" +fi + + saved_CPPFLAGS="$CPPFLAGS" + saved_LIBS="$LIBS" -CPPFLAGS="$CPPFLAGS $LIBUSB_CFLAGS" -LIBS="$LDFLAGS $LIBUSB_LIBS" + CPPFLAGS="$CPPFLAGS $LIBUSB_CFLAGS" + LIBS="$LDFLAGS $LIBUSB_LIBS" -for ac_header in usb.h + for ac_header in libusb.h do : - ac_fn_c_check_header_mongrel "$LINENO" "usb.h" "ac_cv_header_usb_h" "$ac_includes_default" -if test "x$ac_cv_header_usb_h" = xyes; then : + ac_fn_c_check_header_mongrel "$LINENO" "libusb.h" "ac_cv_header_libusb_h" "$ac_includes_default" +if test "x$ac_cv_header_libusb_h" = xyes; then : cat >>confdefs.h <<_ACEOF -#define HAVE_USB_H 1 +#define HAVE_LIBUSB_H 1 _ACEOF else - as_fn_error $? "usb.h not found, install libusb or use ./configure LIBUSB_CFLAGS=..." "$LINENO" 5 + as_fn_error $? "libusb.h not found, install libusb or use ./configure LIBUSB_CFLAGS=..." "$LINENO" 5 fi done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for usb_init" >&5 -$as_echo_n "checking for usb_init... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libusb_init" >&5 +$as_echo_n "checking for libusb_init... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -12589,11 +12851,11 @@ #ifdef __cplusplus extern "C" #endif -char usb_init (); +char libusb_init (); int main () { -return usb_init (); +return libusb_init (); ; return 0; } @@ -12607,77 +12869,22 @@ rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for usb_interrupt_read" >&5 -$as_echo_n "checking for usb_interrupt_read... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char usb_interrupt_read (); -int -main () -{ -return usb_interrupt_read (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - as_fn_error $? "your libusb is too old. install version 0.1.12 or above" "$LINENO" 5 -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -ac_fn_c_check_func "$LINENO" "usb_detach_kernel_driver_np" "ac_cv_func_usb_detach_kernel_driver_np" -if test "x$ac_cv_func_usb_detach_kernel_driver_np" = xyes; then : - -$as_echo "#define HAVE_USB_DETACH_KERNEL_DRIVER_NP 1" >>confdefs.h + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" + use_libusb=yes fi -CPPFLAGS="$saved_CPPFLAGS" -LIBS="$saved_LIBS" - -use_libusb=yes - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libusb is emulated by libusb-compat" >&5 -$as_echo_n "checking if libusb is emulated by libusb-compat... " >&6; } -a=`$PKG_CONFIG --variable=emulated libusb` -if test "x$a" = "x1"; -then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - use_usb_interrupt=yes + if test "${use_libusb}" != "no"; then + WITH_LIBUSB_TRUE= + WITH_LIBUSB_FALSE='#' else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + WITH_LIBUSB_TRUE='#' + WITH_LIBUSB_FALSE= fi - - -# --enable-usb-interrupt -# Check whether --enable-usb-interrupt was given. -if test "${enable_usb_interrupt+set}" = set; then : - enableval=$enable_usb_interrupt; use_usb_interrupt="${enableval}" -fi - - -if test "x$use_usb_interrupt" = xyes; then - -$as_echo "#define USE_USB_INTERRUPT 1" >>confdefs.h - -fi - # --enable-composite-as-multislot use_composite_as_multislot=no # Check whether --enable-composite-as-multislot was given. @@ -12725,7 +12932,6 @@ if test "${multithread}" != no ; then - ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -12813,8 +13019,8 @@ # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case "${host_cpu}-${host_os}" in - *solaris*) +case ${host_os} in + solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based @@ -12827,9 +13033,9 @@ ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; - *-darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" - ;; + darwin*) + ax_pthread_flags="-pthread $ax_pthread_flags" + ;; esac if test x"$ax_pthread_ok" = xno; then @@ -12847,8 +13053,8 @@ PTHREAD_CFLAGS="$flag" ;; - pthread-config) - # Extract the first word of "pthread-config", so it can be a program name with args. + pthread-config) + # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } @@ -12886,10 +13092,10 @@ fi - if test x"$ax_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; + if test x"$ax_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 @@ -12915,17 +13121,17 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include - static void routine(void* a) {a=0;} - static void* start_routine(void* a) {return a;} + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; } int main () { pthread_t th; pthread_attr_t attr; - pthread_create(&th,0,start_routine,0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0); + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */ ; return 0; } @@ -12958,17 +13164,17 @@ CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 $as_echo_n "checking for joinable pthread attribute... " >&6; } - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { -int attr=$attr; return attr; +int attr = $attr; return attr /* ; */ ; return 0; } @@ -12978,7 +13184,7 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - done + done { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 $as_echo "$attr_name" >&6; } if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then @@ -12992,9 +13198,16 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 $as_echo_n "checking if more special flags are required for pthreads... " >&6; } flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + case ${host_os} in + aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; + osf* | hpux*) flag="-D_REENTRANT";; + solaris*) + if test "$GCC" = "yes"; then + flag="-D_REENTRANT" + else + flag="-mt -D_REENTRANT" + fi + ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 $as_echo "${flag}" >&6; } @@ -13002,11 +13215,46 @@ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 +$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; } +if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +int +main () +{ +int i = PTHREAD_PRIO_INHERIT; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_PTHREAD_PRIO_INHERIT=yes +else + ax_cv_PTHREAD_PRIO_INHERIT=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 +$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } + if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"; then : + +$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h + +fi + LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r - if test x"$GCC" != xyes; then + if test x"$GCC" != xyes; then for ac_prog in xlc_r cc_r do # Extract the first word of "$ac_prog", so it can be a program name with args. @@ -13052,7 +13300,7 @@ else PTHREAD_CC=$CC - fi + fi else PTHREAD_CC="$CC" fi @@ -13168,27 +13416,23 @@ fi -# --enable-udev -# Check whether --enable-udev was given. -if test "${enable_udev+set}" = set; then : - enableval=$enable_udev; udev="${enableval}" -else - udev=no -fi +# class driver is disabled +class=no +NOCLASS="--no-class" - if test "${udev}" != "no"; then - UDEV_TRUE= - UDEV_FALSE='#' -else - UDEV_TRUE='#' - UDEV_FALSE= + +# --enable-embedded +# Check whether --enable-embedded was given. +if test "${enable_embedded+set}" = set; then : + enableval=$enable_embedded; use_embedded="${enableval}" fi -# class driver is disabled -class=no -NOCLASS="--no-class" +if test x$use_embedded = xyes; then +$as_echo "#define NO_LOG 1" >>confdefs.h + +fi # Setup dist stuff @@ -13221,13 +13465,11 @@ NOCLASS: ${NOCLASS} libusb support: ${use_libusb} -use USB interrupt: ${use_usb_interrupt} composite as multislot: ${use_composite_as_multislot} multi threading: ${multithread} bundle directory name: ${bundle} USB drop directory: ${usbdropdir} compiled for pcsc-lite: ${pcsclite} -udev support: ${udev} class driver: ${class} EOF @@ -13330,6 +13572,7 @@ ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' @@ -13372,12 +13615,12 @@ as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${WITHOUT_PCSC_TRUE}" && test -z "${WITHOUT_PCSC_FALSE}"; then - as_fn_error $? "conditional \"WITHOUT_PCSC\" was never defined. +if test -z "${WITH_LIBUSB_TRUE}" && test -z "${WITH_LIBUSB_FALSE}"; then + as_fn_error $? "conditional \"WITH_LIBUSB\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${UDEV_TRUE}" && test -z "${UDEV_FALSE}"; then - as_fn_error $? "conditional \"UDEV\" was never defined. +if test -z "${WITHOUT_PCSC_TRUE}" && test -z "${WITHOUT_PCSC_FALSE}"; then + as_fn_error $? "conditional \"WITHOUT_PCSC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi @@ -13777,7 +14020,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by acsccid $as_me 1.0.8, which was +This file was extended by acsccid $as_me 1.1.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13843,7 +14086,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -acsccid config.status 1.0.8 +acsccid config.status 1.1.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -Nru acsccid-1.0.8/configure.ac acsccid-1.1.0/configure.ac --- acsccid-1.0.8/configure.ac 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/configure.ac 2014-12-10 08:32:26.000000000 +0000 @@ -2,9 +2,9 @@ # You may need to use autoconf 2.56 or newer # Require autoconf 2.61 -AC_PREREQ(2.61) +AC_PREREQ([2.69]) -AC_INIT([acsccid], [1.0.8]) +AC_INIT([acsccid], [1.1.0]) AC_CONFIG_SRCDIR(src/ifdhandler.c) AC_CONFIG_AUX_DIR([config]) AM_INIT_AUTOMAKE(1.8 dist-bzip2 no-dist-gzip foreign subdir-objects) @@ -20,7 +20,7 @@ AC_CANONICAL_HOST # create a config.h file (Automake will add -DHAVE_CONFIG_H) -AM_CONFIG_HEADER(config.h) +AC_CONFIG_HEADERS([config.h]) # Options AM_MAINTAINER_MODE @@ -33,10 +33,11 @@ AC_PROG_MAKE_SET AC_PROG_LN_S AM_PROG_LEX +AM_PROG_AR PKG_PROG_PKG_CONFIG # check pcsc-lite version -PCSC_NEEDED_VERSION="1.3.3" +PCSC_NEEDED_VERSION="1.8.3" PKG_CHECK_EXISTS([libpcsclite], [PKG_CHECK_MODULES(PCSC, libpcsclite >= $PCSC_NEEDED_VERSION, [], [ @@ -66,7 +67,7 @@ # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(errno.h fcntl.h stdlib.h unistd.h termios.h string.h sys/time.h sys/types.h stdarg.h arpa/inet.h,, +AC_CHECK_HEADERS(errno.h fcntl.h stdlib.h unistd.h termios.h string.h sys/time.h sys/types.h stdarg.h arpa/inet.h stdio.h,, [AC_MSG_ERROR([some header files not found])]) # Checks for typedefs, structures, and compiler characteristics. @@ -80,102 +81,60 @@ # Select OS specific versions of source files. AC_SUBST(BUNDLE_HOST) AC_SUBST(DYN_LIB_EXT) -case "$host" in -*-*-darwin*) - BUNDLE_HOST="MacOS" +BUNDLE_HOST=`uname | sed -e s,/,_,` +DYN_LIB_EXT="so" +case "$BUNDLE_HOST" in +Darwin) + BUNDLE_HOST=MacOS DYN_LIB_EXT="dylib" ;; -*-*-freebsd*) - BUNDLE_HOST="FreeBSD" - DYN_LIB_EXT="so" +SunOS) + BUNDLE_HOST=Solaris ;; -*-*-openbsd*) - BUNDLE_HOST="OpenBSD" - DYN_LIB_EXT="so.0.0" - ;; -*-*-solaris*) - BUNDLE_HOST="Solaris" - DYN_LIB_EXT="so" - ;; -*-*-dragonfly*) - BUNDLE_HOST="DragonFly" - DYN_LIB_EXT="so" - ;; -*) - BUNDLE_HOST="Linux" - DYN_LIB_EXT="so" -esac + esac -use_usb_interrupt=no - -PKG_CHECK_EXISTS([libusb], [ -PKG_CHECK_MODULES(LIBUSB, libusb, [], - [ - AC_CHECK_PROG([LIBUSBCONFIG], [libusb-config], [yes]) - - if test "$LIBUSBCONFIG" = "yes" ; then - LIBUSB_CFLAGS="$LIBUSB_CFLAGS `libusb-config --cflags`" - LIBUSB_LIBS="$LIBUSB_LIBS `libusb-config --libs`" - else - AC_MSG_WARN([libusb-config not found.]) - fi +# --disable-libusb +AC_ARG_ENABLE(libusb, + AS_HELP_STRING([--disable-libusb],[do not use libusb]), + [ use_libusb="${enableval}" ], [ use_libusb=yes ] ) + +# check if libusb is used +LIBUSB_NEEDED_VERSION="1.0.8" +if test "x$use_libusb" != xno ; then + PKG_CHECK_EXISTS([libusb-1.0], [ + PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= $LIBUSB_NEEDED_VERSION, [], + [ + AC_MSG_WARN([install libusb $LIBUSB_NEEDED_VERSION or later]) + PKG_CHECK_MODULES(LIBUSB, libusb-1.0) + ]) ]) -]) - -saved_CPPFLAGS="$CPPFLAGS" -saved_LIBS="$LIBS" - -CPPFLAGS="$CPPFLAGS $LIBUSB_CFLAGS" -LIBS="$LDFLAGS $LIBUSB_LIBS" -AC_CHECK_HEADERS(usb.h, [], - [ AC_MSG_ERROR([usb.h not found, install libusb or use ./configure LIBUSB_CFLAGS=...]) ]) + saved_CPPFLAGS="$CPPFLAGS" + saved_LIBS="$LIBS" -AC_MSG_CHECKING([for usb_init]) -AC_TRY_LINK_FUNC(usb_init, [ AC_MSG_RESULT([yes]) ], - [ AC_MSG_ERROR([libusb not found, use ./configure LIBUSB_LIBS=...]) ]) + CPPFLAGS="$CPPFLAGS $LIBUSB_CFLAGS" + LIBS="$LDFLAGS $LIBUSB_LIBS" -AC_MSG_CHECKING([for usb_interrupt_read]) -AC_TRY_LINK_FUNC(usb_interrupt_read, [ AC_MSG_RESULT([yes]) ], - [ AC_MSG_ERROR([your libusb is too old. install version 0.1.12 or above]) ]) + AC_CHECK_HEADERS(libusb.h, [], + [ AC_MSG_ERROR([libusb.h not found, install libusb or use ./configure LIBUSB_CFLAGS=...]) ]) -AC_CHECK_FUNC(usb_detach_kernel_driver_np, - [ AC_DEFINE(HAVE_USB_DETACH_KERNEL_DRIVER_NP, 1, [Define if usb_detach_kernel_driver_np() is available]) ]) + AC_MSG_CHECKING([for libusb_init]) + AC_TRY_LINK_FUNC(libusb_init, [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_ERROR([libusb not found, use ./configure LIBUSB_LIBS=...]) ]) -CPPFLAGS="$saved_CPPFLAGS" -LIBS="$saved_LIBS" - -use_libusb=yes + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" -AC_MSG_CHECKING([if libusb is emulated by libusb-compat]) -a=`$PKG_CONFIG --variable=emulated libusb` -if test "x$a" = "x1"; -then - AC_MSG_RESULT([yes]) - use_usb_interrupt=yes -else - AC_MSG_RESULT([no]) + use_libusb=yes fi - AC_SUBST(LIBUSB_CFLAGS) AC_SUBST(LIBUSB_LIBS) - -# --enable-usb-interrupt -AC_ARG_ENABLE(usb-interrupt, - AC_HELP_STRING([--enable-usb-interrupt], [force the use of USB - interrupt even with an old libusb]), - [ use_usb_interrupt="${enableval}" ] ) - -if test "x$use_usb_interrupt" = xyes; then - AC_DEFINE(USE_USB_INTERRUPT, 1, [use libusb usb_interrupt_read() - instead of polling]) -fi +AM_CONDITIONAL(WITH_LIBUSB, test "${use_libusb}" != "no") # --enable-composite-as-multislot use_composite_as_multislot=no AC_ARG_ENABLE(composite-as-multislot, - AC_HELP_STRING([--enable-composite-as-multislot], - [composite device are seen as multi-slots]), + AS_HELP_STRING([--enable-composite-as-multislot],[composite device are seen as multi-slots]), [ use_composite_as_multislot="${enableval}" ] ) if test "x$use_composite_as_multislot" = xyes; then @@ -195,11 +154,11 @@ # --disable-multi-thread AC_ARG_ENABLE(multi-thread, - AC_HELP_STRING([--disable-multi-thread],[disable multi threading]), + AS_HELP_STRING([--disable-multi-thread],[disable multi threading]), [ multithread="${enableval}" ], [ multithread=yes ] ) if test "${multithread}" != no ; then - ACX_PTHREAD( + AX_PTHREAD( [ AC_DEFINE(HAVE_PTHREAD, 1, [Define if you have POSIX threads libraries and header files.]) ], [ AC_MSG_ERROR([POSIX thread support required]) ]) @@ -213,7 +172,7 @@ # --enable-usbdropdir=DIR AC_ARG_ENABLE(usbdropdir, - AC_HELP_STRING([--enable-usbdropdir=DIR],[directory containing USB + AS_HELP_STRING([--enable-usbdropdir=DIR],[directory containing USB drivers (default to pcscd config or $(prefix)/pcsc/drivers)]), [usbdropdir="${enableval}"], [usbdropdir=false]) if test "${usbdropdir}" = false ; then @@ -226,7 +185,7 @@ # --disable-pcsclite AC_ARG_ENABLE(pcsclite, - AC_HELP_STRING([--disable-pcsclite],[do not use pcsc-lite debug support]), + AS_HELP_STRING([--disable-pcsclite],[do not use pcsc-lite debug support]), [ pcsclite="${enableval}" ], [ pcsclite=yes ] ) if test "${pcsclite}" != no ; then @@ -246,17 +205,20 @@ fi AM_CONDITIONAL(WITHOUT_PCSC, test "${pcsclite}" != "yes") -# --enable-udev -AC_ARG_ENABLE(udev, - AC_HELP_STRING([--enable-udev],[udev support for pcscd hotplug]), - [udev="${enableval}"], [udev=no]) -AM_CONDITIONAL(UDEV, test "${udev}" != "no") - # class driver is disabled class=no NOCLASS="--no-class" AC_SUBST(NOCLASS) +# --enable-embedded +AC_ARG_ENABLE(embedded, + AS_HELP_STRING([--enable-embedded],[limit RAM and CPU ressources by disabling features (log)]), + [ use_embedded="${enableval}" ]) + +if test x$use_embedded = xyes; then + AC_DEFINE(NO_LOG, 1, [Disable logging support]) +fi + # Setup dist stuff AC_SUBST(ac_aux_dir) AC_SUBST(bundle) @@ -288,13 +250,11 @@ NOCLASS: ${NOCLASS} libusb support: ${use_libusb} -use USB interrupt: ${use_usb_interrupt} composite as multislot: ${use_composite_as_multislot} multi threading: ${multithread} bundle directory name: ${bundle} USB drop directory: ${usbdropdir} compiled for pcsc-lite: ${pcsclite} -udev support: ${udev} class driver: ${class} EOF diff -Nru acsccid-1.0.8/debian/changelog acsccid-1.1.0/debian/changelog --- acsccid-1.0.8/debian/changelog 2014-07-03 06:13:07.000000000 +0000 +++ acsccid-1.1.0/debian/changelog 2015-05-19 16:32:32.000000000 +0000 @@ -1,3 +1,20 @@ +acsccid (1.1.0-1~ubuntu15.04.1) vivid-backports; urgency=medium + + * No-change backport to vivid (LP: #1456518) + + -- Felix Geyer Tue, 19 May 2015 18:32:32 +0200 + +acsccid (1.1.0-1) unstable; urgency=low + + * New upstream release. + * Updated libpcsclite-dev to 1.8.3. + * Replaced libusb-dev with libusb-1.0-0-dev (>= 1.0.8~). + * Updated Standards-Version to 3.9.6. + * Removed --enable-composite-as-multislot in debian/rules. + * Updated debian/copyright. + + -- Godfrey Chung Thu, 11 Dec 2014 11:41:37 +0800 + acsccid (1.0.8-1) unstable; urgency=low * New upstream release. diff -Nru acsccid-1.0.8/debian/control acsccid-1.1.0/debian/control --- acsccid-1.0.8/debian/control 2014-04-22 06:21:12.000000000 +0000 +++ acsccid-1.1.0/debian/control 2014-12-10 10:03:58.000000000 +0000 @@ -6,11 +6,11 @@ dh-autoreconf, debhelper (>= 9~), flex, - libpcsclite-dev (>= 1.3.3~), - libusb-dev (>= 0.1.12~), + libpcsclite-dev (>= 1.8.3~), + libusb-1.0-0-dev (>= 1.0.8~), perl, pkg-config -Standards-Version: 3.9.5 +Standards-Version: 3.9.6 Homepage: http://acsccid.sourceforge.net/ Package: libacsccid1 diff -Nru acsccid-1.0.8/debian/copyright acsccid-1.1.0/debian/copyright --- acsccid-1.0.8/debian/copyright 2014-04-22 06:05:58.000000000 +0000 +++ acsccid-1.1.0/debian/copyright 2014-12-11 03:33:41.000000000 +0000 @@ -15,25 +15,59 @@ Files: m4/ax_pthread.m4 Copyright: 2008 Steven G. Johnson + 2011 Daniel Richard G. License: GPL-3 Files: MacOSX/* -Copyright: 1999-2009 Ludovic Rousseau - 1999-2005 David Corcoran - 1999-2004 Damien Sauveron -License: LGPL-2.1+ +Copyright: 1999-2011 Ludovic Rousseau + 1999-2005 David Corcoran + 2003-2004 Damien Sauveron +License: BSD-3-clause + +Files: MacOSX/configure +Copyright: 2007-2009 Ludovic Rousseau +License: LGPL-2+ + +Files: MacOSX/convert_reader_h.pl +Copyright: 2008 Ludovic Rousseau +License: LGPL-2+ Files: src/* Copyright: 2009-2014 Advanced Card Systems Ltd. - 2001-2011 Ludovic Rousseau - 2003 Toni Andjelkovic - 2001-2003 David Corcoran + 2003-2011 Ludovic Rousseau + 2005 Martin Paljak License: LGPL-2.1+ +Files: src/*.pl +Copyright: 2004-2009 Ludovic Rousseau +License: LGPL-2+ + +Files: src/misc.h +Copyright: 2005-2010 Ludovic Rousseau +License: BSD-3-clause + +Files: src/parser.h +Copyright: 2003 Toni Andjelkovic + 2005-2009 Ludovic Rousseau +License: BSD-3-clause + +Files: src/simclist.* +Copyright: 2007-2011 Mij +License: ISC + Files: src/strlcpy.c Copyright: 1998 Todd C. Miller License: ISC +Files: src/strlcpycat.h +Copyright: 2004-2010 Ludovic Rousseau +License: BSD-3-clause + +Files: src/tokenparser.* +Copyright: 2001-2003 David Corcoran + 2003-2010 Ludovic Rousseau +License: BSD-3-clause + Files: src/openct/* Copyright: 2011 Advanced Card Systems Ltd. 2004 Ludovic Rousseau @@ -112,3 +146,30 @@ . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". + +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + . + Changes to this license can be made only by the copyright author with + explicit written consent. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru acsccid-1.0.8/debian/rules acsccid-1.1.0/debian/rules --- acsccid-1.0.8/debian/rules 2014-04-22 06:21:58.000000000 +0000 +++ acsccid-1.1.0/debian/rules 2014-12-10 10:19:46.000000000 +0000 @@ -6,10 +6,6 @@ %: dh $@ --with autoreconf --parallel -override_dh_auto_configure: - # Enable composite device as multi-slot reader. - dh_auto_configure -- --enable-composite-as-multislot - override_dh_installudev: dh_installudev --priority=92 diff -Nru acsccid-1.0.8/INSTALL acsccid-1.1.0/INSTALL --- acsccid-1.0.8/INSTALL 2012-05-22 08:36:41.000000000 +0000 +++ acsccid-1.1.0/INSTALL 2014-12-10 08:32:26.000000000 +0000 @@ -15,7 +15,7 @@ # make install 4. To build the driver in Mac OS X, please install development tools from - Apple and install libusb-0.1. Enter the following commands to install the + Apple and install libusb. Enter the following commands to install the driver. # ./MacOSX/configure diff -Nru acsccid-1.0.8/m4/ax_pthread.m4 acsccid-1.1.0/m4/ax_pthread.m4 --- acsccid-1.0.8/m4/ax_pthread.m4 2010-08-18 22:00:00.000000000 +0000 +++ acsccid-1.1.0/m4/ax_pthread.m4 2014-12-10 08:32:26.000000000 +0000 @@ -33,6 +33,10 @@ # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action @@ -45,9 +49,12 @@ # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # +# Updated for Autoconf 2.68 by Daniel Richard G. +# # LICENSE # # Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2011 Daniel Richard G. # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the @@ -75,13 +82,12 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 9 +#serial 18 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) -AC_LANG_SAVE -AC_LANG_C +AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h @@ -139,8 +145,8 @@ # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case "${host_cpu}-${host_os}" in - *solaris*) +case ${host_os} in + solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based @@ -153,9 +159,9 @@ ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; - *-darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" - ;; + darwin*) + ax_pthread_flags="-pthread $ax_pthread_flags" + ;; esac if test x"$ax_pthread_ok" = xno; then @@ -171,12 +177,12 @@ PTHREAD_CFLAGS="$flag" ;; - pthread-config) - AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) - if test x"$ax_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; + pthread-config) + AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) + if test x"$ax_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) @@ -198,16 +204,17 @@ # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. - AC_TRY_LINK([#include - static void routine(void* a) {a=0;} - static void* start_routine(void* a) {return a;}], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th,0,start_routine,0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0); ], - [ax_pthread_ok=yes]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" @@ -230,12 +237,14 @@ CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_TRY_LINK([#include ], [int attr=$attr; return attr;], - [attr_name=$attr; break]) - done + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $attr; return attr /* ; */])], + [attr_name=$attr; break], + []) + done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, @@ -245,24 +254,41 @@ AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + case ${host_os} in + aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; + osf* | hpux*) flag="-D_REENTRANT";; + solaris*) + if test "$GCC" = "yes"; then + flag="-D_REENTRANT" + else + flag="-mt -D_REENTRANT" + fi + ;; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + ax_cv_PTHREAD_PRIO_INHERIT, [ + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], + AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) + LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r - if test x"$GCC" != xyes; then + if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC - fi + fi else PTHREAD_CC="$CC" fi @@ -279,5 +305,5 @@ ax_pthread_ok=no $2 fi -AC_LANG_RESTORE +AC_LANG_POP ])dnl AX_PTHREAD diff -Nru acsccid-1.0.8/MacOSX/configure acsccid-1.1.0/MacOSX/configure --- acsccid-1.0.8/MacOSX/configure 2014-04-01 15:41:01.000000000 +0000 +++ acsccid-1.1.0/MacOSX/configure 2014-12-10 08:32:26.000000000 +0000 @@ -17,6 +17,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA. +# $Id: configure 6792 2013-11-25 13:03:21Z rousseau $ + # to use # ./MacOSX/configure # make @@ -37,16 +39,15 @@ exit; fi -./MacOSX/convert_reader_h.pl MacOSX/reader.h.in > MacOSX/reader.h - # find pcsc-lite header files in MacOSX/ # use ${varname:-word} to return word only if varname is not already defined PCSC_CFLAGS=${PCSC_CFLAGS:--I$(pwd)/MacOSX} PCSC_LIBS=${PCSC_LIBS:--framework PCSC} -# use libusb-0.1 -LIBUSB_CFLAGS=-I/usr/local/include -LIBUSB_LIBS="/usr/local/lib/libusb.a -Wl,-framework -Wl,IOKit -Wl,-framework -Wl,CoreFoundation" +# use libusb-1.0 (or libusbx-1.0) +LIBUSB_ARCHIVE=$(pkg-config --variable=libdir libusb-1.0)/libusb-1.0.a +LIBUSB_CFLAGS=$(pkg-config --cflags --static libusb-1.0) +LIBUSB_LIBS=$(pkg-config --libs --static libusb-1.0) # RESPONSECODE is already defined by PCSC/wintypes.h # define needed here to compile examples/scardcontrol.c since config.h is @@ -54,8 +55,25 @@ CFLAGS="$CFLAGS -DRESPONSECODE_DEFINED_IN_WINTYPES_H" # Build a Universal Binary -CFLAGS="$CFLAGS -isysroot /Developer/SDKs/MacOSX10.6.sdk -arch ppc -arch i386 -arch x86_64" -LDFLAGS="-arch ppc -arch i386 -arch x86_64" +UB=$(file $LIBUSB_ARCHIVE | grep "Mach-O universal binary") +echo $UB +if [ -z "$UB" ] +then + echo -en $RED + echo "*************************" + echo "No Universal Binary build" + echo "*************************" + echo -en $NORMAL +else + echo "Universal Binary build" + CFLAGS="$CFLAGS -arch i386 -arch x86_64" + if [ -d /Developer/SDKs/MacOSX10.6.sdk ] + then + CFLAGS="$CFLAGS -arch ppc" + fi +fi +echo + CONFIGURE_ARGS="--disable-dependency-tracking" # do not build a static driver @@ -68,8 +86,19 @@ # simulate a composite device as multi slots CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-composite-as-multislot" -# use a specific bundle name to NOT overwrite the official CCID driver -#CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-bundle=ifd-ccid-foobar.bundle" +# set BUNDLE_ID to a specific value for a specific driver +#BUNDLE_ID="vendor-reader" +if [ ! -z "$BUNDLE_ID" ] +then + # do not build a class driver (not yet used by pcsc-lite on Mac OS X) + CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-class" + + # use a specific bundle name to NOT overwrite the official CCID driver + CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-bundle=ifd-ccid-$BUNDLE_ID.bundle" + + # differentiate each libccid library by the dynamic linker + CONFIGURE_ARGS="$CONFIGURE_ARGS --prefix=/fake/$BUNDLE_ID" +fi set -x ./configure \ diff -Nru acsccid-1.0.8/MacOSX/debuglog.h acsccid-1.1.0/MacOSX/debuglog.h --- acsccid-1.0.8/MacOSX/debuglog.h 2009-01-28 13:27:32.000000000 +0000 +++ acsccid-1.1.0/MacOSX/debuglog.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,12 +1,38 @@ /* - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) + * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) * * Copyright (C) 1999-2004 - * David Corcoran - * Copyright (C) 1999-2005 + * David Corcoran + * Copyright (C) 1999-2011 * Ludovic Rousseau * - * $Id: debuglog.h 3075 2008-07-30 14:25:27Z rousseau $ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +Changes to this license can be made only by the copyright author with +explicit written consent. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: debuglog.h 6851 2014-02-14 15:43:32Z rousseau $ */ /** @@ -33,22 +59,15 @@ #ifndef __debuglog_h__ #define __debuglog_h__ -#ifdef __cplusplus -extern "C" -{ -#endif - #ifndef PCSC_API #define PCSC_API #endif -#define DEBUGLOG_LOG_ENTRIES 1 -#define DEBUGLOG_IGNORE_ENTRIES 2 - enum { DEBUGLOG_NO_DEBUG = 0, DEBUGLOG_SYSLOG_DEBUG, - DEBUGLOG_STDERR_DEBUG + DEBUGLOG_STDOUT_DEBUG, + DEBUGLOG_STDOUT_COLOR_DEBUG }; #define DEBUG_CATEGORY_NOTHING 0 @@ -67,11 +86,33 @@ #define __FUNCTION__ "" #endif +#ifndef __GNUC__ +#define __attribute__(x) /*nothing*/ +#endif + +#ifdef NO_LOG + +#define Log0(priority) do { } while(0) +#define Log1(priority, fmt) do { } while(0) +#define Log2(priority, fmt, data) do { } while(0) +#define Log3(priority, fmt, data1, data2) do { } while(0) +#define Log4(priority, fmt, data1, data2, data3) do { } while(0) +#define Log5(priority, fmt, data1, data2, data3, data4) do { } while(0) +#define Log9(priority, fmt, data1, data2, data3, data4, data5, data6, data7, data8) do { } while(0) +#define LogXxd(priority, msg, buffer, size) do { } while(0) + +#define DebugLogA(a) +#define DebugLogB(a, b) +#define DebugLogC(a, b,c) + +#else + #define Log0(priority) log_msg(priority, "%s:%d:%s()", __FILE__, __LINE__, __FUNCTION__) #define Log1(priority, fmt) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__) #define Log2(priority, fmt, data) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data) #define Log3(priority, fmt, data1, data2) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data1, data2) #define Log4(priority, fmt, data1, data2, data3) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data1, data2, data3) +#define Log5(priority, fmt, data1, data2, data3, data4) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data1, data2, data3, data4) #define Log9(priority, fmt, data1, data2, data3, data4, data5, data6, data7, data8) log_msg(priority, "%s:%d:%s() " fmt, __FILE__, __LINE__, __FUNCTION__, data1, data2, data3, data4, data5, data6, data7, data8) #define LogXxd(priority, msg, buffer, size) log_xxd(priority, msg, buffer, size) @@ -79,7 +120,11 @@ #define DebugLogB(a, b) Log2(PCSC_LOG_INFO, a, b) #define DebugLogC(a, b,c) Log3(PCSC_LOG_INFO, a, b, c) -PCSC_API void log_msg(const int priority, const char *fmt, ...); +#endif /* NO_LOG */ + +PCSC_API void log_msg(const int priority, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); + PCSC_API void log_xxd(const int priority, const char *msg, const unsigned char *buffer, const int size); @@ -89,9 +134,5 @@ void DebugLogCategory(const int, const unsigned char *, const int); PCSC_API void DebugLogSetLevel(const int level); -#ifdef __cplusplus -} -#endif - #endif /* __debuglog_h__ */ diff -Nru acsccid-1.0.8/MacOSX/ifdhandler.h acsccid-1.1.0/MacOSX/ifdhandler.h --- acsccid-1.0.8/MacOSX/ifdhandler.h 2008-06-27 03:07:05.000000000 +0000 +++ acsccid-1.1.0/MacOSX/ifdhandler.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,16 +1,255 @@ /* - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) + * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) * * Copyright (C) 1999-2004 - * David Corcoran + * David Corcoran + * Copyright (C) 2003-2004 * Damien Sauveron + * Copyright (C) 2002-2011 + * Ludovic Rousseau * - * $Id: ifdhandler.h 3029 2008-06-26 13:58:52Z rousseau $ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +Changes to this license can be made only by the copyright author with +explicit written consent. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: ifdhandler.h 6851 2014-02-14 15:43:32Z rousseau $ */ /** * @file + * @defgroup IFDHandler IFDHandler * @brief This provides reader specific low-level calls. + +The routines specified hereafter will allow you to write an IFD handler +for the PC/SC Lite resource manager. Please use the complement +developer's kit complete with headers and Makefile at: +http://www.musclecard.com/drivers.html + +This gives a common API for communication to most readers in a +homogeneous fashion. This document assumes that the driver developer is +experienced with standards such as ISO-7816-(1, 2, 3, 4), EMV and MCT +specifications. For listings of these specifications please access the +above web site. + +@section UsbReaders USB readers + +USB readers use the bundle approach so that the reader can be loaded +and unloaded upon automatic detection of the device. The bundle +approach is simple: the actual library is just embedded in a +directory so additional information can be gathered about the device. + +A bundle looks like the following: + +@verbatim +GenericReader.bundle/ + Contents/ + Info.plist - XML file describing the reader + MacOS/ - Driver directory for OS X + Solaris/ - Driver directory for Solaris + Linux/ - Driver directory for Linux + HPUX/ - Driver directory for HPUX +@endverbatim + +The @c Info.plist file describes the driver and gives the loader +all the necessary information. The following must be contained in the +@c Info.plist file: + +@subsection ifdVendorID + +The vendor ID of the USB device. + +Example: + +@verbatim + ifdVendorID + 0x04E6 +@endverbatim + +You may have an OEM of this reader in which an additional @c +can be used like in the below example: + +@verbatim + ifdVendorID + + 0x04E6 + 0x0973 + +@endverbatim + +If multiples exist all the other parameters must have a second value +also. You may chose not to support this feature but it is useful when +reader vendors OEM products so you only distribute one driver. + + +The CCID driver from Ludovic Rousseau +http://pcsclite.alioth.debian.org/ccid.html uses this feature since the +same driver supports many different readers. + +@subsection ifdProductID + + The product id of the USB device. + +@verbatim + ifdProductID + 0x3437 +@endverbatim + +@subsection ifdFriendlyName + + Example: + +@verbatim + ifdFriendlyName + SCM Microsystems USB Reader +@endverbatim + +@subsection CFBundleExecutable + + The executable name which exists in the particular platform's directory. + + Example: + +@verbatim + CFBundleExecutable + libccid.so.0.4.2 +@endverbatim + +@subsection ifdCapabilities + + List of capabilities supported by the driver. This is a bit field. Possible values are: + +- 0 + No special capabilities +- 1 IFD_GENERATE_HOTPLUG + The driver supports the hot plug feature. + +Complete sample file: + +@verbatim + + + + + CFBundleDevelopmentRegion + English + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 0.0.1d1 + ifdCapabilities + 0x00000000 + ifdProtocolSupport + 0x00000001 + ifdVersionNumber + 0x00000001 + + CFBundleExecutable + libfoobar.so.x.y + + ifdManufacturerString + Foo bar inc. + + ifdProductString + Driver for Foobar reader, version x.y + + ifdVendorID + 0x1234 + + ifdProductID + 0x5678 + + ifdFriendlyName + Foobar USB reader + + +@endverbatim + +As indicated in the XML file the DTD is available at +http://www.apple.com/DTDs/PropertyList-1.0.dtd. + +@section SerialReaders Serial readers + +Serial drivers must be configured to operate on a particular port and +respond to a particular name. The @c reader.conf file is used for this +purpose. + +It has the following syntax: + +@verbatim +# Configuration file for pcsc-lite +# David Corcoran + +FRIENDLYNAME Generic Reader +DEVICENAME /dev/ttyS0 +LIBPATH /usr/lib/pcsc/drivers/libgen_ifd.so +CHANNELID 1 +@endverbatim + +The pound sign # denotes a comment. + +@subsection FRIENDLYNAME +The FRIENDLYNAME field is an arbitrary text used to identify the reader. +This text is displayed by commands like @c pcsc_scan +http://ludovic.rousseau.free.fr/softwares/pcsc-tools/ that prints the +names of all the connected and detected readers. + +@subsection DEVICENAME +The DEVICENAME field was not used for old drivers (using the IFD handler +version 2.0 or previous). It is now (IFD handler version 3.0) used to +identify the physical port on which the reader is connected. This is +the device name of this port. It is dependent of the OS kernel. For +example the first serial port device is called @c /dev/ttyS0 under Linux +and @c /dev/cuaa0 under FreeBSD. + +If you want to use IFDHCreateChannel() instead of +IFDHCreateChannelByName() then do not use any DEVICENAME line in the +configuration file. IFDHCreateChannel() will then be called with the +CHANNELID parameter. + +@subsection LIBPATH +The LIBPATH field is the filename of the driver code. The driver is a +dynamically loaded piece of code (generally a @c drivername.so* file). + +@subsection CHANNELID +The CHANNELID is no more used for recent drivers (IFD handler 3.0) and +has been superseded by DEVICENAME. + +If you have an old driver this field is used to indicate the port to +use. You should read your driver documentation to know what information +is needed here. It should be the serial port number for a serial reader. + +CHANNELID was the numeric version of the port in which the reader will +be located. This may be done by a symbolic link where @c /dev/pcsc/1 is +the first device which may be a symbolic link to @c /dev/ttyS0 or +whichever location your reader resides. + */ #ifndef _ifd_handler_h_ @@ -18,15 +257,9 @@ #include -#ifdef __cplusplus -extern "C" -{ -#endif - /* * List of data structures available to ifdhandler */ - typedef struct _DEVICE_CAPABILITIES { LPSTR Vendor_Name; /**< Tag 0x0100 */ @@ -75,6 +308,9 @@ } PROTOCOL_OPTIONS, *PPROTOCOL_OPTIONS; + /** + * Use by SCardTransmit() + */ typedef struct _SCARD_IO_HEADER { DWORD Protocol; @@ -83,26 +319,19 @@ SCARD_IO_HEADER, *PSCARD_IO_HEADER; /* - * End of structure list - */ - - /* * The list of tags should be alot more but this is all I use in the * meantime */ - -#define TAG_IFD_ATR 0x0303 -#define TAG_IFD_SLOTNUM 0x0180 -#define TAG_IFD_SLOT_THREAD_SAFE 0x0FAC -#define TAG_IFD_THREAD_SAFE 0x0FAD -#define TAG_IFD_SLOTS_NUMBER 0x0FAE -#define TAG_IFD_SIMULTANEOUS_ACCESS 0x0FAF -#define TAG_IFD_POLLING_THREAD 0x0FB0 -#define TAG_IFD_POLLING_THREAD_KILLABLE 0x0FB1 - - /* - * End of tag list - */ +#define TAG_IFD_ATR 0x0303 /**< ATR */ +#define TAG_IFD_SLOTNUM 0x0180 /**< select a slot */ +#define TAG_IFD_SLOT_THREAD_SAFE 0x0FAC /**< support access to different slots of the reader */ +#define TAG_IFD_THREAD_SAFE 0x0FAD /**< driver is thread safe */ +#define TAG_IFD_SLOTS_NUMBER 0x0FAE /**< number of slots of the reader */ +#define TAG_IFD_SIMULTANEOUS_ACCESS 0x0FAF /**< number of reader the driver can manage */ +#define TAG_IFD_POLLING_THREAD 0x0FB0 /**< not used. See TAG_IFD_POLLING_THREAD_WITH_TIMEOUT */ +#define TAG_IFD_POLLING_THREAD_KILLABLE 0x0FB1 /**< the polling thread can be killed */ +#define TAG_IFD_STOP_POLLING_THREAD 0x0FB2 /**< method used to stop the polling thread (instead of just pthread_kill()) */ +#define TAG_IFD_POLLING_THREAD_WITH_TIMEOUT 0x0FB3 /**< driver uses a polling thread with a timeout parameter */ /* * IFD Handler version number enummerations @@ -110,47 +339,49 @@ #define IFD_HVERSION_1_0 0x00010000 #define IFD_HVERSION_2_0 0x00020000 #define IFD_HVERSION_3_0 0x00030000 - /* - * End of version number enummerations - */ /* * List of defines available to ifdhandler */ - -#define IFD_POWER_UP 500 -#define IFD_POWER_DOWN 501 -#define IFD_RESET 502 - -#define IFD_NEGOTIATE_PTS1 1 -#define IFD_NEGOTIATE_PTS2 2 -#define IFD_NEGOTIATE_PTS3 4 - -#define IFD_SUCCESS 0 -#define IFD_ERROR_TAG 600 -#define IFD_ERROR_SET_FAILURE 601 -#define IFD_ERROR_VALUE_READ_ONLY 602 -#define IFD_ERROR_PTS_FAILURE 605 +#define IFD_POWER_UP 500 /**< power up the card */ +#define IFD_POWER_DOWN 501 /**< power down the card */ +#define IFD_RESET 502 /**< warm reset */ + +#define IFD_NEGOTIATE_PTS1 1 /**< negotiate PTS1 */ +#define IFD_NEGOTIATE_PTS2 2 /**< negotiate PTS2 */ +#define IFD_NEGOTIATE_PTS3 4 /**< negotiate PTS3 */ + +#define IFD_SUCCESS 0 /**< no error */ +#define IFD_ERROR_TAG 600 /**< tag unknown */ +#define IFD_ERROR_SET_FAILURE 601 /**< set failed */ +#define IFD_ERROR_VALUE_READ_ONLY 602 /**< value is read only */ +#define IFD_ERROR_PTS_FAILURE 605 /**< failed to negotiate PTS */ #define IFD_ERROR_NOT_SUPPORTED 606 -#define IFD_PROTOCOL_NOT_SUPPORTED 607 -#define IFD_ERROR_POWER_ACTION 608 +#define IFD_PROTOCOL_NOT_SUPPORTED 607 /**< requested protocol not supported */ +#define IFD_ERROR_POWER_ACTION 608 /**< power up failed */ #define IFD_ERROR_SWALLOW 609 #define IFD_ERROR_EJECT 610 #define IFD_ERROR_CONFISCATE 611 -#define IFD_COMMUNICATION_ERROR 612 -#define IFD_RESPONSE_TIMEOUT 613 -#define IFD_NOT_SUPPORTED 614 -#define IFD_ICC_PRESENT 615 -#define IFD_ICC_NOT_PRESENT 616 +#define IFD_COMMUNICATION_ERROR 612 /**< generic error */ +#define IFD_RESPONSE_TIMEOUT 613 /**< timeout */ +#define IFD_NOT_SUPPORTED 614 /**< request is not supported */ +#define IFD_ICC_PRESENT 615 /**< card is present */ +#define IFD_ICC_NOT_PRESENT 616 /**< card is absent */ +/** + * The \ref IFD_NO_SUCH_DEVICE error must be returned by the driver when + * it detects the reader is no more present. This will tell pcscd to + * remove the reader from the list of available readers. + */ #define IFD_NO_SUCH_DEVICE 617 +#define IFD_ERROR_INSUFFICIENT_BUFFER 618 /**< buffer is too small */ #ifndef RESPONSECODE_DEFINED_IN_WINTYPES_H typedef long RESPONSECODE; #endif /* - * If you want to compile a V2.0 IFDHandler, define IFDHANDLERv2 before you - * include this file. + * If you want to compile a V2.0 IFDHandler, define IFDHANDLERv2 + * before you include this file. * * By default it is setup for for most recent version of the API (V3.0) */ @@ -165,54 +396,428 @@ * IFDHControl() API changed */ - RESPONSECODE IFDHCreateChannelByName(DWORD, LPSTR); - RESPONSECODE IFDHControl(DWORD, DWORD, PUCHAR, DWORD, PUCHAR, - DWORD, LPDWORD); -#else +/** +This function is required to open a communications channel to the port +listed by @p DeviceName. - /* - * List of Defined Functions Available to IFD_Handler 2.0 - */ +Once the channel is opened the reader must be in a state in which it is +possible to query IFDHICCPresence() for card status. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number\n + Use this for multiple card slots or multiple readers. 0xXXXXYYYY - + XXXX multiple readers, YYYY multiple slots. The resource manager will + set these automatically. By default the resource manager loads a new + instance of the driver so if your reader does not have more than one + smart card slot then ignore the Lun in all the functions.\n + \n + PC/SC supports the loading of multiple readers through one instance of + the driver in which XXXX is important. XXXX identifies the unique + reader in which the driver communicates to. The driver should set up + an array of structures that asociate this XXXX with the underlying + details of the particular reader. + +@param[in] DeviceName Filename to use by the driver.\n + For drivers configured by @p /etc/reader.conf this is the value of the + field \ref DEVICENAME. + \n + For USB drivers the @p DeviceName must start with @p usb:VID/PID. VID + is the Vendor ID and PID is the Product ID. Both are a 4-digits hex + number. + +Typically the string is generated by: + +@code +printf("usb:%04x/%04x", idVendor, idProduct); +@endcode + +The @p DeviceName string may also contain a more specialised +identification string. This additional information is used to +differentiate between two identical readers connected at the same time. +In this case the driver can't differentiate the two readers using VID +and PID and must use some additional information identifying the USB +port used by each reader. + +- libusb + + For USB drivers using libusb-1.0 http://libusb.sourceforge.net/ for USB + abstraction the @p DeviceName the string may be generated by: + + @code + printf("usb:%04x/%04x:libusb-1.0:%d:%d:%d", + idVendor, idProduct, bus_number, device_address, interface) + @endcode + + So it is something like: usb:08e6/3437:libusb-1.0:7:99:0 under + GNU/Linux. + +- libudev + + If pcscd is compiled with libudev support instead of libusb (default + since pcsc-lite 1.6.8) the string will look like: + + @code + printf("usb:%04x/%04x:libudev:%d:%s", idVendor, idProduct, + bInterfaceNumber, devpath); + @endcode + + bInterfaceNumber is the number of the interface on the device. It is + only usefull for devices with more than one CCID interface. + + devpath is the filename of the device on the file system. + + So it is something like: + usb:08e6/3437:libudev:0:/dev/bus/usb/008/047 + under GNU/Linux. + +- other + + If the driver does not understand the :libusb: or + :libudev: scheme or if a new scheme is used, the driver should + ignore the part it does not understand instead of failing. + + The driver shall recognize the usb:VID/PID part and, only if + possible, the remaining of the DeviceName field. + + It is the responsibility of the driver to correctly identify the reader. + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName); + +/** +This function performs a data exchange with the reader (not the card) +specified by Lun. It is responsible for abstracting functionality such +as PIN pads, biometrics, LCD panels, etc. You should follow the MCT and +CTBCS specifications for a list of accepted commands to implement. This +function is fully voluntary and does not have to be implemented unless +you want extended functionality. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number +@param[in] dwControlCode Control code for the operation\n + This value identifies the specific operation to be performed. This + value is driver specific. +@param[in] TxBuffer Transmit data +@param[in] TxLength Length of this buffer +@param[out] RxBuffer Receive data +@param[in] RxLength Length of the response buffer +@param[out] pdwBytesReturned Length of response\n + This function will be passed the length of the buffer RxBuffer in + RxLength and it must set the length of the received data in + pdwBytesReturned. + +@note + @p *pdwBytesReturned should be set to zero on error. + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR) +@retval IFD_RESPONSE_TIMEOUT The response timed out (\ref IFD_RESPONSE_TIMEOUT) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR + TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength, + LPDWORD pdwBytesReturned); + +#else - RESPONSECODE IFDHControl(DWORD, PUCHAR, DWORD, PUCHAR, PDWORD); +/** + * Available in IFD_Handler 2.0 + * + * @deprecated + * You should use the new form of IFDHControl() + */ +RESPONSECODE IFDHControl(DWORD Lun, PUCHAR TxBuffer, DWORD TxLength, + PUCHAR RxBuffer, PDWORD RxLength); #endif /* * common functions in IFD_Handler 2.0 and 3.0 */ - RESPONSECODE IFDHCreateChannel(DWORD, DWORD); - RESPONSECODE IFDHCloseChannel(DWORD); - RESPONSECODE IFDHGetCapabilities(DWORD, DWORD, PDWORD, PUCHAR); - RESPONSECODE IFDHSetCapabilities(DWORD, DWORD, DWORD, PUCHAR); - RESPONSECODE IFDHSetProtocolParameters(DWORD, DWORD, UCHAR, - UCHAR, UCHAR, UCHAR); - RESPONSECODE IFDHPowerICC(DWORD, DWORD, PUCHAR, PDWORD); - RESPONSECODE IFDHTransmitToICC(DWORD, SCARD_IO_HEADER, PUCHAR, - DWORD, PUCHAR, PDWORD, PSCARD_IO_HEADER); - RESPONSECODE IFDHICCPresence(DWORD); - - /* - * List of Defined Functions Available to IFD_Handler 1.0 - */ - - RESPONSECODE IO_Create_Channel(DWORD); - RESPONSECODE IO_Close_Channel(void); - RESPONSECODE IFD_Get_Capabilities(DWORD, PUCHAR); - RESPONSECODE IFD_Set_Capabilities(DWORD, PUCHAR); - RESPONSECODE IFD_Set_Protocol_Parameters(DWORD, UCHAR, UCHAR, - UCHAR, UCHAR); - RESPONSECODE IFD_Power_ICC(DWORD); - RESPONSECODE IFD_Swallow_ICC(void); - RESPONSECODE IFD_Eject_ICC(void); - RESPONSECODE IFD_Confiscate_ICC(void); - RESPONSECODE IFD_Transmit_to_ICC(SCARD_IO_HEADER, PUCHAR, DWORD, - PUCHAR, PDWORD, PSCARD_IO_HEADER); - RESPONSECODE IFD_Is_ICC_Present(void); - RESPONSECODE IFD_Is_ICC_Absent(void); +/** +This function is required to open a communications channel to the port +listed by Channel. For example, the first serial reader on COM1 would +link to @p /dev/pcsc/1 which would be a symbolic link to @p /dev/ttyS0 +on some machines This is used to help with inter-machine independence. + +On machines with no /dev directory the driver writer may choose to map +their Channel to whatever they feel is appropriate. + +Once the channel is opened the reader must be in a state in which it is +possible to query IFDHICCPresence() for card status. + +USB readers can ignore the @p Channel parameter and query the USB bus +for the particular reader by manufacturer and product id. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number\n + Use this for multiple card slots or multiple readers. 0xXXXXYYYY - + XXXX multiple readers, YYYY multiple slots. The resource manager will + set these automatically. By default the resource manager loads a new + instance of the driver so if your reader does not have more than one + smart card slot then ignore the Lun in all the functions.\n + \n + PC/SC supports the loading of multiple readers through one instance of + the driver in which XXXX is important. XXXX identifies the unique + reader in which the driver communicates to. The driver should set up + an array of structures that associate this XXXX with the underlying + details of the particular reader. +@param[in] Channel Channel ID + This is denoted by the following: + - 0x000001 @p /dev/pcsc/1 + - 0x000002 @p /dev/pcsc/2 + - 0x000003 @p /dev/pcsc/3 + - 0x000004 @p /dev/pcsc/4 + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) -#ifdef __cplusplus -} -#endif + */ +RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel); + +/** +This function should close the reader communication channel for the +particular reader. Prior to closing the communication channel the reader +should make sure the card is powered down and the terminal is also +powered down. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHCloseChannel(DWORD Lun); + +/** +This function should get the slot/card capabilities for a particular +slot/card specified by Lun. Again, if you have only 1 card slot and +don't mind loading a new driver for each reader then ignore Lun. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number +@param[in] Tag Tag of the desired data value +- \ref TAG_IFD_ATR + Return the ATR and its size (implementation is mandatory). +- \ref TAG_IFD_SLOTNUM + Unused/deprecated +- \ref SCARD_ATTR_ATR_STRING + Same as \ref TAG_IFD_ATR but this one is not mandatory. It is defined + in Microsoft PC/SC SCardGetAttrib(). +- \ref TAG_IFD_SIMULTANEOUS_ACCESS + Return the number of sessions (readers) the driver can handle in + Value[0]. + This is used for multiple readers sharing the same driver. +- \ref TAG_IFD_THREAD_SAFE + If the driver supports more than one reader (see + \ref TAG_IFD_SIMULTANEOUS_ACCESS above) this tag indicates if the + driver supports access to multiple readers at the same time.\n + Value[0] = 1 indicates the driver supports simultaneous accesses. +- \ref TAG_IFD_SLOTS_NUMBER + Return the number of slots in this reader in Value[0]. +- \ref TAG_IFD_SLOT_THREAD_SAFE + If the reader has more than one slot (see \ref TAG_IFD_SLOTS_NUMBER + above) this tag indicates if the driver supports access to multiple + slots of the same reader at the same time.\n + Value[0] = 1 indicates the driver supports simultaneous slot + accesses. +- \ref TAG_IFD_POLLING_THREAD + Unused/deprecated +- \ref TAG_IFD_POLLING_THREAD_WITH_TIMEOUT + If the driver provides a polling thread then @p Value is a pointer to + this function. The function prototype is: +@verbatim + RESPONSECODE foo(DWORD Lun, int timeout); +@endverbatim +- \ref TAG_IFD_POLLING_THREAD_KILLABLE + Tell if the polling thread can be killed (pthread_kill()) by pcscd +- \ref TAG_IFD_STOP_POLLING_THREAD + Returns a pointer in @p Value to the function used to stop the polling + thread returned by \ref TAG_IFD_POLLING_THREAD_WITH_TIMEOUT. The + function prototype is: +@verbatim + RESPONSECODE foo(DWORD Lun); +@endverbatim +@param[in,out] Length Length of the desired data value +@param[out] Value Value of the desired data + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_ERROR_TAG Invalid tag given (\ref IFD_ERROR_TAG) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag, PDWORD Length, + PUCHAR Value); + +/** +This function should set the slot/card capabilities for a particular +slot/card specified by @p Lun. Again, if you have only 1 card slot and +don't mind loading a new driver for each reader then ignore @p Lun. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number +@param[in] Tag Tag of the desired data value +@param[in,out] Length Length of the desired data value +@param[out] Value Value of the desired data + +This function is also called when the application uses the PC/SC +SCardGetAttrib() function. The list of supported tags is not limited. + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_ERROR_TAG Invalid tag given (\ref IFD_ERROR_TAG) +@retval IFD_ERROR_SET_FAILURE Could not set value (\ref IFD_ERROR_SET_FAILURE) +@retval IFD_ERROR_VALUE_READ_ONLY Trying to set read only value (\ref IFD_ERROR_VALUE_READ_ONLY) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag, DWORD Length, PUCHAR Value); + +/** +This function should set the Protocol Type Selection (PTS) of a +particular card/slot using the three PTS parameters sent + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number +@param[in] Protocol Desired protocol +- \ref SCARD_PROTOCOL_T0 + T=0 protocol +- \ref SCARD_PROTOCOL_T1 + T=1 protocol +@param[in] Flags Logical OR of possible values to determine which PTS values +to negotiate +- \ref IFD_NEGOTIATE_PTS1 +- \ref IFD_NEGOTIATE_PTS2 +- \ref IFD_NEGOTIATE_PTS3 +@param[in] PTS1 1st PTS Value +@param[in] PTS2 2nd PTS Value +@param[in] PTS3 3rd PTS Value\n + See ISO 7816/EMV documentation. + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_ERROR_PTS_FAILURE Could not set PTS value (\ref IFD_ERROR_PTS_FAILURE) +@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR) +@retval IFD_PROTOCOL_NOT_SUPPORTED Protocol is not supported (\ref IFD_PROTOCOL_NOT_SUPPORTED) +@retval IFD_NOT_SUPPORTED Action not supported (\ref IFD_NOT_SUPPORTED) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol, UCHAR Flags, + UCHAR PTS1, UCHAR PTS2, UCHAR PTS3); +/** +This function controls the power and reset signals of the smart card +reader at the particular reader/slot specified by @p Lun. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number +@param[in] Action Action to be taken on the card +- \ref IFD_POWER_UP + Power up the card (store and return Atr and AtrLength) +- \ref IFD_POWER_DOWN + Power down the card (Atr and AtrLength should be zeroed) +- \ref IFD_RESET + Perform a warm reset of the card (no power down). If the card is not powered then power up the card (store and return Atr and AtrLength) +@param[out] Atr Answer to Reset (ATR) of the card\n + The driver is responsible for caching this value in case + IFDHGetCapabilities() is called requesting the ATR and its length. The + ATR length should not exceed \ref MAX_ATR_SIZE. +@param[in,out] AtrLength Length of the ATR\n + This should not exceed \ref MAX_ATR_SIZE. + +@note +Memory cards without an ATR should return \ref IFD_SUCCESS on reset but the +Atr should be zeroed and the length should be zero Reset errors should +return zero for the AtrLength and return \ref IFD_ERROR_POWER_ACTION. + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_ERROR_POWER_ACTION Error powering/resetting card (\ref IFD_ERROR_POWER_ACTION) +@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR) +@retval IFD_NOT_SUPPORTED Action not supported (\ref IFD_NOT_SUPPORTED) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action, PUCHAR Atr, PDWORD + AtrLength); + +/** +This function performs an APDU exchange with the card/slot specified by +Lun. The driver is responsible for performing any protocol specific +exchanges such as T=0, 1, etc. differences. Calling this function will +abstract all protocol differences. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number +@param[in] SendPci contains two structure members +- Protocol 0, 1, ... 14\n + T=0 ... T=14 +- Length\n + Not used. +@param[in] TxBuffer Transmit APDU\n + Example: "\x00\xA4\x00\x00\x02\x3F\x00" +@param[in] TxLength Length of this buffer +@param[out] RxBuffer Receive APDU\n + Example: "\x61\x14" +@param[in,out] RxLength Length of the received APDU\n + This function will be passed the size of the buffer of RxBuffer and + this function is responsible for setting this to the length of the + received APDU response. This should be ZERO on all errors. The + resource manager will take responsibility of zeroing out any temporary + APDU buffers for security reasons. +@param[out] RecvPci contains two structure members +- Protocol - 0, 1, ... 14\n + T=0 ... T=14 +- Length\n + Not used. + +@note +The driver is responsible for knowing what type of card it has. If the +current slot/card contains a memory card then this command should ignore +the Protocol and use the MCT style commands for support for these style +cards and transmit them appropriately. If your reader does not support +memory cards or you don't want to implement this functionality, then +ignore this. +@par +RxLength should be set to zero on error. +@par +The driver is not responsible for doing an automatic Get Response +command for received buffers containing 61 XX. + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR) +@retval IFD_RESPONSE_TIMEOUT The response timed out (\ref IFD_RESPONSE_TIMEOUT) +@retval IFD_ICC_NOT_PRESENT ICC is not present (\ref IFD_ICC_NOT_PRESENT) +@retval IFD_NOT_SUPPORTED Action not supported (\ref IFD_NOT_SUPPORTED) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci, + PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, PDWORD + RxLength, PSCARD_IO_HEADER RecvPci); + +/** +This function returns the status of the card inserted in the reader/slot +specified by @p Lun. In cases where the device supports asynchronous +card insertion/removal detection, it is advised that the driver manages +this through a thread so the driver does not have to send and receive a +command each time this function is called. + +@ingroup IFDHandler +@param[in] Lun Logical Unit Number + +@return Error codes +@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS) +@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR) +@retval IFD_ICC_NOT_PRESENT ICC is not present (\ref IFD_ICC_NOT_PRESENT) +@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE) + */ +RESPONSECODE IFDHICCPresence(DWORD Lun); #endif diff -Nru acsccid-1.0.8/MacOSX/reader.h acsccid-1.1.0/MacOSX/reader.h --- acsccid-1.0.8/MacOSX/reader.h 1970-01-01 00:00:00.000000000 +0000 +++ acsccid-1.1.0/MacOSX/reader.h 2014-12-10 08:32:26.000000000 +0000 @@ -0,0 +1,276 @@ +/* + * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) + * + * Copyright (C) 1999-2005 + * David Corcoran + * Copyright (C) 2005-2009 + * Ludovic Rousseau + * +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +Changes to this license can be made only by the copyright author with +explicit written consent. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: reader.h 6851 2014-02-14 15:43:32Z rousseau $ + */ + +/** + * @file + * @brief This keeps a list of defines shared between the driver and the application + */ + +#ifndef __reader_h__ +#define __reader_h__ + +/* + * Tags for requesting card and reader attributes + */ + +#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag))) + +#define SCARD_CLASS_VENDOR_INFO 1 /**< Vendor information definitions */ +#define SCARD_CLASS_COMMUNICATIONS 2 /**< Communication definitions */ +#define SCARD_CLASS_PROTOCOL 3 /**< Protocol definitions */ +#define SCARD_CLASS_POWER_MGMT 4 /**< Power Management definitions */ +#define SCARD_CLASS_SECURITY 5 /**< Security Assurance definitions */ +#define SCARD_CLASS_MECHANICAL 6 /**< Mechanical characteristic definitions */ +#define SCARD_CLASS_VENDOR_DEFINED 7 /**< Vendor specific definitions */ +#define SCARD_CLASS_IFD_PROTOCOL 8 /**< Interface Device Protocol options */ +#define SCARD_CLASS_ICC_STATE 9 /**< ICC State specific definitions */ +#define SCARD_CLASS_SYSTEM 0x7fff /**< System-specific definitions */ + +#define SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0100) /**< Vendor name. */ +#define SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0101) /**< Vendor-supplied interface device type (model designation of reader). */ +#define SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0102) /**< Vendor-supplied interface device version (DWORD in the form 0xMMmmbbbb where MM = major version, mm = minor version, and bbbb = build number). */ +#define SCARD_ATTR_VENDOR_IFD_SERIAL_NO SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0103) /**< Vendor-supplied interface device serial number. */ +#define SCARD_ATTR_CHANNEL_ID SCARD_ATTR_VALUE(SCARD_CLASS_COMMUNICATIONS, 0x0110) /**< DWORD encoded as 0xDDDDCCCC, where DDDD = data channel type and CCCC = channel number */ +#define SCARD_ATTR_ASYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0120) /**< FIXME */ +#define SCARD_ATTR_DEFAULT_CLK SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0121) /**< Default clock rate, in kHz. */ +#define SCARD_ATTR_MAX_CLK SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0122) /**< Maximum clock rate, in kHz. */ +#define SCARD_ATTR_DEFAULT_DATA_RATE SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0123) /**< Default data rate, in bps. */ +#define SCARD_ATTR_MAX_DATA_RATE SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0124) /**< Maximum data rate, in bps. */ +#define SCARD_ATTR_MAX_IFSD SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0125) /**< Maximum bytes for information file size device. */ +#define SCARD_ATTR_SYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0126) /**< FIXME */ +#define SCARD_ATTR_POWER_MGMT_SUPPORT SCARD_ATTR_VALUE(SCARD_CLASS_POWER_MGMT, 0x0131) /**< Zero if device does not support power down while smart card is inserted. Nonzero otherwise. */ +#define SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE SCARD_ATTR_VALUE(SCARD_CLASS_SECURITY, 0x0140) /**< FIXME */ +#define SCARD_ATTR_USER_AUTH_INPUT_DEVICE SCARD_ATTR_VALUE(SCARD_CLASS_SECURITY, 0x0142) /**< FIXME */ +#define SCARD_ATTR_CHARACTERISTICS SCARD_ATTR_VALUE(SCARD_CLASS_MECHANICAL, 0x0150) /**< DWORD indicating which mechanical characteristics are supported. If zero, no special characteristics are supported. Note that multiple bits can be set */ + +#define SCARD_ATTR_CURRENT_PROTOCOL_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0201) /**< FIXME */ +#define SCARD_ATTR_CURRENT_CLK SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0202) /**< Current clock rate, in kHz. */ +#define SCARD_ATTR_CURRENT_F SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0203) /**< Clock conversion factor. */ +#define SCARD_ATTR_CURRENT_D SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0204) /**< Bit rate conversion factor. */ +#define SCARD_ATTR_CURRENT_N SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0205) /**< Current guard time. */ +#define SCARD_ATTR_CURRENT_W SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0206) /**< Current work waiting time. */ +#define SCARD_ATTR_CURRENT_IFSC SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0207) /**< Current byte size for information field size card. */ +#define SCARD_ATTR_CURRENT_IFSD SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0208) /**< Current byte size for information field size device. */ +#define SCARD_ATTR_CURRENT_BWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0209) /**< Current block waiting time. */ +#define SCARD_ATTR_CURRENT_CWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020a) /**< Current character waiting time. */ +#define SCARD_ATTR_CURRENT_EBC_ENCODING SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020b) /**< Current error block control encoding. */ +#define SCARD_ATTR_EXTENDED_BWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020c) /**< FIXME */ + +#define SCARD_ATTR_ICC_PRESENCE SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0300) /**< Single byte indicating smart card presence */ +#define SCARD_ATTR_ICC_INTERFACE_STATUS SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0301) /**< Single byte. Zero if smart card electrical contact is not active; nonzero if contact is active. */ +#define SCARD_ATTR_CURRENT_IO_STATE SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0302) /**< FIXME */ +#define SCARD_ATTR_ATR_STRING SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0303) /**< Answer to reset (ATR) string. */ +#define SCARD_ATTR_ICC_TYPE_PER_ATR SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0304) /**< Single byte indicating smart card type */ + +#define SCARD_ATTR_ESC_RESET SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA000) /**< FIXME */ +#define SCARD_ATTR_ESC_CANCEL SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA003) /**< FIXME */ +#define SCARD_ATTR_ESC_AUTHREQUEST SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA005) /**< FIXME */ +#define SCARD_ATTR_MAXINPUT SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA007) /**< FIXME */ + +#define SCARD_ATTR_DEVICE_UNIT SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0001) /**< Instance of this vendor's reader attached to the computer. The first instance will be device unit 0, the next will be unit 1 (if it is the same brand of reader) and so on. Two different brands of readers will both have zero for this value. */ +#define SCARD_ATTR_DEVICE_IN_USE SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0002) /**< Reserved for future use. */ +#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0003) +#define SCARD_ATTR_DEVICE_SYSTEM_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0004) +#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_W SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0005) +#define SCARD_ATTR_DEVICE_SYSTEM_NAME_W SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0006) +#define SCARD_ATTR_SUPRESS_T1_IFS_REQUEST SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0007) /**< FIXME */ + +#ifdef UNICODE +#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_W /**< Reader's display name. */ +#define SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME_W /**< Reader's system name. */ +#else +#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_A /**< Reader's display name. */ +#define SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME_A /**< Reader's system name. */ +#endif + +/** + * Provide source compatibility on different platforms + */ +#define SCARD_CTL_CODE(code) (0x42000000 + (code)) + +/** + * PC/SC part 10 v2.02.07 March 2010 reader tags + */ +#define CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400) + +#define FEATURE_VERIFY_PIN_START 0x01 +#define FEATURE_VERIFY_PIN_FINISH 0x02 +#define FEATURE_MODIFY_PIN_START 0x03 +#define FEATURE_MODIFY_PIN_FINISH 0x04 +#define FEATURE_GET_KEY_PRESSED 0x05 +#define FEATURE_VERIFY_PIN_DIRECT 0x06 /**< Verify PIN */ +#define FEATURE_MODIFY_PIN_DIRECT 0x07 /**< Modify PIN */ +#define FEATURE_MCT_READER_DIRECT 0x08 +#define FEATURE_MCT_UNIVERSAL 0x09 +#define FEATURE_IFD_PIN_PROPERTIES 0x0A /**< retrieve properties of the IFD regarding PIN handling */ +#define FEATURE_ABORT 0x0B +#define FEATURE_SET_SPE_MESSAGE 0x0C +#define FEATURE_VERIFY_PIN_DIRECT_APP_ID 0x0D +#define FEATURE_MODIFY_PIN_DIRECT_APP_ID 0x0E +#define FEATURE_WRITE_DISPLAY 0x0F +#define FEATURE_GET_KEY 0x10 +#define FEATURE_IFD_DISPLAY_PROPERTIES 0x11 +#define FEATURE_GET_TLV_PROPERTIES 0x12 +#define FEATURE_CCID_ESC_COMMAND 0x13 +#define FEATURE_EXECUTE_PACE 0x20 + +/* structures used (but not defined) in PC/SC Part 10: + * "IFDs with Secure Pin Entry Capabilities" */ + +#include + +/* Set structure elements aligment on bytes + * http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */ +#if defined(__APPLE__) | defined(sun) +#pragma pack(1) +#else +#pragma pack(push, 1) +#endif + +/** the structure must be 6-bytes long */ +typedef struct +{ + uint8_t tag; + uint8_t length; + uint32_t value; /**< This value is always in BIG ENDIAN format as documented in PCSC v2 part 10 ch 2.2 page 2. You can use ntohl() for example */ +} PCSC_TLV_STRUCTURE; + +/** Since CCID 1.4.1 (revision 5252) the byte order is no more important + * These macros are now deprecated and should be removed in the future */ +#define HOST_TO_CCID_16(x) (x) +#define HOST_TO_CCID_32(x) (x) + +/** structure used with \ref FEATURE_VERIFY_PIN_DIRECT */ +typedef struct +{ + uint8_t bTimerOut; /**< timeout is seconds (00 means use default timeout) */ + uint8_t bTimerOut2; /**< timeout in seconds after first key stroke */ + uint8_t bmFormatString; /**< formatting options */ + uint8_t bmPINBlockString; /**< bits 7-4 bit size of PIN length in APDU, + * bits 3-0 PIN block size in bytes after + * justification and formatting */ + uint8_t bmPINLengthFormat; /**< bits 7-5 RFU, + * bit 4 set if system units are bytes, clear if + * system units are bits, + * bits 3-0 PIN length position in system units */ + uint16_t wPINMaxExtraDigit; /**< 0xXXYY where XX is minimum PIN size in digits, + and YY is maximum PIN size in digits */ + uint8_t bEntryValidationCondition; /**< Conditions under which PIN entry should + * be considered complete */ + uint8_t bNumberMessage; /**< Number of messages to display for PIN verification */ + uint16_t wLangId; /**< Language for messages */ + uint8_t bMsgIndex; /**< Message index (should be 00) */ + uint8_t bTeoPrologue[3]; /**< T=1 block prologue field to use (fill with 00) */ + uint32_t ulDataLength; /**< length of Data to be sent to the ICC */ + uint8_t abData +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + [] /* valid C99 code */ +#else + [0] /* non-standard, but usually working code */ +#endif + ; /**< Data to send to the ICC */ +} PIN_VERIFY_STRUCTURE; + +/** structure used with \ref FEATURE_MODIFY_PIN_DIRECT */ +typedef struct +{ + uint8_t bTimerOut; /**< timeout is seconds (00 means use default timeout) */ + uint8_t bTimerOut2; /**< timeout in seconds after first key stroke */ + uint8_t bmFormatString; /**< formatting options */ + uint8_t bmPINBlockString; /**< bits 7-4 bit size of PIN length in APDU, + * bits 3-0 PIN block size in bytes after + * justification and formatting */ + uint8_t bmPINLengthFormat; /**< bits 7-5 RFU, + * bit 4 set if system units are bytes, clear if + * system units are bits, + * bits 3-0 PIN length position in system units */ + uint8_t bInsertionOffsetOld; /**< Insertion position offset in bytes for + the current PIN */ + uint8_t bInsertionOffsetNew; /**< Insertion position offset in bytes for + the new PIN */ + uint16_t wPINMaxExtraDigit; + /**< 0xXXYY where XX is minimum PIN size in digits, + and YY is maximum PIN size in digits */ + uint8_t bConfirmPIN; /**< Flags governing need for confirmation of new PIN */ + uint8_t bEntryValidationCondition; /**< Conditions under which PIN entry should + * be considered complete */ + uint8_t bNumberMessage; /**< Number of messages to display for PIN verification*/ + uint16_t wLangId; /**< Language for messages */ + uint8_t bMsgIndex1; /**< index of 1st prompting message */ + uint8_t bMsgIndex2; /**< index of 2d prompting message */ + uint8_t bMsgIndex3; /**< index of 3d prompting message */ + uint8_t bTeoPrologue[3]; /**< T=1 block prologue field to use (fill with 00) */ + uint32_t ulDataLength; /**< length of Data to be sent to the ICC */ + uint8_t abData +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + [] /* valid C99 code */ +#else + [0] /* non-standard, but usually working code */ +#endif + ; /**< Data to send to the ICC */ +} PIN_MODIFY_STRUCTURE; + +/** structure used with \ref FEATURE_IFD_PIN_PROPERTIES */ +typedef struct { + uint16_t wLcdLayout; /**< display characteristics */ + uint8_t bEntryValidationCondition; + uint8_t bTimeOut2; +} PIN_PROPERTIES_STRUCTURE; + +/* restore default structure elements alignment */ +#if defined(__APPLE__) | defined(sun) +#pragma pack() +#else +#pragma pack(pop) +#endif + +/* properties returned by FEATURE_GET_TLV_PROPERTIES */ +#define PCSCv2_PART10_PROPERTY_wLcdLayout 1 +#define PCSCv2_PART10_PROPERTY_bEntryValidationCondition 2 +#define PCSCv2_PART10_PROPERTY_bTimeOut2 3 +#define PCSCv2_PART10_PROPERTY_wLcdMaxCharacters 4 +#define PCSCv2_PART10_PROPERTY_wLcdMaxLines 5 +#define PCSCv2_PART10_PROPERTY_bMinPINSize 6 +#define PCSCv2_PART10_PROPERTY_bMaxPINSize 7 +#define PCSCv2_PART10_PROPERTY_sFirmwareID 8 +#define PCSCv2_PART10_PROPERTY_bPPDUSupport 9 +#define PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize 10 +#define PCSCv2_PART10_PROPERTY_wIdVendor 11 +#define PCSCv2_PART10_PROPERTY_wIdProduct 12 + +#endif + diff -Nru acsccid-1.0.8/MacOSX/reader.h.in acsccid-1.1.0/MacOSX/reader.h.in --- acsccid-1.0.8/MacOSX/reader.h.in 2009-05-14 18:39:23.000000000 +0000 +++ acsccid-1.1.0/MacOSX/reader.h.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,223 +0,0 @@ -/* - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) - * - * Copyright (C) 1999-2005 - * David Corcoran - * Copyright (C) 1999-2009 - * Ludovic Rousseau - * - * $Id: reader.h.in 4210 2009-05-14 13:14:59Z rousseau $ - */ - -/** - * @file - * @brief This keeps a list of defines shared between the driver and the application - */ - -#ifndef __reader_h__ -#define __reader_h__ - -/* - * Tags for requesting card and reader attributes - */ - -#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag))) - -#define SCARD_CLASS_VENDOR_INFO 1 /**< Vendor information definitions */ -#define SCARD_CLASS_COMMUNICATIONS 2 /**< Communication definitions */ -#define SCARD_CLASS_PROTOCOL 3 /**< Protocol definitions */ -#define SCARD_CLASS_POWER_MGMT 4 /**< Power Management definitions */ -#define SCARD_CLASS_SECURITY 5 /**< Security Assurance definitions */ -#define SCARD_CLASS_MECHANICAL 6 /**< Mechanical characteristic definitions */ -#define SCARD_CLASS_VENDOR_DEFINED 7 /**< Vendor specific definitions */ -#define SCARD_CLASS_IFD_PROTOCOL 8 /**< Interface Device Protocol options */ -#define SCARD_CLASS_ICC_STATE 9 /**< ICC State specific definitions */ -#define SCARD_CLASS_SYSTEM 0x7fff /**< System-specific definitions */ - -#define SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0100) /**< Vendor name. */ -#define SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0101) /**< Vendor-supplied interface device type (model designation of reader). */ -#define SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0102) /**< Vendor-supplied interface device version (DWORD in the form 0xMMmmbbbb where MM = major version, mm = minor version, and bbbb = build number). */ -#define SCARD_ATTR_VENDOR_IFD_SERIAL_NO SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0103) /**< Vendor-supplied interface device serial number. */ -#define SCARD_ATTR_CHANNEL_ID SCARD_ATTR_VALUE(SCARD_CLASS_COMMUNICATIONS, 0x0110) /**< DWORD encoded as 0xDDDDCCCC, where DDDD = data channel type and CCCC = channel number */ -#define SCARD_ATTR_ASYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0120) /**< FIXME */ -#define SCARD_ATTR_DEFAULT_CLK SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0121) /**< Default clock rate, in kHz. */ -#define SCARD_ATTR_MAX_CLK SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0122) /**< Maximum clock rate, in kHz. */ -#define SCARD_ATTR_DEFAULT_DATA_RATE SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0123) /**< Default data rate, in bps. */ -#define SCARD_ATTR_MAX_DATA_RATE SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0124) /**< Maximum data rate, in bps. */ -#define SCARD_ATTR_MAX_IFSD SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0125) /**< Maximum bytes for information file size device. */ -#define SCARD_ATTR_SYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0126) /**< FIXME */ -#define SCARD_ATTR_POWER_MGMT_SUPPORT SCARD_ATTR_VALUE(SCARD_CLASS_POWER_MGMT, 0x0131) /**< Zero if device does not support power down while smart card is inserted. Nonzero otherwise. */ -#define SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE SCARD_ATTR_VALUE(SCARD_CLASS_SECURITY, 0x0140) /**< FIXME */ -#define SCARD_ATTR_USER_AUTH_INPUT_DEVICE SCARD_ATTR_VALUE(SCARD_CLASS_SECURITY, 0x0142) /**< FIXME */ -#define SCARD_ATTR_CHARACTERISTICS SCARD_ATTR_VALUE(SCARD_CLASS_MECHANICAL, 0x0150) /**< DWORD indicating which mechanical characteristics are supported. If zero, no special characteristics are supported. Note that multiple bits can be set */ - -#define SCARD_ATTR_CURRENT_PROTOCOL_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0201) /**< FIXME */ -#define SCARD_ATTR_CURRENT_CLK SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0202) /**< Current clock rate, in kHz. */ -#define SCARD_ATTR_CURRENT_F SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0203) /**< Clock conversion factor. */ -#define SCARD_ATTR_CURRENT_D SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0204) /**< Bit rate conversion factor. */ -#define SCARD_ATTR_CURRENT_N SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0205) /**< Current guard time. */ -#define SCARD_ATTR_CURRENT_W SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0206) /**< Current work waiting time. */ -#define SCARD_ATTR_CURRENT_IFSC SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0207) /**< Current byte size for information field size card. */ -#define SCARD_ATTR_CURRENT_IFSD SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0208) /**< Current byte size for information field size device. */ -#define SCARD_ATTR_CURRENT_BWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0209) /**< Current block waiting time. */ -#define SCARD_ATTR_CURRENT_CWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020a) /**< Current character waiting time. */ -#define SCARD_ATTR_CURRENT_EBC_ENCODING SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020b) /**< Current error block control encoding. */ -#define SCARD_ATTR_EXTENDED_BWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020c) /**< FIXME */ - -#define SCARD_ATTR_ICC_PRESENCE SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0300) /**< Single byte indicating smart card presence */ -#define SCARD_ATTR_ICC_INTERFACE_STATUS SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0301) /**< Single byte. Zero if smart card electrical contact is not active; nonzero if contact is active. */ -#define SCARD_ATTR_CURRENT_IO_STATE SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0302) /**< FIXME */ -#define SCARD_ATTR_ATR_STRING SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0303) /**< Answer to reset (ATR) string. */ -#define SCARD_ATTR_ICC_TYPE_PER_ATR SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0304) /**< Single byte indicating smart card type */ - -#define SCARD_ATTR_ESC_RESET SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA000) /**< FIXME */ -#define SCARD_ATTR_ESC_CANCEL SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA003) /**< FIXME */ -#define SCARD_ATTR_ESC_AUTHREQUEST SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA005) /**< FIXME */ -#define SCARD_ATTR_MAXINPUT SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA007) /**< FIXME */ - -#define SCARD_ATTR_DEVICE_UNIT SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0001) /**< Instance of this vendor's reader attached to the computer. The first instance will be device unit 0, the next will be unit 1 (if it is the same brand of reader) and so on. Two different brands of readers will both have zero for this value. */ -#define SCARD_ATTR_DEVICE_IN_USE SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0002) /**< Reserved for future use. */ -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0003) -#define SCARD_ATTR_DEVICE_SYSTEM_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0004) -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_W SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0005) -#define SCARD_ATTR_DEVICE_SYSTEM_NAME_W SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0006) -#define SCARD_ATTR_SUPRESS_T1_IFS_REQUEST SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0007) /**< FIXME */ - -#ifdef UNICODE -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_W /**< Reader's display name. */ -#define SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME_W /**< Reader's system name. */ -#else -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_A /**< Reader's display name. */ -#define SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME_A /**< Reader's system name. */ -#endif - -/** - * Provide source compatibility on different platforms - */ -#define SCARD_CTL_CODE(code) (0x42000000 + (code)) - -/** - * PC/SC v2.02.05 part 10 reader tags - */ -#define CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400) - -#define FEATURE_VERIFY_PIN_START 0x01 -#define FEATURE_VERIFY_PIN_FINISH 0x02 -#define FEATURE_MODIFY_PIN_START 0x03 -#define FEATURE_MODIFY_PIN_FINISH 0x04 -#define FEATURE_GET_KEY_PRESSED 0x05 -#define FEATURE_VERIFY_PIN_DIRECT 0x06 /**< Verify PIN */ -#define FEATURE_MODIFY_PIN_DIRECT 0x07 /**< Modify PIN */ -#define FEATURE_MCT_READERDIRECT 0x08 -#define FEATURE_MCT_UNIVERSAL 0x09 -#define FEATURE_IFD_PIN_PROPERTIES 0x0A /**< retrieve properties of the IFD regarding PIN handling */ -#define FEATURE_ABORT 0x0B -#define FEATURE_SET_SPE_MESSAGE 0x0C -#define FEATURE_VERIFY_PIN_DIRECT_APP_ID 0x0D -#define FEATURE_MODIFY_PIN_DIRECT_APP_ID 0x0E -#define FEATURE_WRITE_DISPLAY 0x0F -#define FEATURE_GET_KEY 0x10 -#define FEATURE_IFD_DISPLAY_PROPERTIES 0x11 - -/* structures used (but not defined) in PC/SC Part 10 revision 2.02.05: - * "IFDs with Secure Pin Entry Capabilities" */ - -#include - -/* Set structure elements aligment on bytes - * http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */ -#if defined(__APPLE__) | defined(sun) -#pragma pack(1) -#else -#pragma pack(push, 1) -#endif - -/** the structure must be 6-bytes long */ -typedef struct -{ - uint8_t tag; - uint8_t length; - uint32_t value; /**< This value is always in BIG ENDIAN format as documented in PCSC v2 part 10 ch 2.2 page 2. You can use ntohl() for example */ -} PCSC_TLV_STRUCTURE; - -/** the wLangId and wPINMaxExtraDigit are 16-bits long so are subject to byte - * ordering */ -#define HOST_TO_CCID_16(x) @host_to_ccid_16@ -#define HOST_TO_CCID_32(x) @host_to_ccid_32@ - -/** structure used with \ref FEATURE_VERIFY_PIN_DIRECT */ -typedef struct -{ - uint8_t bTimerOut; /**< timeout is seconds (00 means use default timeout) */ - uint8_t bTimerOut2; /**< timeout in seconds after first key stroke */ - uint8_t bmFormatString; /**< formatting options */ - uint8_t bmPINBlockString; /**< bits 7-4 bit size of PIN length in APDU, - * bits 3-0 PIN block size in bytes after - * justification and formatting */ - uint8_t bmPINLengthFormat; /**< bits 7-5 RFU, - * bit 4 set if system units are bytes, clear if - * system units are bits, - * bits 3-0 PIN length position in system units */ - uint16_t wPINMaxExtraDigit; /**< 0xXXYY where XX is minimum PIN size in digits, - and YY is maximum PIN size in digits */ - uint8_t bEntryValidationCondition; /**< Conditions under which PIN entry should - * be considered complete */ - uint8_t bNumberMessage; /**< Number of messages to display for PIN verification */ - uint16_t wLangId; /**< Language for messages */ - uint8_t bMsgIndex; /**< Message index (should be 00) */ - uint8_t bTeoPrologue[3]; /**< T=1 block prologue field to use (fill with 00) */ - uint32_t ulDataLength; /**< length of Data to be sent to the ICC */ - uint8_t abData[1]; /**< Data to send to the ICC */ -} PIN_VERIFY_STRUCTURE; - -/** structure used with \ref FEATURE_MODIFY_PIN_DIRECT */ -typedef struct -{ - uint8_t bTimerOut; /**< timeout is seconds (00 means use default timeout) */ - uint8_t bTimerOut2; /**< timeout in seconds after first key stroke */ - uint8_t bmFormatString; /**< formatting options */ - uint8_t bmPINBlockString; /**< bits 7-4 bit size of PIN length in APDU, - * bits 3-0 PIN block size in bytes after - * justification and formatting */ - uint8_t bmPINLengthFormat; /**< bits 7-5 RFU, - * bit 4 set if system units are bytes, clear if - * system units are bits, - * bits 3-0 PIN length position in system units */ - uint8_t bInsertionOffsetOld; /**< Insertion position offset in bytes for - the current PIN */ - uint8_t bInsertionOffsetNew; /**< Insertion position offset in bytes for - the new PIN */ - uint16_t wPINMaxExtraDigit; - /**< 0xXXYY where XX is minimum PIN size in digits, - and YY is maximum PIN size in digits */ - uint8_t bConfirmPIN; /**< Flags governing need for confirmation of new PIN */ - uint8_t bEntryValidationCondition; /**< Conditions under which PIN entry should - * be considered complete */ - uint8_t bNumberMessage; /**< Number of messages to display for PIN verification*/ - uint16_t wLangId; /**< Language for messages */ - uint8_t bMsgIndex1; /**< index of 1st prompting message */ - uint8_t bMsgIndex2; /**< index of 2d prompting message */ - uint8_t bMsgIndex3; /**< index of 3d prompting message */ - uint8_t bTeoPrologue[3]; /**< T=1 block prologue field to use (fill with 00) */ - uint32_t ulDataLength; /**< length of Data to be sent to the ICC */ - uint8_t abData[1]; /**< Data to send to the ICC */ -} PIN_MODIFY_STRUCTURE; - -/** structure used with \ref FEATURE_IFD_PIN_PROPERTIES */ -typedef struct { - uint16_t wLcdLayout; /**< display characteristics */ - uint16_t wLcdMaxCharacters; - uint16_t wLcdMaxLines; - uint8_t bEntryValidationCondition; - uint8_t bTimeOut2; -} PIN_PROPERTIES_STRUCTURE; - -/* restore default structure elements alignment */ -#if defined(__APPLE__) | defined(sun) -#pragma pack() -#else -#pragma pack(pop) -#endif - -#endif - diff -Nru acsccid-1.0.8/Makefile.am acsccid-1.1.0/Makefile.am --- acsccid-1.0.8/Makefile.am 2014-06-16 05:51:03.000000000 +0000 +++ acsccid-1.1.0/Makefile.am 2014-12-10 08:32:26.000000000 +0000 @@ -10,7 +10,7 @@ MacOSX/debuglog.h \ MacOSX/ifdhandler.h \ MacOSX/pcsclite.h \ - MacOSX/reader.h.in \ + MacOSX/reader.h \ MacOSX/winscard.h \ MacOSX/wintypes.h diff -Nru acsccid-1.0.8/Makefile.in acsccid-1.1.0/Makefile.in --- acsccid-1.0.8/Makefile.in 2014-07-03 02:07:54.000000000 +0000 +++ acsccid-1.1.0/Makefile.in 2014-12-10 08:34:13.000000000 +0000 @@ -81,8 +81,9 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in AUTHORS COPYING ChangeLog INSTALL NEWS \ - README config/compile config/config.guess config/config.sub \ - config/install-sh config/missing config/ltmain.sh \ + README config/ar-lib config/compile config/config.guess \ + config/config.sub config/install-sh config/missing \ + config/ltmain.sh $(top_srcdir)/config/ar-lib \ $(top_srcdir)/config/compile $(top_srcdir)/config/config.guess \ $(top_srcdir)/config/config.sub \ $(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \ @@ -243,7 +244,6 @@ # Automatically update the libtool script if it becomes out-of-date. LIBTOOL_DEPS = @LIBTOOL_DEPS@ -LIBUSBCONFIG = @LIBUSBCONFIG@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIPO = @LIPO@ @@ -349,7 +349,7 @@ MacOSX/debuglog.h \ MacOSX/ifdhandler.h \ MacOSX/pcsclite.h \ - MacOSX/reader.h.in \ + MacOSX/reader.h \ MacOSX/winscard.h \ MacOSX/wintypes.h diff -Nru acsccid-1.0.8/NEWS acsccid-1.1.0/NEWS --- acsccid-1.0.8/NEWS 2008-11-18 21:48:42.000000000 +0000 +++ acsccid-1.1.0/NEWS 2014-12-10 08:32:26.000000000 +0000 @@ -0,0 +1 @@ +Read the README file for news. diff -Nru acsccid-1.0.8/README acsccid-1.1.0/README --- acsccid-1.0.8/README 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/README 2014-12-10 08:32:26.000000000 +0000 @@ -10,11 +10,23 @@ readers. This library provides a PC/SC IFD handler implementation and communicates with the readers through the PC/SC Lite resource manager (pcscd). -acsccid is based on ccid 1.3.11. See CCID free software driver [1] for more +acsccid is based on ccid. See CCID free software driver [1] for more information. -To build acsccid, you need pcsc-lite 1.3.3 or above and libusb 0.1.12. For more -information, see the INSTALL file. +To build acsccid, you need the following software: + +Linux +- pcsclite 1.8.3 or above +- libusb 1.0.8 or above +- flex +- perl +- pkg-config + +Mac OS X +- libusb 1.0.9 or above +- pkg-config + +For more information, see the INSTALL file. [1] http://pcsclite.alioth.debian.org/ccid.html @@ -54,7 +66,7 @@ 072F 2011 ACR88U ACS ACR88U 072F 8900 ACR89U-A1 ACS ACR89 ICC Reader 072F 8901 ACR89U-A2 ACS ACR89 Dual Reader -072F 8902 ACR89U-A3 ACS ACR89 FP Reader +072F 8902 ACR89U-FP ACS ACR89 FP Reader 072F 1205 ACR100I ACS ACR100 ICC Reader 072F 1204 ACR101 ACS ACR101 ICC Reader 072F 1206 ACR102 ACS ACR102 ICC Reader @@ -76,11 +88,12 @@ 072F 2218 ACR1251U-C (SAM) ACS ACR1251U-C Smart Card Reader 072F 221B ACR1251U-C ACS ACR1251U-C Smart Card Reader 072F 2232 ACR1251UK ACS ACR1251K Dual Reader -072F 2242 ACR1251U-C1 ACS ACR1251 1S Dual Reader +072F 2242 ACR1251U-C3 ACS ACR1251 1S Dual Reader 072F 223B ACR1252U-A1 ACS ACR1252 1S CL Reader 072F 223E ACR1252U-A2 ACS ACR1252 CL Reader 072F 223D ACR1252U BL ACS ACR1252 USB FW_Upgrade v100 -072F 2244 ACR1252U-A1 (PICC) ACS ACR1252 BADANAMU MAGIC READER +072F 2244 ACR1252U-A1 (PICC) ACS ACR1252U BADANAMU MAGIC READER +072F 223F ACR1255U-J1 ACS ACR1255U-J1 PICC Reader 072F 2239 ACR1256U ACS ACR1256U PICC Reader 072F 2211 ACR1261U-C1 ACS ACR1261 1S Dual Reader 072F 2100 ACR128U ACS ACR128U @@ -123,9 +136,17 @@ History ------- +v1.1.0 (10/12/2014) +- Add the following readers support: + ACR1255U-J1 PICC Reader +- Fix the PICC detection problem in ACR1281 2S CL Reader. +- Merge with ccid 1.4.18. + - Fix the memory leak in Multi_PollingProc(). +- Fix the compilation warnings. + v1.0.8 (3/7/2014) - Add the following readers support: - ACS ACR1252 BADANAMU MAGIC READER + ACS ACR1252U BADANAMU MAGIC READER ACS ACR1261 1S Dual Reader - Change the delay of cold reset to 10 ms. - Remove the checking of specific mode before setting the parameters. @@ -341,7 +362,7 @@ ------------------------------------------------------------------------------- Copyright (C) 2009-2014 Advanced Card Systems Ltd. -Copyright (C) 2003-2009 Ludovic Rousseau +Copyright (C) 2003-2011 Ludovic Rousseau Copyright (C) 2000-2001 Carlos Prados Copyright (C) 2003 Olaf Kirch Copyright (C) 1999-2002 Matthias Bruestle diff -Nru acsccid-1.0.8/src/92_pcscd_acsccid_group.rules acsccid-1.1.0/src/92_pcscd_acsccid_group.rules --- acsccid-1.0.8/src/92_pcscd_acsccid_group.rules 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/src/92_pcscd_acsccid_group.rules 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -# udev rules to set the access rights of ACS CCID smart card readers -# so they can be used by pcscd - -# If not adding the device, go away -ACTION!="add", GOTO="pcscd_acsccid_rules_end" -SUBSYSTEM!="usb", GOTO="pcscd_acsccid_rules_end" -ENV{DEVTYPE}!="usb_device", GOTO="pcscd_acsccid_rules_end" - -# generic CCID device (bInterfaceClass = 0x0b) -ENV{ID_USB_INTERFACES}=="*:0b0000:*", GROUP="pcscd" - -# -# non CCID generic (InterfaceClass: 0x00) -# - -# ACS ACR83U -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90d2", GROUP="pcscd" - -# ACS ACR88U -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2011", GROUP="pcscd" - -# ACS ACR1251 1S Dual Reader -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2242", GROUP="pcscd" - -# ACS ACR1261 1S Dual Reader -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2211", GROUP="pcscd" - -# ACS ACR128U -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2100", GROUP="pcscd" - -# ACS ACR1281 1S Dual Reader -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2224", GROUP="pcscd" - -# ACS ACR1281 2S CL Reader -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2215", GROUP="pcscd" - -# ACS APG8201 -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="8201", GROUP="pcscd" - -# -# non-CCID readers -# - -# ACS ACR38U -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="9000", GROUP="pcscd" - -# ACS ACR38U-SAM -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90cf", GROUP="pcscd" - -# ACS AET65 1SAM ICC Reader -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="0101", GROUP="pcscd" - -# IRIS SCR21U -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90ce", GROUP="pcscd" - -# ACS CryptoMate -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="9006", GROUP="pcscd" - -# All done -LABEL="pcscd_acsccid_rules_end" diff -Nru acsccid-1.0.8/src/acr38cmd.c acsccid-1.1.0/src/acr38cmd.c --- acsccid-1.0.8/src/acr38cmd.c 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/src/acr38cmd.c 2014-12-10 08:32:26.000000000 +0000 @@ -1,6 +1,6 @@ /* acr38cmd.c: Emulated CCID reader commands for ACR38 non-CCID reader - Copyright (C) 2011-2013 Advanced Card Systems Ltd. + Copyright (C) 2011-2014 Advanced Card Systems Ltd. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,10 +17,21 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "config.h" +#include + +#ifdef HAVE_STRING_H #include +#endif +#ifdef HAVE_STDLIB_H #include +#endif +#ifdef HAVE_ERRNO_H #include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + #include #include #include @@ -32,7 +43,6 @@ #include "defs.h" #include "ccid_ifdhandler.h" #include "debug.h" -#include "ccid_usb.h" #define ACR38_HEADER_SIZE 4 #define ACR38_STATUS_OFFSET 1 @@ -81,11 +91,6 @@ #define ACR38_OPTION_EMV_MODE 0x10 // EMV mode #define ACR38_OPTION_MEMCARD_MODE 0x20 // Memory card mode -// Fix problem using pcsc-lite 1.6.x header files -#ifndef IFD_ERROR_INSUFFICIENT_BUFFER -#define IFD_ERROR_INSUFFICIENT_BUFFER 618 -#endif - static RESPONSECODE ACR38_CmdXfrBlockTPDU_T0(unsigned int reader_index, unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length, unsigned char rx_buffer[]); @@ -582,7 +587,7 @@ break; default: - DEBUG_CRITICAL2("Card type %d is not supported", cardType); + DEBUG_CRITICAL2("Card type " DWORD_D " is not supported", cardType); ccid_descriptor->cardType = ACR38_CARD_TYPE_MCU_AUTO; return_value = IFD_COMMUNICATION_ERROR; break; @@ -604,7 +609,6 @@ unsigned int length; RESPONSECODE return_value = IFD_SUCCESS; unsigned char buffer_tmp[20]; - _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); // GET_ACR_STAT cmd[0] = 0x01; diff -Nru acsccid-1.0.8/src/ccid.c acsccid-1.1.0/src/ccid.c --- acsccid-1.0.8/src/ccid.c 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/src/ccid.c 2014-12-10 08:32:26.000000000 +0000 @@ -1,7 +1,7 @@ /* ccid.c: CCID common code - Copyright (C) 2003-2005 Ludovic Rousseau - Copyright (C) 2009-2013 Advanced Card Systems Ltd. + Copyright (C) 2003-2010 Ludovic Rousseau + Copyright (C) 2009-2014 Advanced Card Systems Ltd. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -19,23 +19,38 @@ */ /* - * $Id: ccid.c 4346 2009-07-28 13:39:37Z rousseau $ + * $Id: ccid.c 6976 2014-09-04 11:35:46Z rousseau $ */ +#include + +#ifdef HAVE_STDIO_H #include +#endif +#ifdef HAVE_STDLIB_H #include +#endif +#ifdef HAVE_STRING_H #include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + #include #include -#include "config.h" #include "debug.h" #include "ccid.h" #include "defs.h" #include "ccid_ifdhandler.h" #include "commands.h" +#include "utils.h" #include "acr38cmd.h" -#include "ccid_usb.h" + +#ifdef __APPLE__ +#include +#endif static int ACR83_GetFirmwareVersion(unsigned int reader_index, unsigned int *pFirmwareVersion); static int ACR83_DisplayLcdMessage(unsigned int reader_index, const char *message); @@ -49,17 +64,10 @@ int ccid_open_hack_pre(unsigned int reader_index) { _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); - int doInterruptRead = 0; // Disable InterruptRead int i; switch (ccid_descriptor->readerID) { - case CARDMAN3121+1: - /* Reader announces APDU but is in fact TPDU */ - ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; - ccid_descriptor->dwFeatures |= CCID_CLASS_TPDU; - break; - case MYSMARTPAD: ccid_descriptor->dwMaxIFSD = 254; break; @@ -67,12 +75,24 @@ case CL1356D: /* the firmware needs some time to initialize */ (void)sleep(1); - ccid_descriptor->readTimeout = 60; /* 60 seconds */ + ccid_descriptor->readTimeout = 60*1000; /* 60 seconds */ break; - case KOBIL_TRIBANK: - /* the InterruptRead does not timeout (on Mac OS X) */ - doInterruptRead = 0; + case GEMPCTWIN: + case GEMPCKEY: + case DELLSCRK: + /* Only the chipset with firmware version 2.00 is "bogus" + * The reader may send packets of 0 bytes when the reader is + * connected to a USB 3 port */ + if (0x0200 == ccid_descriptor->IFD_bcdDevice) + { + ccid_descriptor->zlp = TRUE; + DEBUG_INFO1("ZLP fixup"); + } + break; + + case OZ776_7772: + ccid_descriptor->dwMaxDataRate = 9600; break; case ACS_ACR122U: @@ -93,17 +113,21 @@ break; } +#ifndef __APPLE__ /* CCID */ - if (doInterruptRead && (0 == ccid_descriptor->bInterfaceProtocol)) + if (((PROTOCOL_CCID == ccid_descriptor->bInterfaceProtocol) + || (PROTOCOL_ACR38 == ccid_descriptor->bInterfaceProtocol)) + && (3 == ccid_descriptor -> bNumEndpoints)) { #ifndef TWIN_SERIAL - /* just wait for 10ms in case a notification is in the pipe */ - (void)InterruptRead(reader_index, 10); + /* just wait for 100ms in case a notification is in the pipe */ + (void)InterruptRead(reader_index, 100); #endif } +#endif /* ICCD type A */ - if (ICCD_A == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol) { unsigned char tmp[MAX_ATR_SIZE]; unsigned int n = sizeof(tmp); @@ -115,7 +139,7 @@ } /* ICCD type B */ - if (ICCD_B == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol) { unsigned char tmp[MAX_ATR_SIZE]; unsigned int n = sizeof(tmp); @@ -137,6 +161,102 @@ return 0; } /* ccid_open_hack_pre */ +#ifndef NO_LOG +/***************************************************************************** + * + * dump_gemalto_firmware_features + * + ****************************************************************************/ +static void dump_gemalto_firmware_features(struct GEMALTO_FIRMWARE_FEATURES *gff) +{ + DEBUG_INFO2("Dumping Gemalto firmware features (%zd bytes):", + sizeof(struct GEMALTO_FIRMWARE_FEATURES)); + +#define YESNO(x) (x) ? "yes" : "no" + + DEBUG_INFO2(" bLogicalLCDLineNumber: %d", gff->bLogicalLCDLineNumber); + DEBUG_INFO2(" bLogicalLCDRowNumber: %d", gff->bLogicalLCDRowNumber); + DEBUG_INFO2(" bLcdInfo: 0x%02X", gff->bLcdInfo); + DEBUG_INFO2(" bEntryValidationCondition: 0x%02X", + gff->bEntryValidationCondition); + + DEBUG_INFO1(" Reader supports PC/SCv2 features:"); + DEBUG_INFO2(" VerifyPinStart: %s", YESNO(gff->VerifyPinStart)); + DEBUG_INFO2(" VerifyPinFinish: %s", YESNO(gff->VerifyPinFinish)); + DEBUG_INFO2(" ModifyPinStart: %s", YESNO(gff->ModifyPinStart)); + DEBUG_INFO2(" ModifyPinFinish: %s", YESNO(gff->ModifyPinFinish)); + DEBUG_INFO2(" GetKeyPressed: %s", YESNO(gff->GetKeyPressed)); + DEBUG_INFO2(" VerifyPinDirect: %s", YESNO(gff->VerifyPinDirect)); + DEBUG_INFO2(" ModifyPinDirect: %s", YESNO(gff->ModifyPinDirect)); + DEBUG_INFO2(" Abort: %s", YESNO(gff->Abort)); + DEBUG_INFO2(" GetKey: %s", YESNO(gff->GetKey)); + DEBUG_INFO2(" WriteDisplay: %s", YESNO(gff->WriteDisplay)); + DEBUG_INFO2(" SetSpeMessage: %s", YESNO(gff->SetSpeMessage)); + DEBUG_INFO2(" bTimeOut2: %s", YESNO(gff->bTimeOut2)); + DEBUG_INFO2(" bPPDUSupportOverXferBlock: %s", + YESNO(gff->bPPDUSupportOverXferBlock)); + DEBUG_INFO2(" bPPDUSupportOverEscape: %s", + YESNO(gff->bPPDUSupportOverEscape)); + + DEBUG_INFO2(" bListSupportedLanguages: %s", + YESNO(gff->bListSupportedLanguages)); + DEBUG_INFO2(" bNumberMessageFix: %s", YESNO(gff->bNumberMessageFix)); + + DEBUG_INFO2(" VersionNumber: 0x%02X", gff->VersionNumber); + DEBUG_INFO2(" MinimumPINSize: %d", gff->MinimumPINSize); + DEBUG_INFO2(" MaximumPINSize: %d", gff->MaximumPINSize); + DEBUG_INFO2(" Firewall: %s", YESNO(gff->Firewall)); + if (gff->Firewall && gff->FirewalledCommand_SW1 + && gff->FirewalledCommand_SW2) + { + DEBUG_INFO2(" FirewalledCommand_SW1: 0x%02X", + gff->FirewalledCommand_SW1); + DEBUG_INFO2(" FirewalledCommand_SW2: 0x%02X", + gff->FirewalledCommand_SW2); + } + +} /* dump_gemalto_firmware_features */ +#endif + +/***************************************************************************** + * + * set_gemalto_firmware_features + * + ****************************************************************************/ +static void set_gemalto_firmware_features(unsigned int reader_index) +{ + _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + struct GEMALTO_FIRMWARE_FEATURES *gf_features; + + gf_features = malloc(sizeof(struct GEMALTO_FIRMWARE_FEATURES)); + if (gf_features) + { + unsigned char cmd[] = { 0x6A }; /* GET_FIRMWARE_FEATURES command id */ + unsigned int len_features = sizeof *gf_features; + RESPONSECODE ret; + + ret = CmdEscape(reader_index, cmd, sizeof cmd, + (unsigned char*)gf_features, &len_features, 0); + if ((IFD_SUCCESS == ret) && + (len_features == sizeof *gf_features)) + { + /* Command is supported if it succeeds at CCID level */ + /* and returned size matches our expectation */ + ccid_descriptor->gemalto_firmware_features = gf_features; +#ifndef NO_LOG + dump_gemalto_firmware_features(gf_features); +#endif + } + else + { + /* Command is not supported, let's free allocated memory */ + free(gf_features); + DEBUG_INFO3("GET_FIRMWARE_FEATURES failed: " DWORD_D ", len=%d", + ret, len_features); + } + } +} /* set_gemalto_firmware_features */ + /***************************************************************************** * * ccid_open_hack_post @@ -145,19 +265,20 @@ int ccid_open_hack_post(unsigned int reader_index) { _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + RESPONSECODE return_value = IFD_SUCCESS; switch (ccid_descriptor->readerID) { case GEMPCKEY: case GEMPCTWIN: - /* Reader announces TPDU but can do APDU */ + /* Reader announces TPDU but can do APDU (EMV in fact) */ if (DriverOptions & DRIVER_OPTION_GEMPC_TWIN_KEY_APDU) { - unsigned char cmd[] = { 0xA0, 0x02 }; + unsigned char cmd[] = { 0x1F, 0x02 }; unsigned char res[10]; unsigned int length_res = sizeof(res); - if (CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res) == IFD_SUCCESS) + if (CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0) == IFD_SUCCESS) { ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU; @@ -165,6 +286,7 @@ } break; + case VEGAALPHA: case GEMPCPINPAD: /* load the l10n strings in the pinpad memory */ { @@ -273,10 +395,28 @@ "Card Error", "PIN blocked" }; - char *lang; + const char *lang; const char **l10n; +#ifdef __APPLE__ + CFArrayRef cfa; + CFStringRef slang; + + /* Get the complete ordered list */ + cfa = CFLocaleCopyPreferredLanguages(); + + /* Use the first/preferred language + * As the driver is run as root we get the language + * selected during install */ + slang = CFArrayGetValueAtIndex(cfa, 0); + + /* CFString -> C string */ + lang = CFStringGetCStringPtr(slang, kCFStringEncodingMacRoman); +#else + /* The other Unixes just use the LANG env variable */ lang = getenv("LANG"); +#endif + DEBUG_COMM2("Using lang: %s", lang); if (NULL == lang) l10n = en; else @@ -299,6 +439,10 @@ l10n = en; } +#ifdef __APPLE__ + /* Release the allocated array */ + CFRelease(cfa); +#endif offset = 0; cmd[offset++] = 0xB2; /* load strings */ cmd[offset++] = 0xA0; /* address of the memory */ @@ -319,17 +463,42 @@ } (void)sleep(1); - if (IFD_SUCCESS == CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res)) + if (IFD_SUCCESS == CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, DEFAULT_COM_READ_TIMEOUT)) { DEBUG_COMM("l10n string loaded successfully"); } else { DEBUG_COMM("Failed to load l10n strings"); + return_value = IFD_COMMUNICATION_ERROR; + } + + if (DriverOptions & DRIVER_OPTION_DISABLE_PIN_RETRIES) + { + /* disable VERIFY from reader */ + const unsigned char cmd2[] = {0xb5, 0x00}; + length_res = sizeof(res); + if (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res, DEFAULT_COM_READ_TIMEOUT)) + { + DEBUG_COMM("Disable SPE retry counter successfull"); + } + else + { + DEBUG_CRITICAL("Failed to disable SPE retry counter"); + } } } break; + case HPSMARTCARDKEYBOARD: + case HP_CCIDSMARTCARDKEYBOARD: + case FUJITSUSMARTKEYB: + /* the Secure Pin Entry is bogus so disable it + * http://martinpaljak.net/2011/03/19/insecure-hp-usb-smart-card-keyboard/ + */ + ccid_descriptor->bPINSupport = 0; + break; + #if 0 /* SCM SCR331-DI contactless */ case SCR331DI: @@ -350,8 +519,8 @@ unsigned char res[20]; unsigned int length_res = sizeof(res); - if ((IFD_SUCCESS == CmdEscape(reader_index, cmd1, sizeof(cmd1), res, &length_res)) - && (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res))) + if ((IFD_SUCCESS == CmdEscape(reader_index, cmd1, sizeof(cmd1), res, &length_res, 0)) + && (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res, 0))) { DEBUG_COMM("SCM SCR331-DI contactless detected"); } @@ -384,7 +553,7 @@ ccid_descriptor->wLcdLayout = 0x0210; - DEBUG_INFO("Getting ACR83U firmware version..."); + DEBUG_INFO1("Getting ACR83U firmware version..."); if (ACR83_GetFirmwareVersion(reader_index, &firmwareVersion)) { DEBUG_INFO2("ACR83U firmware version: 0x%04X", firmwareVersion); @@ -423,7 +592,7 @@ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK; ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU; - DEBUG_INFO("Getting ACR85 ICC firmware version..."); + DEBUG_INFO1("Getting ACR85 ICC firmware version..."); if (ACR83_GetFirmwareVersion(reader_index, &firmwareVersion)) { DEBUG_INFO2("ACR85 ICC firmware version: 0x%04X", firmwareVersion); @@ -446,7 +615,7 @@ char firmwareVersion[30]; unsigned int firmwareVersionLen = sizeof(firmwareVersion); - DEBUG_INFO("Getting ACR1222 firmware version..."); + DEBUG_INFO1("Getting ACR1222 firmware version..."); if (ACR1222_GetFirmwareVersion(reader_index, firmwareVersion, &firmwareVersionLen)) { DEBUG_INFO2("ACR1222 firmware version: %s", firmwareVersion); @@ -457,7 +626,7 @@ if ((ccid_descriptor->firmwareFixEnabled) && (ccid_descriptor->bCurrentSlotIndex == 1)) { - DEBUG_INFO("Enabling PICC..."); + DEBUG_INFO1("Enabling PICC..."); EnablePicc(reader_index, 1); } } @@ -477,7 +646,7 @@ char firmwareVersion[30]; unsigned int firmwareVersionLen = sizeof(firmwareVersion); - DEBUG_INFO("Getting ACR85 PICC firmware version..."); + DEBUG_INFO1("Getting ACR85 PICC firmware version..."); if (ACR1222_GetFirmwareVersion(reader_index, firmwareVersion, &firmwareVersionLen)) { DEBUG_INFO2("ACR85 PICC firmware version: %s", firmwareVersion); @@ -487,7 +656,7 @@ if (ccid_descriptor->firmwareFixEnabled) { - DEBUG_INFO("Enabling PICC..."); + DEBUG_INFO1("Enabling PICC..."); EnablePicc(reader_index, 1); } } @@ -594,6 +763,7 @@ { ccid_descriptor->dwFeatures = 0x0004047A; // Contactless ccid_descriptor->dwMaxDataRate = 344100; + ccid_descriptor->isSamSlot = 0; } else { @@ -642,7 +812,11 @@ break; } - return 0; + /* Gemalto readers may report additional information */ + if (GET_VENDOR(ccid_descriptor->readerID) == VENDOR_GEMALTO) + set_gemalto_firmware_features(reader_index); + + return return_value; } /* ccid_open_hack_post */ /***************************************************************************** @@ -652,6 +826,7 @@ ****************************************************************************/ void ccid_error(int error, const char *file, int line, const char *function) { +#ifndef NO_LOG const char *text; char var_text[30]; @@ -769,11 +944,13 @@ break; } log_msg(PCSC_LOG_ERROR, "%s:%d:%s %s", file, line, function, text); +#endif } /* ccid_error */ void acr38_error(int error, const char *file, int line, const char *function) { +#ifndef NO_LOG const char *text; char var_text[30]; @@ -835,6 +1012,7 @@ } log_msg(PCSC_LOG_ERROR, "%s:%d:%s %s", file, line, function, text); +#endif } // Enable PICC @@ -847,13 +1025,13 @@ unsigned char antennaOn[] = { 0xFF, 0x00, 0x00, 0x00, 0x04, 0xD4, 0x32, 0x01, 0x03 }; unsigned char response[300]; - int responseLen; + unsigned int responseLen; if (enabled) { // Turn ON polling responseLen = sizeof(response); - if (CmdEscape(reader_index, pollingOn, sizeof(pollingOn), response, &responseLen) != IFD_SUCCESS) + if (CmdEscape(reader_index, pollingOn, sizeof(pollingOn), response, &responseLen, 0) != IFD_SUCCESS) { DEBUG_CRITICAL("Polling ON failed"); } @@ -869,7 +1047,7 @@ { // Turn OFF polling responseLen = sizeof(response); - if (CmdEscape(reader_index, pollingOff, sizeof(pollingOff), response, &responseLen) != IFD_SUCCESS) + if (CmdEscape(reader_index, pollingOff, sizeof(pollingOff), response, &responseLen, 0) != IFD_SUCCESS) { DEBUG_CRITICAL("Polling OFF failed"); } @@ -891,7 +1069,7 @@ unsigned char response[3 + 6]; unsigned int responseLen = sizeof(response); - if (CmdEscape(reader_index, command, commandLen, response, &responseLen) == IFD_SUCCESS) + if (CmdEscape(reader_index, command, commandLen, response, &responseLen, 0) == IFD_SUCCESS) { if ((responseLen >= 7) && (response[0] == 0x84)) { @@ -921,7 +1099,7 @@ // Copy message to command memcpy(command + 5, message, messageLen); - if (CmdEscape(reader_index, command, commandLen, response, &responseLen) == IFD_SUCCESS) + if (CmdEscape(reader_index, command, commandLen, response, &responseLen, 0) == IFD_SUCCESS) { if ((responseLen >= 5) && (response[0] == 0x85) && (response[3] == 0) && (response[4] == 0)) @@ -940,7 +1118,7 @@ unsigned char response[300]; unsigned int responseLen = sizeof(response); - if (CmdEscape(reader_index, command, sizeof(command), response, &responseLen) == IFD_SUCCESS) + if (CmdEscape(reader_index, command, sizeof(command), response, &responseLen, 0) == IFD_SUCCESS) { if (*pFirmwareVersionLen >= responseLen - 5 + 1) { diff -Nru acsccid-1.0.8/src/ccid.h acsccid-1.1.0/src/ccid.h --- acsccid-1.0.8/src/ccid.h 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/src/ccid.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,6 +1,6 @@ /* ccid.h: CCID structures - Copyright (C) 2003-2009 Ludovic Rousseau + Copyright (C) 2003-2010 Ludovic Rousseau Copyright (C) 2009-2014 Advanced Card Systems Ltd. This library is free software; you can redistribute it and/or @@ -19,7 +19,7 @@ */ /* - * $Id: ccid.h 4280 2009-06-26 14:58:23Z rousseau $ + * $Id: ccid.h 6922 2014-06-16 13:55:33Z rousseau $ */ #ifdef __APPLE__ @@ -91,7 +91,7 @@ /* * Read communication port timeout - * value is seconds + * value is milliseconds * this value can evolve dynamically if card request it (time processing). */ unsigned int readTimeout; @@ -127,8 +127,30 @@ */ int bVoltageSupport; - // bcdDevice - unsigned int bcdDevice; + /* + * USB serial number of the device (if any) + */ + char *sIFD_serial_number; + + /* + * USB iManufacturer string + */ + char *sIFD_iManufacturer; + + /* + * USB bcdDevice + */ + int IFD_bcdDevice; + + /* + * Gemalto extra features, if any + */ + struct GEMALTO_FIRMWARE_FEATURES *gemalto_firmware_features; + + /* + * Zero Length Packet fixup (boolean) + */ + char zlp; // Pointer to array of bStatus unsigned char *bStatus; @@ -187,8 +209,9 @@ #define CCID_TIME_EXTENSION 0x80 /* 10 0000 00 */ /* bInterfaceProtocol for ICCD */ -#define ICCD_A 1 /* ICCD Version A */ -#define ICCD_B 2 /* ICCD Version B */ +#define PROTOCOL_CCID 0 /* plain CCID */ +#define PROTOCOL_ICCD_A 1 /* ICCD Version A */ +#define PROTOCOL_ICCD_B 2 /* ICCD Version B */ #define PROTOCOL_ACR38 38 // ACR38 non-CCID /* Product identification for special treatments */ @@ -197,9 +220,11 @@ #define GEMPCTWIN 0x08E63437 #define GEMPCPINPAD 0x08E63478 #define GEMCORESIMPRO 0x08E63480 +#define GEMCORESIMPRO2 0x08E60000 /* Does NOT match a real VID/PID as new firmware release exposes same VID/PID */ #define GEMCOREPOSPRO 0x08E63479 #define GEMALTOPROXDU 0x08E65503 #define GEMALTOPROXSU 0x08E65504 +#define GEMALTO_EZIO_CBP 0x08E634C3 #define CARDMAN3121 0x076B3021 #define LTC31 0x07830003 #define SCR331DI 0x04E65111 @@ -217,7 +242,14 @@ #define SEG 0x08E68000 #define BLUDRIVEII_CCID 0x1B0E1078 #define DELLSCRK 0x413C2101 +#define DELLSK 0x413C2100 #define KOBIL_TRIBANK 0x0D463010 +#define KOBIL_MIDENTITY_VISUAL 0x0D460D46 +#define VEGAALPHA 0x09820008 +#define HPSMARTCARDKEYBOARD 0x03F01024 +#define HP_CCIDSMARTCARDKEYBOARD 0x03F00036 +#define KOBIL_IDTOKEN 0x0D46301D +#define FUJITSUSMARTKEYB 0x0BF81017 // CCID readers #define ACS_ACR32_ICC_READER 0x072fb301 @@ -270,6 +302,9 @@ #define ACS_AET65_1SAM_ICC_READER 0x072f0101 #define ACS_CRYPTOMATE 0x072f9006 +#define VENDOR_GEMALTO 0x08E6 +#define GET_VENDOR(readerID) ((readerID >> 16) & 0xFFFF) + /* * The O2Micro OZ776S reader has a wrong USB descriptor * The extra[] field is associated with the last endpoint instead of the @@ -322,3 +357,72 @@ /* data rates supported by the secondary slots on the GemCore Pos Pro & SIM Pro */ #define GEMPLUS_CUSTOM_DATA_RATES 10753, 21505, 43011, 125000 +/* data rates for GemCore SIM Pro 2 */ +#define SIMPRO2_ISO_DATA_RATES 8709, 10322, 12403, 12500, \ + 12903, 17204, 18750, 20645, 24806, \ + 25000, 25806, 28125, 30967, 34408, \ + 37500, 41290, 46875, 49612, 50000, \ + 51612, 56250, 62500, 64516, 68817, \ + 74418, 75000, 82580, 86021, 93750, \ + 99224, 100000, 103225, 112500, 124031, \ + 125000, 137634, 150000, 154838, 165161, \ + 172043, 187500, 198449, 200000, 206451, \ + 258064, 275268, 300000, 396899, 400000, \ + 412903, 550537, 600000, 825806 + +/* Structure returned by Gemalto readers for the CCID Escape command 0x6A */ +struct GEMALTO_FIRMWARE_FEATURES +{ + unsigned char bLogicalLCDLineNumber; /* Logical number of LCD lines */ + unsigned char bLogicalLCDRowNumber; /* Logical number of characters per LCD line */ + unsigned char bLcdInfo; /* b0 indicates if scrolling is available */ + unsigned char bEntryValidationCondition; /* See PIN_PROPERTIES */ + + /* Here come the PC/SC bit features to report */ + unsigned char VerifyPinStart:1; + unsigned char VerifyPinFinish:1; + unsigned char ModifyPinStart:1; + unsigned char ModifyPinFinish:1; + unsigned char GetKeyPressed:1; + unsigned char VerifyPinDirect:1; + unsigned char ModifyPinDirect:1; + unsigned char Abort:1; + + unsigned char GetKey:1; + unsigned char WriteDisplay:1; + unsigned char SetSpeMessage:1; + unsigned char RFUb1:5; + + unsigned char RFUb2[2]; + + /* Additional flags */ + unsigned char bTimeOut2:1; + unsigned char bListSupportedLanguages:1; /* Reader is able to indicate + the list of supported languages through CCID-ESC 0x6B */ + unsigned char bNumberMessageFix:1; /* Reader handles correctly shifts + made by bNumberMessage in PIN modification data structure */ + unsigned char bPPDUSupportOverXferBlock:1; /* Reader supports PPDU over + PC_to_RDR_XferBlock command */ + unsigned char bPPDUSupportOverEscape:1; /* Reader supports PPDU over + PC_to_RDR_Escape command with abData[0]=0xFF */ + unsigned char RFUb3:3; + + unsigned char RFUb4[3]; + + unsigned char VersionNumber; /* ?? */ + unsigned char MinimumPINSize; /* for Verify and Modify */ + unsigned char MaximumPINSize; + + /* Miscellaneous reader features */ + unsigned char Firewall:1; + unsigned char RFUb5:7; + + /* The following fields, FirewalledCommand_SW1 and + * FirewalledCommand_SW2 are only valid if Firewall=1 + * These fields give the SW1 SW2 value used by the reader to + * indicate a command has been firewalled */ + unsigned char FirewalledCommand_SW1; + unsigned char FirewalledCommand_SW2; + unsigned char RFUb6[3]; +}; + diff -Nru acsccid-1.0.8/src/ccid_ifdhandler.h acsccid-1.1.0/src/ccid_ifdhandler.h --- acsccid-1.0.8/src/ccid_ifdhandler.h 2012-01-05 08:05:24.000000000 +0000 +++ acsccid-1.1.0/src/ccid_ifdhandler.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,7 +1,7 @@ /* ccid_ifdhandler.h: non-generic ifdhandler functions - Copyright (C) 2004-2009 Ludovic Rousseau - Copyright (C) 2010-2012 Advanced Card Systems Ltd. + Copyright (C) 2004-2010 Ludovic Rousseau + Copyright (C) 2010-2014 Advanced Card Systems Ltd. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,7 @@ */ /* - * $Id: ccid_ifdhandler.h 4279 2009-06-26 14:58:03Z rousseau $ + * $Id: ccid_ifdhandler.h 6876 2014-03-23 12:00:57Z rousseau $ */ #ifndef _ccid_ifd_handler_h_ @@ -32,24 +32,12 @@ SCARD_CTL_CODE(FEATURE_VERIFY_PIN_DIRECT + CLASS2_IOCTL_MAGIC) #define IOCTL_FEATURE_MODIFY_PIN_DIRECT \ SCARD_CTL_CODE(FEATURE_MODIFY_PIN_DIRECT + CLASS2_IOCTL_MAGIC) - -// Fix problem using pcsc-lite 1.7.3 or later header files -#ifndef FEATURE_MCT_READERDIRECT -#define FEATURE_MCT_READERDIRECT FEATURE_MCT_READER_DIRECT -#endif - -#define IOCTL_FEATURE_MCT_READERDIRECT \ - SCARD_CTL_CODE(FEATURE_MCT_READERDIRECT + CLASS2_IOCTL_MAGIC) - -// Fix problem using pcsc-lite 1.4.x header files -#ifdef FEATURE_IFD_PIN_PROP -#define FEATURE_IFD_PIN_PROPERTIES FEATURE_IFD_PIN_PROP -#endif - -#ifdef FEATURE_IFD_PIN_PROPERTIES +#define IOCTL_FEATURE_MCT_READER_DIRECT \ + SCARD_CTL_CODE(FEATURE_MCT_READER_DIRECT + CLASS2_IOCTL_MAGIC) #define IOCTL_FEATURE_IFD_PIN_PROPERTIES \ SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC) -#endif +#define IOCTL_FEATURE_GET_TLV_PROPERTIES \ + SCARD_CTL_CODE(FEATURE_GET_TLV_PROPERTIES + CLASS2_IOCTL_MAGIC) // MS CCID I/O control code for escape command #define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(3500) @@ -70,10 +58,11 @@ #define DRIVER_OPTION_GEMPC_TWIN_KEY_APDU 2 #define DRIVER_OPTION_USE_BOGUS_FIRMWARE 4 #define DRIVER_OPTION_RESET_ON_CLOSE 8 +#define DRIVER_OPTION_DISABLE_PIN_RETRIES (1 << 6) -// ACR1222/ACR85 driver option -#define DRIVER_OPTION_REMOVE_PUPI_FROM_ATR 0x40 -#define DRIVER_OPTION_DISABLE_PICC 0x80 +// ACS driver option +#define ACS_DRIVER_OPTION_REMOVE_PUPI_FROM_ATR 1 +#define ACS_DRIVER_OPTION_DISABLE_PICC 2 extern int DriverOptions; diff -Nru acsccid-1.0.8/src/ccid_usb.c acsccid-1.1.0/src/ccid_usb.c --- acsccid-1.0.8/src/ccid_usb.c 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/src/ccid_usb.c 2014-12-10 08:32:26.000000000 +0000 @@ -1,17 +1,17 @@ /* - ccid_usb.c: USB access routines using the libusb library - Copyright (C) 2003-2009 Ludovic Rousseau - Copyright (C) 2009-2014 Advanced Card Systems Ltd. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + ccid_usb.c: USB access routines using the libusb library + Copyright (C) 2003-2010 Ludovic Rousseau + Copyright (C) 2009-2014 Advanced Card Systems Ltd. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, @@ -19,57 +19,74 @@ */ /* - * $Id: ccid_usb.c 4346 2009-07-28 13:39:37Z rousseau $ + * $Id: ccid_usb.c 6975 2014-09-04 11:33:05Z rousseau $ */ #define __CCID_USB__ -#ifdef __APPLE__ -#include -#endif - #include #include #include +#include # ifdef S_SPLINT_S # include # endif -#include +#include +#include +#include +#include #include +#include #include "misc.h" #include "ccid.h" -#include "config.h" #include "debug.h" #include "defs.h" #include "utils.h" #include "parser.h" #include "ccid_ifdhandler.h" -#ifdef __APPLE__ -#include -#endif - /* write timeout * we don't have to wait a long time since the card was doing nothing */ -#define USB_WRITE_TIMEOUT (5 * 1000) /* 5 seconds timeout */ +#define USB_WRITE_TIMEOUT (5 * 1000) /* 5 seconds timeout */ /* * Proprietary USB Class (0xFF) are (or are not) accepted * A proprietary class is used for devices released before the final CCID * specifications were ready. - * We should not have problems with non CCID devices becasue the + * We should not have problems with non CCID devices because the * Manufacturer and Product ID are also used to identify the device */ #define ALLOW_PROPRIETARY_CLASS #define BUS_DEVICE_STRSIZE 32 +/* Using the default libusb context */ +/* does not work for libusb <= 1.0.8 */ +/* #define ctx NULL */ +libusb_context *ctx = NULL; + +#define CCID_INTERRUPT_SIZE 8 + +struct usbDevice_MultiSlot_Extension +{ + int reader_index; + + /* The multi-threaded polling part */ + int terminated; + int status; + unsigned char buffer[CCID_INTERRUPT_SIZE]; + pthread_t thread_proc; + pthread_mutex_t mutex; + pthread_cond_t condition; + struct libusb_transfer *transfer; +}; + typedef struct { - usb_dev_handle *handle; - char *dirname; - char *filename; + libusb_device_handle *dev_handle; + uint8_t bus_number; + uint8_t device_address; int interface; /* @@ -88,6 +105,12 @@ */ _ccid_descriptor ccid; + /* libusb transfer for the polling (or NULL) */ + struct libusb_transfer *polling_transfer; + + /* pointer to the multislot extension (if any) */ + struct usbDevice_MultiSlot_Extension *multislot_extension; + #ifdef __APPLE__ // Thread handle for card detection pthread_t hThread; @@ -95,6 +118,13 @@ // Flag to terminate thread int terminated; int *pTerminated; + + // Pointer to libusb transfer + struct libusb_transfer **pTransfer; + + // Lock for libusb transfer + pthread_mutex_t transferLock; + pthread_mutex_t *pTransferLock; #endif // Max packet size of bulk out endpoint @@ -104,67 +134,29 @@ /* The _usbDevice structure must be defined before including ccid_usb.h */ #include "ccid_usb.h" -static int get_end_points(struct usb_device *dev, _usbDevice *usbdevice, int num); -int ccid_check_firmware(struct usb_device *dev); +/* Specific hooks for multislot readers */ +static int Multi_InterruptRead(int reader_index, int timeout /* in ms */); +static void Multi_InterruptStop(int reader_index); +static struct usbDevice_MultiSlot_Extension *Multi_CreateFirstSlot(int reader_index); +static struct usbDevice_MultiSlot_Extension *Multi_CreateNextSlot(int physical_reader_index); +static void Multi_PollingTerminate(struct usbDevice_MultiSlot_Extension *msExt); + +static int get_end_points(struct libusb_config_descriptor *desc, + _usbDevice *usbdevice, int num); +int ccid_check_firmware(struct libusb_device_descriptor *desc); static unsigned int *get_data_rates(unsigned int reader_index, - struct usb_device *dev, int num); + struct libusb_config_descriptor *desc, int num); #ifdef __APPLE__ - -#if defined (kIOUSBInterfaceInterfaceID220) -#define usb_interface_t IOUSBInterfaceInterface220 -#elif defined (kIOUSBInterfaceInterfaceID197) -#define usb_interface_t IOUSBInterfaceInterface197 -#elif defined (kIOUSBInterfaceInterfaceID190) -#define usb_interface_t IOUSBInterfaceInterface190 -#elif defined (kIOUSBInterfaceInterfaceID182) -#define usb_interface_t IOUSBInterfaceInterface182 -#else -#define usb_interface_t IOUSBInterfaceInterface -#endif - -#if defined (kIOUSBDeviceInterfaceID197) -#define usb_device_t IOUSBDeviceInterface197 -#elif defined (kIOUSBDeviceInterfaceID187) -#define usb_device_t IOUSBDeviceInterface187 -#elif defined (kIOUSBDeviceInterfaceID182) -#define usb_device_t IOUSBDeviceInterface182 -#else -#define usb_device_t IOUSBDeviceInterface -#endif - -struct darwin_dev_handle { - usb_device_t **device; - usb_interface_t **interface; - int open; - - int num_endpoints; - unsigned char *endpoint_addrs; -}; - -struct usb_dev_handle { - int fd; - - struct usb_bus *bus; - struct usb_device *device; - - int config; - int interface; - int altsetting; - - void *impl_info; -}; - static void *CardDetectionThread(void *pParam); -static int GetPipeRef(struct darwin_dev_handle *device, int ep); #endif /* ne need to initialize to 0 since it is static */ static _usbDevice usbDevice[CCID_DRIVER_MAX_READERS]; -#define PCSCLITE_MANUKEY_NAME "ifdVendorID" -#define PCSCLITE_PRODKEY_NAME "ifdProductID" -#define PCSCLITE_NAMEKEY_NAME "ifdFriendlyName" +#define PCSCLITE_MANUKEY_NAME "ifdVendorID" +#define PCSCLITE_PRODKEY_NAME "ifdProductID" +#define PCSCLITE_NAMEKEY_NAME "ifdFriendlyName" struct _bogus_firmware { @@ -176,7 +168,6 @@ static struct _bogus_firmware Bogus_firmwares[] = { { 0x04e6, 0xe001, 0x0516 }, /* SCR 331 */ { 0x04e6, 0x5111, 0x0620 }, /* SCR 331-DI */ - { 0x04e6, 0x5115, 0x0514 }, /* SCR 335 */ { 0x04e6, 0xe003, 0x0510 }, /* SPR 532 */ { 0x0D46, 0x3001, 0x0037 }, /* KAAN Base */ { 0x0D46, 0x3002, 0x0037 }, /* KAAN Advanced */ @@ -184,8 +175,13 @@ { 0x0DC3, 0x1004, 0x0502 }, /* ASE IIIe USBv2 */ { 0x0DC3, 0x1102, 0x0607 }, /* ASE IIIe KB USB */ { 0x058F, 0x9520, 0x0102 }, /* Alcor AU9520-G */ - // Remove firmware version checking - // { 0x072F, 0x2200, 0x0206 }, /* ACS ACR122U-WB-R */ + { 0x08C3, 0x0402, 0x5000 }, /* Precise Biometrics Precise 200 MC */ + { 0x08C3, 0x0401, 0x5000 }, /* Precise Biometrics Precise 250 MC */ + { 0x0B0C, 0x0050, 0x0101 }, /* Todos Argos Mini II */ + { 0x0DC3, 0x0900, 0x0200 }, /* Athena IDProtect Key v2 */ + { 0x03F0, 0x0036, 0x0124 }, /* HP USB CCID Smartcard Keyboard */ + { 0x062D, 0x0001, 0x0102 }, /* THRC Smart Card Reader */ + { 0x04E6, 0x5291, 0x0112 }, /* SCM SCL010 Contactless Reader */ /* the firmware version is not correct since I do not have received a * working reader yet */ @@ -197,6 +193,29 @@ /* data rates supported by the secondary slots on the GemCore Pos Pro & SIM Pro */ unsigned int SerialCustomDataRates[] = { GEMPLUS_CUSTOM_DATA_RATES, 0 }; +/***************************************************************************** + * + * close_libusb_if_needed + * + ****************************************************************************/ +static void close_libusb_if_needed(void) +{ + int i, to_exit = TRUE; + + /* if at least 1 reader is still in use we do not exit libusb */ + for (i=0; inext) + /* for every device */ + i = 0; + while ((dev = devs[i++]) != NULL) { - struct usb_device *dev; + struct libusb_device_descriptor desc; + struct libusb_config_descriptor *config_desc; + uint8_t bus_number = libusb_get_bus_number(dev); + uint8_t device_address = libusb_get_device_address(dev); - /* any device on this bus */ - for (dev = bus->devices; dev; dev = dev->next) + int r = libusb_get_device_descriptor(dev, &desc); + if (r < 0) { - /* device defined by name? */ - if (dirname && (strcmp(dirname, bus->dirname) - || strcmp(filename, dev->filename))) - continue; + DEBUG_INFO3("failed to get device descriptor for %d/%d", + bus_number, device_address); + continue; + } - if (dev->descriptor.idVendor == vendorID - && dev->descriptor.idProduct == productID) - { - int r, already_used; - struct usb_interface *usb_interface = NULL; - int interface; - int num = 0; - int readerID = (vendorID << 16) + productID; - int numSlots; + if (desc.idVendor == vendorID && desc.idProduct == productID) + { + int already_used; + const struct libusb_interface *usb_interface = NULL; + int interface; + int num = 0; + const unsigned char *device_descriptor; + int readerID = (vendorID << 16) + productID; + int numSlots = 0; #ifdef USE_COMPOSITE_AS_MULTISLOT - static int static_interface = 1; + static int static_interface = 1; - { - /* simulate a composite device as when libhal is - * used */ - if ((GEMALTOPROXDU == readerID) - || (GEMALTOPROXSU == readerID)) - { - if(interface_number >= 0) - { - DEBUG_CRITICAL("USE_COMPOSITE_AS_MULTISLOT can't be used with libhal"); - continue; - } + /* simulate a composite device as when libudev is used */ + if ((GEMALTOPROXDU == readerID) + || (GEMALTOPROXSU == readerID)) + { + /* + * We can't talk to the two CCID interfaces + * at the same time (the reader enters a + * dead lock). So we simulate a multi slot + * reader. By default multi slot readers + * can't use the slots at the same time. See + * TAG_IFD_SLOT_THREAD_SAFE + * + * One side effect is that the two readers + * are seen by pcscd as one reader so the + * interface name is the same for the two. + * + * So we have: + * 0: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 00 + * 1: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 01 + * instead of + * 0: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 00 + * 1: Gemalto Prox-DU [Prox-DU Contactless_09A00795] (09A00795) 01 00 + */ - /* the CCID interfaces are 1 and 2 */ - interface_number = static_interface; - } - // Simulate ACR1281 Dual Reader (composite device) as multi-slot reader - else if ((ACS_ACR1281_DUAL_READER_QPBOC == readerID) || - (ACS_ACR1281_DUAL_READER_BSI == readerID) || - (ACS_ACR1281_1S_PICC_READER == readerID) || - (ACS_ACR1251_1S_CL_READER == readerID) || - (ACS_ACR1251U_C == readerID) || - (ACS_ACR1251K_DUAL_READER == readerID) || - (ACS_ACR1252_1S_CL_READER == readerID)) - { - // the CCID interfaces are 0 and 1 - interface_number = static_interface - 1; - } - } + /* the CCID interfaces are 1 and 2 */ + interface_number = static_interface; + } + // Simulate ACR1281 Dual Reader (composite device) as multi-slot reader + else if ((ACS_ACR1281_DUAL_READER_QPBOC == readerID) || + (ACS_ACR1281_DUAL_READER_BSI == readerID) || + (ACS_ACR1281_1S_PICC_READER == readerID) || + (ACS_ACR1251_1S_CL_READER == readerID) || + (ACS_ACR1251U_C == readerID) || + (ACS_ACR1251K_DUAL_READER == readerID) || + (ACS_ACR1252_1S_CL_READER == readerID)) + { + // the CCID interfaces are 0 and 1 + interface_number = static_interface - 1; + } #endif - /* is it already opened? */ - already_used = FALSE; + /* is it already opened? */ + already_used = FALSE; - DEBUG_COMM3("Checking device: %s/%s", - bus->dirname, dev->filename); - for (r=0; rdirname) == 0 && strcmp(usbDevice[r].filename, dev->filename) == 0) - already_used = TRUE; - } + /* same bus, same address */ + if (usbDevice[r].bus_number == bus_number + && usbDevice[r].device_address == device_address) + already_used = TRUE; } + } - /* this reader is already managed by us */ - if (already_used) - { - if ((previous_reader_index != -1) - && usbDevice[previous_reader_index].handle - && (strcmp(usbDevice[previous_reader_index].dirname, bus->dirname) == 0) - && (strcmp(usbDevice[previous_reader_index].filename, dev->filename) == 0) - && usbDevice[previous_reader_index].ccid.bCurrentSlotIndex < usbDevice[previous_reader_index].ccid.bMaxSlotIndex) + /* this reader is already managed by us */ + if (already_used) + { + if ((previous_reader_index != -1) + && usbDevice[previous_reader_index].dev_handle + && (usbDevice[previous_reader_index].bus_number == bus_number) + && (usbDevice[previous_reader_index].device_address == device_address) + && usbDevice[previous_reader_index].ccid.bCurrentSlotIndex < usbDevice[previous_reader_index].ccid.bMaxSlotIndex) + { + /* we reuse the same device + * and the reader is multi-slot */ + usbDevice[reader_index] = usbDevice[previous_reader_index]; + /* The other slots of GemCore SIM Pro firmware + * 1.0 do not have the same data rates. + * Firmware 2.0 do not have this limitation */ + if ((GEMCOREPOSPRO == readerID) + || ((GEMCORESIMPRO == readerID) + && (usbDevice[reader_index].ccid.IFD_bcdDevice < 0x0200))) { - /* we reuse the same device - * and the reader is multi-slot */ - usbDevice[reader_index] = usbDevice[previous_reader_index]; - /* the other slots do not have the same data rates */ - if ((GEMCOREPOSPRO == usbDevice[reader_index].ccid.readerID) - || (GEMCORESIMPRO == usbDevice[reader_index].ccid.readerID)) - { - usbDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialCustomDataRates; - usbDevice[reader_index].ccid.dwMaxDataRate = 125000; - } - - *usbDevice[reader_index].nb_opened_slots += 1; - usbDevice[reader_index].ccid.bCurrentSlotIndex++; - usbDevice[reader_index].ccid.dwSlotStatus = - IFD_ICC_PRESENT; - - // Get PICC reader index - if (((usbDevice[reader_index].ccid.readerID == ACS_ACR1222_DUAL_READER) || - (usbDevice[reader_index].ccid.readerID == ACS_ACR1222_1SAM_DUAL_READER)) - && (usbDevice[reader_index].ccid.bCurrentSlotIndex == 1) || - (usbDevice[reader_index].ccid.readerID == ACS_ACR85_PINPAD_READER_ICC)) - { - *usbDevice[reader_index].ccid.pPiccReaderIndex = reader_index; - } + usbDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialCustomDataRates; + usbDevice[reader_index].ccid.dwMaxDataRate = 125000; + } - DEBUG_INFO2("Opening slot: %d", - usbDevice[reader_index].ccid.bCurrentSlotIndex); + *usbDevice[reader_index].nb_opened_slots += 1; + usbDevice[reader_index].ccid.bCurrentSlotIndex++; + usbDevice[reader_index].ccid.dwSlotStatus = + IFD_ICC_PRESENT; + DEBUG_INFO2("Opening slot: %d", + usbDevice[reader_index].ccid.bCurrentSlotIndex); - // Simulate ACR85 as multi-slot reader - if (usbDevice[reader_index].ccid.readerID == ACS_ACR85_PINPAD_READER_ICC) + // Simulate ACR85 as multi-slot reader + if (usbDevice[reader_index].ccid.readerID == ACS_ACR85_PINPAD_READER_ICC) + { + libusb_device *picc_dev = NULL; + int picc_index = 0; + struct libusb_device_descriptor picc_desc; + uint8_t picc_bus_number = 0; + + // Reset number of opened slots + *usbDevice[reader_index].nb_opened_slots = 1; + + // Find PICC + dev = NULL; + while ((picc_dev = devs[picc_index++]) != NULL) { - struct usb_device *piccDevice; - - // Reset number of opened slots - *usbDevice[reader_index].nb_opened_slots = 1; + picc_bus_number = libusb_get_bus_number(picc_dev); - // Find PICC - dev = NULL; - for (piccDevice = bus->devices; piccDevice; piccDevice = piccDevice->next) + r = libusb_get_device_descriptor(picc_dev, &picc_desc); + if (r < 0) { - if ((piccDevice->descriptor.idVendor << 16) + piccDevice->descriptor.idProduct == ACS_ACR85_PINPAD_READER_PICC) - { - dev = piccDevice; - break; - } + continue; } - if (dev == NULL) + if ((picc_bus_number == bus_number) && + ((picc_desc.idVendor << 16) + picc_desc.idProduct == ACS_ACR85_PINPAD_READER_PICC)) { - DEBUG_CRITICAL("ACR85 PICC not found."); - return STATUS_UNSUCCESSFUL; + dev = picc_dev; + break; } } - else - goto end; + + if (dev == NULL) + { + DEBUG_CRITICAL("ACR85 PICC not found."); + return_value = STATUS_UNSUCCESSFUL; + goto end2; + } } else { - /* if an interface number is given by HAL we - * continue with this device. */ - if (-1 == interface_number) - { - DEBUG_INFO3("USB device %s/%s already in use." - " Checking next one.", - bus->dirname, dev->filename); - continue; - } +#ifndef __APPLE__ + /* This is a multislot reader + * Init the multislot stuff for this next slot */ + usbDevice[reader_index].multislot_extension = Multi_CreateNextSlot(previous_reader_index); +#endif + goto end; } } - - DEBUG_COMM3("Trying to open USB bus/device: %s/%s", - bus->dirname, dev->filename); - - dev_handle = usb_open(dev); - if (dev_handle == NULL) + else { - DEBUG_CRITICAL4("Can't usb_open(%s/%s): %s", - bus->dirname, dev->filename, strerror(errno)); - - continue; + /* if an interface number is given by HAL we + * continue with this device. */ + if (-1 == interface_number) + { + DEBUG_INFO3("USB device %d/%d already in use." + " Checking next one.", + bus_number, device_address); + continue; + } } + } - /* now we found a free reader and we try to use it */ - if (dev->config == NULL) - { - (void)usb_close(dev_handle); - DEBUG_CRITICAL3("No dev->config found for %s/%s", - bus->dirname, dev->filename); - return STATUS_UNSUCCESSFUL; - } + DEBUG_COMM3("Trying to open USB bus/device: %d/%d", + bus_number, device_address); -again: - usb_interface = get_ccid_usb_interface(dev, &num); - if (usb_interface == NULL) - { - (void)usb_close(dev_handle); - if (0 == num) - DEBUG_CRITICAL3("Can't find a CCID interface on %s/%s", - bus->dirname, dev->filename); - interface_number = -1; - continue; - } + r = libusb_open(dev, &dev_handle); + if (r < 0) + { + DEBUG_CRITICAL4("Can't libusb_open(%d/%d): %d", + bus_number, device_address, r); + + continue; + } - if (usb_interface->altsetting->extralen != 54) +again: + r = libusb_get_active_config_descriptor(dev, &config_desc); + if (r < 0) + { +#ifdef __APPLE__ + /* Some early Gemalto Ezio CB+ readers have + * bDeviceClass, bDeviceSubClass and bDeviceProtocol set + * to 0xFF (proprietary) instead of 0x00. + * + * So on Mac OS X the reader configuration is not done + * by the OS/kernel and we do it ourself. + */ + if ((0xFF == desc.bDeviceClass) + && (0xFF == desc.bDeviceSubClass) + && (0xFF == desc.bDeviceProtocol)) { - // These readers do not have altsetting - if ((readerID != ACS_ACR38U) && - (readerID != ACS_ACR38U_SAM) && - (readerID != IRIS_SCR21U) && - (readerID != ACS_AET65_1SAM_ICC_READER) && - (readerID != ACS_CRYPTOMATE) && - (readerID != ACS_ACR88U) && - (readerID != ACS_ACR128U) && - (readerID != ACS_ACR1281_1S_DUAL_READER) && - (readerID != ACS_ACR1281_2S_CL_READER)) + r = libusb_set_configuration(dev_handle, 1); + if (r < 0) { - (void)usb_close(dev_handle); - DEBUG_CRITICAL4("Extra field for %s/%s has a wrong length: %d", bus->dirname, dev->filename, usb_interface->altsetting->extralen); - return STATUS_UNSUCCESSFUL; + (void)libusb_close(dev_handle); + DEBUG_CRITICAL4("Can't set configuration on %d/%d: %d", + bus_number, device_address, r); + continue; } } - interface = usb_interface->altsetting->bInterfaceNumber; - if (interface_number >= 0 && interface != interface_number) + /* recall */ + r = libusb_get_active_config_descriptor(dev, &config_desc); + if (r < 0) { - /* an interface was specified and it is not the - * current one */ - DEBUG_INFO3("Wrong interface for USB device %s/%s." - " Checking next one.", bus->dirname, dev->filename); +#endif + (void)libusb_close(dev_handle); + DEBUG_CRITICAL4("Can't get config descriptor on %d/%d: %d", + bus_number, device_address, r); + continue; + } +#ifdef __APPLE__ + } +#endif - /* check for another CCID interface on the same device */ - num++; - goto again; - } + usb_interface = get_ccid_usb_interface(config_desc, &num); + if (usb_interface == NULL) + { + (void)libusb_close(dev_handle); + if (0 == num) + DEBUG_CRITICAL3("Can't find a CCID interface on %d/%d", + bus_number, device_address); + interface_number = -1; + continue; + } - if (usb_claim_interface(dev_handle, interface) < 0) - { - (void)usb_close(dev_handle); - DEBUG_CRITICAL4("Can't claim interface %s/%s: %s", - bus->dirname, dev->filename, strerror(errno)); - interface_number = -1; - continue; + device_descriptor = get_ccid_device_descriptor(usb_interface); + if (NULL == device_descriptor) + { + // These readers do not have altsetting + if ((readerID != ACS_ACR38U) && + (readerID != ACS_ACR38U_SAM) && + (readerID != IRIS_SCR21U) && + (readerID != ACS_AET65_1SAM_ICC_READER) && + (readerID != ACS_CRYPTOMATE) && + (readerID != ACS_ACR88U) && + (readerID != ACS_ACR128U) && + (readerID != ACS_ACR1281_1S_DUAL_READER) && + (readerID != ACS_ACR1281_2S_CL_READER)) + { + (void)libusb_close(dev_handle); + DEBUG_CRITICAL3("Unable to find the device descriptor for %d/%d", + bus_number, device_address); + return_value = STATUS_UNSUCCESSFUL; + goto end2; } + } - DEBUG_INFO4("Found Vendor/Product: %04X/%04X (%s)", - dev->descriptor.idVendor, - dev->descriptor.idProduct, keyValue); - DEBUG_INFO3("Using USB bus/device: %s/%s", - bus->dirname, dev->filename); + interface = usb_interface->altsetting->bInterfaceNumber; + if (interface_number >= 0 && interface != interface_number) + { + /* an interface was specified and it is not the + * current one */ + DEBUG_INFO3("Found interface %d but expecting %d", + interface_number, interface); + DEBUG_INFO3("Wrong interface for USB device %d/%d." + " Checking next one.", bus_number, device_address); - /* check for firmware bugs */ - if (ccid_check_firmware(dev)) - { - (void)usb_close(dev_handle); - return STATUS_UNSUCCESSFUL; - } + /* check for another CCID interface on the same device */ + num++; -#ifdef USE_COMPOSITE_AS_MULTISLOT - /* use the next interface for the next "slot" */ - static_interface++; + goto again; + } - /* reset for a next reader */ - if (static_interface > 2) - static_interface = 1; -#endif + r = libusb_claim_interface(dev_handle, interface); + if (r < 0) + { + (void)libusb_close(dev_handle); + DEBUG_CRITICAL4("Can't claim interface %d/%d: %d", + bus_number, device_address, r); + claim_failed = TRUE; + interface_number = -1; + continue; + } - /* Get Endpoints values*/ - (void)get_end_points(dev, &usbDevice[reader_index], num); + DEBUG_INFO4("Found Vendor/Product: %04X/%04X (%s)", + desc.idVendor, desc.idProduct, friendlyName); + DEBUG_INFO3("Using USB bus/device: %d/%d", + bus_number, device_address); - /* store device information */ - usbDevice[reader_index].handle = dev_handle; - usbDevice[reader_index].dirname = strdup(bus->dirname); - usbDevice[reader_index].filename = strdup(dev->filename); - usbDevice[reader_index].interface = interface; - usbDevice[reader_index].real_nb_opened_slots = 1; - usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots; - - /* CCID common informations */ - usbDevice[reader_index].ccid.real_bSeq = 0; - usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq; - usbDevice[reader_index].ccid.readerID = - (dev->descriptor.idVendor << 16) + - dev->descriptor.idProduct; + /* check for firmware bugs */ + if (ccid_check_firmware(&desc)) + { + (void)libusb_close(dev_handle); + return_value = STATUS_UNSUCCESSFUL; + goto end2; + } - // Store bcdDevice for firmware version checking - usbDevice[reader_index].ccid.bcdDevice = dev->descriptor.bcdDevice; +#ifdef USE_COMPOSITE_AS_MULTISLOT + /* use the next interface for the next "slot" */ + static_interface++; - // These readers do not have altsetting - if ((readerID == ACS_ACR38U) || (readerID == ACS_CRYPTOMATE)) - { - usbDevice[reader_index].ccid.dwFeatures = 0x00010030; - usbDevice[reader_index].ccid.wLcdLayout = 0; - usbDevice[reader_index].ccid.bPINSupport = 0; - usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; - usbDevice[reader_index].ccid.dwMaxIFSD = 248; - usbDevice[reader_index].ccid.dwDefaultClock = 4000; - usbDevice[reader_index].ccid.dwMaxDataRate = 229390; - usbDevice[reader_index].ccid.bMaxSlotIndex = 0; - usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; - usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; - usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; - usbDevice[reader_index].ccid.bInterfaceProtocol = PROTOCOL_ACR38; - usbDevice[reader_index].ccid.bNumEndpoints = 3; - usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; - usbDevice[reader_index].ccid.bVoltageSupport = 0x07; - } - else if ((readerID == ACS_ACR38U_SAM) || (readerID == IRIS_SCR21U) || - (readerID == ACS_AET65_1SAM_ICC_READER)) - { - usbDevice[reader_index].ccid.dwFeatures = 0x00010030; - usbDevice[reader_index].ccid.wLcdLayout = 0; - usbDevice[reader_index].ccid.bPINSupport = 0; - usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; - usbDevice[reader_index].ccid.dwMaxIFSD = 248; - usbDevice[reader_index].ccid.dwDefaultClock = 4000; - usbDevice[reader_index].ccid.dwMaxDataRate = 229390; + /* reset for a next reader */ + if (static_interface > 2) + static_interface = 1; +#endif + + /* Get Endpoints values*/ + (void)get_end_points(config_desc, &usbDevice[reader_index], num); + + /* store device information */ + usbDevice[reader_index].dev_handle = dev_handle; + usbDevice[reader_index].bus_number = bus_number; + usbDevice[reader_index].device_address = device_address; + usbDevice[reader_index].interface = interface; + usbDevice[reader_index].real_nb_opened_slots = 1; + usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots; + usbDevice[reader_index].polling_transfer = NULL; + + /* CCID common informations */ + usbDevice[reader_index].ccid.real_bSeq = 0; + usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq; + usbDevice[reader_index].ccid.readerID = + (desc.idVendor << 16) + desc.idProduct; + + // These readers do not have altsetting + if ((readerID == ACS_ACR38U) || (readerID == ACS_CRYPTOMATE)) + { + usbDevice[reader_index].ccid.dwFeatures = 0x00010030; + usbDevice[reader_index].ccid.wLcdLayout = 0; + usbDevice[reader_index].ccid.bPINSupport = 0; + usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; + usbDevice[reader_index].ccid.dwMaxIFSD = 248; + usbDevice[reader_index].ccid.dwDefaultClock = 4000; + usbDevice[reader_index].ccid.dwMaxDataRate = 229390; + usbDevice[reader_index].ccid.bMaxSlotIndex = 0; + usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; + usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; + usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; + usbDevice[reader_index].ccid.bInterfaceProtocol = PROTOCOL_ACR38; + usbDevice[reader_index].ccid.bNumEndpoints = 3; + usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; + usbDevice[reader_index].ccid.bVoltageSupport = 0x07; + } + else if ((readerID == ACS_ACR38U_SAM) || (readerID == IRIS_SCR21U) || + (readerID == ACS_AET65_1SAM_ICC_READER)) + { + usbDevice[reader_index].ccid.dwFeatures = 0x00010030; + usbDevice[reader_index].ccid.wLcdLayout = 0; + usbDevice[reader_index].ccid.bPINSupport = 0; + usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; + usbDevice[reader_index].ccid.dwMaxIFSD = 248; + usbDevice[reader_index].ccid.dwDefaultClock = 4000; + usbDevice[reader_index].ccid.dwMaxDataRate = 229390; + usbDevice[reader_index].ccid.bMaxSlotIndex = 1; + usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; + usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; + usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; + usbDevice[reader_index].ccid.bInterfaceProtocol = PROTOCOL_ACR38; + usbDevice[reader_index].ccid.bNumEndpoints = 3; + usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; + usbDevice[reader_index].ccid.bVoltageSupport = 0x07; + } + else if (readerID == ACS_ACR88U) + { + usbDevice[reader_index].ccid.dwFeatures = 0x000204BA; + usbDevice[reader_index].ccid.wLcdLayout = 0x0815; + usbDevice[reader_index].ccid.bPINSupport = 0x03; + usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; + usbDevice[reader_index].ccid.dwMaxIFSD = 248; + usbDevice[reader_index].ccid.dwDefaultClock = 3600; + usbDevice[reader_index].ccid.dwMaxDataRate = 116129; + usbDevice[reader_index].ccid.bMaxSlotIndex = 4; + usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; + usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; + usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; + usbDevice[reader_index].ccid.bInterfaceProtocol = 0; + usbDevice[reader_index].ccid.bNumEndpoints = 3; + usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; + usbDevice[reader_index].ccid.bVoltageSupport = 0x03; + } + else if (readerID == ACS_ACR128U) + { + usbDevice[reader_index].ccid.dwFeatures = 0x000204BA; + usbDevice[reader_index].ccid.wLcdLayout = 0; + usbDevice[reader_index].ccid.bPINSupport = 0; + usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; + usbDevice[reader_index].ccid.dwMaxIFSD = 248; + usbDevice[reader_index].ccid.dwDefaultClock = 3600; + usbDevice[reader_index].ccid.dwMaxDataRate = 116129; + usbDevice[reader_index].ccid.bMaxSlotIndex = 2; + usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; + usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; + usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; + usbDevice[reader_index].ccid.bInterfaceProtocol = 0; + usbDevice[reader_index].ccid.bNumEndpoints = 3; + usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; + usbDevice[reader_index].ccid.bVoltageSupport = 0x03; + } + else if ((readerID == ACS_ACR1251_1S_DUAL_READER) || + (readerID == ACS_ACR1261_1S_DUAL_READER) || + (readerID == ACS_ACR1281_1S_DUAL_READER) || + (readerID == ACS_ACR1281_2S_CL_READER)) + { + usbDevice[reader_index].ccid.dwFeatures = 0x000204BA; + usbDevice[reader_index].ccid.wLcdLayout = 0; + usbDevice[reader_index].ccid.bPINSupport = 0; + usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; + usbDevice[reader_index].ccid.dwMaxIFSD = 248; + usbDevice[reader_index].ccid.dwDefaultClock = 4000; + usbDevice[reader_index].ccid.dwMaxDataRate = 344100; + usbDevice[reader_index].ccid.bMaxSlotIndex = 2; + usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; + usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; + usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; + usbDevice[reader_index].ccid.bInterfaceProtocol = 0; + usbDevice[reader_index].ccid.bNumEndpoints = 3; + usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; + usbDevice[reader_index].ccid.bVoltageSupport = 0x03; + } + else + { + usbDevice[reader_index].ccid.dwFeatures = dw2i(device_descriptor, 40); + usbDevice[reader_index].ccid.wLcdLayout = + (device_descriptor[51] << 8) + device_descriptor[50]; + usbDevice[reader_index].ccid.bPINSupport = device_descriptor[52]; + usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(device_descriptor, 44); + usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(device_descriptor, 28); + usbDevice[reader_index].ccid.dwDefaultClock = dw2i(device_descriptor, 10); + usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(device_descriptor, 23); + + // Fix ACR1222 incorrect max slot index + if ((readerID == ACS_ACR1222_1SAM_PICC_READER) || + (readerID == ACS_ACR1222_DUAL_READER)) usbDevice[reader_index].ccid.bMaxSlotIndex = 1; - usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; - usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; - usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; - usbDevice[reader_index].ccid.bInterfaceProtocol = PROTOCOL_ACR38; - usbDevice[reader_index].ccid.bNumEndpoints = 3; - usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; - usbDevice[reader_index].ccid.bVoltageSupport = 0x07; - } - else if (readerID == ACS_ACR88U) - { - usbDevice[reader_index].ccid.dwFeatures = 0x000204BA; - usbDevice[reader_index].ccid.wLcdLayout = 0x0815; - usbDevice[reader_index].ccid.bPINSupport = 0x03; - usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; - usbDevice[reader_index].ccid.dwMaxIFSD = 248; - usbDevice[reader_index].ccid.dwDefaultClock = 3600; - usbDevice[reader_index].ccid.dwMaxDataRate = 116129; - usbDevice[reader_index].ccid.bMaxSlotIndex = 4; - usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; - usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; - usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; - usbDevice[reader_index].ccid.bInterfaceProtocol = 0; - usbDevice[reader_index].ccid.bNumEndpoints = 3; - usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; - usbDevice[reader_index].ccid.bVoltageSupport = 0x03; - } - else if (readerID == ACS_ACR128U) - { - usbDevice[reader_index].ccid.dwFeatures = 0x000204BA; - usbDevice[reader_index].ccid.wLcdLayout = 0; - usbDevice[reader_index].ccid.bPINSupport = 0; - usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; - usbDevice[reader_index].ccid.dwMaxIFSD = 248; - usbDevice[reader_index].ccid.dwDefaultClock = 3600; - usbDevice[reader_index].ccid.dwMaxDataRate = 116129; + else if (readerID == ACS_ACR1222_1SAM_DUAL_READER) usbDevice[reader_index].ccid.bMaxSlotIndex = 2; - usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; - usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; - usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; - usbDevice[reader_index].ccid.bInterfaceProtocol = 0; - usbDevice[reader_index].ccid.bNumEndpoints = 3; - usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; - usbDevice[reader_index].ccid.bVoltageSupport = 0x03; - } - else if ((readerID == ACS_ACR1251_1S_DUAL_READER) || - (readerID == ACS_ACR1261_1S_DUAL_READER) || - (readerID == ACS_ACR1281_1S_DUAL_READER) || - (readerID == ACS_ACR1281_2S_CL_READER)) + // Fix ACR32 incorrect max slot index + else if (readerID == ACS_ACR32_ICC_READER) + usbDevice[reader_index].ccid.bMaxSlotIndex = 0; + else + usbDevice[reader_index].ccid.bMaxSlotIndex = device_descriptor[4]; + + usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; + usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; + if (device_descriptor[27]) + usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, config_desc, num); + else { - usbDevice[reader_index].ccid.dwFeatures = 0x000204BA; - usbDevice[reader_index].ccid.wLcdLayout = 0; - usbDevice[reader_index].ccid.bPINSupport = 0; - usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271; - usbDevice[reader_index].ccid.dwMaxIFSD = 248; - usbDevice[reader_index].ccid.dwDefaultClock = 4000; - usbDevice[reader_index].ccid.dwMaxDataRate = 344100; - usbDevice[reader_index].ccid.bMaxSlotIndex = 2; - usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; - usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; - usbDevice[reader_index].ccid.bInterfaceProtocol = 0; - usbDevice[reader_index].ccid.bNumEndpoints = 3; - usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; - usbDevice[reader_index].ccid.bVoltageSupport = 0x03; + DEBUG_INFO1("bNumDataRatesSupported is 0"); } - else - { - usbDevice[reader_index].ccid.dwFeatures = dw2i(usb_interface->altsetting->extra, 40); - usbDevice[reader_index].ccid.wLcdLayout = - (usb_interface->altsetting->extra[51] << 8) + - usb_interface->altsetting->extra[50]; - usbDevice[reader_index].ccid.bPINSupport = usb_interface->altsetting->extra[52]; - usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(usb_interface->altsetting->extra, 44); - usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(usb_interface->altsetting->extra, 28); - usbDevice[reader_index].ccid.dwDefaultClock = dw2i(usb_interface->altsetting->extra, 10); - usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(usb_interface->altsetting->extra, 23); - - // Fix ACR1222 incorrect max slot index - if ((readerID == ACS_ACR1222_1SAM_PICC_READER) || - (readerID == ACS_ACR1222_DUAL_READER)) - usbDevice[reader_index].ccid.bMaxSlotIndex = 1; - else if (readerID == ACS_ACR1222_1SAM_DUAL_READER) - usbDevice[reader_index].ccid.bMaxSlotIndex = 2; - // Simulate ACR85 as multi-slot reader - else if (readerID == ACS_ACR85_PINPAD_READER_ICC) - usbDevice[reader_index].ccid.bMaxSlotIndex = 1; - // Fix ACR32 incorrect max slot index - else if (readerID == ACS_ACR32_ICC_READER) - usbDevice[reader_index].ccid.bMaxSlotIndex = 0; - else - usbDevice[reader_index].ccid.bMaxSlotIndex = usb_interface->altsetting->extra[4]; + usbDevice[reader_index].ccid.bInterfaceProtocol = usb_interface->altsetting->bInterfaceProtocol; + usbDevice[reader_index].ccid.bNumEndpoints = usb_interface->altsetting->bNumEndpoints; + usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; + usbDevice[reader_index].ccid.bVoltageSupport = device_descriptor[5]; + } - usbDevice[reader_index].ccid.bCurrentSlotIndex = 0; - usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT; + usbDevice[reader_index].ccid.sIFD_serial_number = NULL; + usbDevice[reader_index].ccid.gemalto_firmware_features = NULL; + usbDevice[reader_index].ccid.zlp = FALSE; + if (desc.iSerialNumber) + { + unsigned char serial[128]; + int ret; - if (usb_interface->altsetting->extra[27] == 0) - usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; - else - usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, dev, num); + ret = libusb_get_string_descriptor_ascii(dev_handle, + desc.iSerialNumber, serial, + sizeof(serial)); + if (ret > 0) + usbDevice[reader_index].ccid.sIFD_serial_number + = strdup((char *)serial); + } - usbDevice[reader_index].ccid.bInterfaceProtocol = usb_interface->altsetting->bInterfaceProtocol; - usbDevice[reader_index].ccid.bNumEndpoints = usb_interface->altsetting->bNumEndpoints; - usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT; - usbDevice[reader_index].ccid.bVoltageSupport = usb_interface->altsetting->extra[5]; - } + usbDevice[reader_index].ccid.sIFD_iManufacturer = NULL; + if (desc.iManufacturer) + { + unsigned char iManufacturer[128]; + int ret; - // Get number of slots - numSlots = usbDevice[reader_index].ccid.bMaxSlotIndex + 1; + ret = libusb_get_string_descriptor_ascii(dev_handle, + desc.iManufacturer, iManufacturer, + sizeof(iManufacturer)); + if (ret > 0) + usbDevice[reader_index].ccid.sIFD_iManufacturer + = strdup((char *)iManufacturer); + } - // Allocate array of bStatus - usbDevice[reader_index].ccid.bStatus = (unsigned char *) calloc(numSlots, sizeof(unsigned char)); - if (usbDevice[reader_index].ccid.bStatus == NULL) - { - usb_close(dev_handle); - DEBUG_CRITICAL("Not enough memory"); - return STATUS_UNSUCCESSFUL; - } + usbDevice[reader_index].ccid.IFD_bcdDevice = desc.bcdDevice; +#ifndef __APPLE__ + /* If this is a multislot reader, init the multislot stuff */ + if (usbDevice[reader_index].ccid.bMaxSlotIndex) + usbDevice[reader_index].multislot_extension = Multi_CreateFirstSlot(reader_index); + else +#endif + usbDevice[reader_index].multislot_extension = NULL; + + // Get number of slots + numSlots = usbDevice[reader_index].ccid.bMaxSlotIndex + 1; + + // Allocate array of bStatus + usbDevice[reader_index].ccid.bStatus = (unsigned char *) calloc(numSlots, sizeof(unsigned char)); + if (usbDevice[reader_index].ccid.bStatus == NULL) + { + (void)libusb_close(dev_handle); + DEBUG_CRITICAL("Not enough memory"); + return_value = STATUS_UNSUCCESSFUL; + goto end2; + } - // Initialize array of bStatus - memset(usbDevice[reader_index].ccid.bStatus, 0xFF, numSlots * sizeof(unsigned char)); + // Initialize array of bStatus + memset(usbDevice[reader_index].ccid.bStatus, 0xFF, numSlots * sizeof(unsigned char)); - // Initialize firmware fix enabled - usbDevice[reader_index].ccid.firmwareFixEnabled = FALSE; + // Initialize firmware fix enabled + usbDevice[reader_index].ccid.firmwareFixEnabled = FALSE; - // Simulate ACR85 as multi-slot reader - if (readerID != ACS_ACR85_PINPAD_READER_PICC) - { - // Initialize PICC enabled - usbDevice[reader_index].ccid.piccEnabled = TRUE; - usbDevice[reader_index].ccid.pPiccEnabled = &usbDevice[reader_index].ccid.piccEnabled; - - // Initialize PICC reader index - usbDevice[reader_index].ccid.piccReaderIndex = -1; - usbDevice[reader_index].ccid.pPiccReaderIndex = &usbDevice[reader_index].ccid.piccReaderIndex; - } + // Simulate ACR85 as multi-slot reader + if (readerID == ACS_ACR85_PINPAD_READER_ICC) + usbDevice[reader_index].ccid.bMaxSlotIndex = 1; - // Initialize card voltage (ACR38U, ACR38U-SAM and SCR21U) - usbDevice[reader_index].ccid.cardVoltage = 0; + // Simulate ACR85 as multi-slot reader + if (readerID != ACS_ACR85_PINPAD_READER_PICC) + { + // Initialize PICC enabled + usbDevice[reader_index].ccid.piccEnabled = TRUE; + usbDevice[reader_index].ccid.pPiccEnabled = &usbDevice[reader_index].ccid.piccEnabled; + + // Initialize PICC reader index + usbDevice[reader_index].ccid.piccReaderIndex = -1; + usbDevice[reader_index].ccid.pPiccReaderIndex = &usbDevice[reader_index].ccid.piccReaderIndex; + } - // Initialize card type (ACR38U, ACR38U-SAM and SCR21U) - usbDevice[reader_index].ccid.cardType = 0; + // Initialize card voltage (ACR38U, ACR38U-SAM and SCR21U) + usbDevice[reader_index].ccid.cardVoltage = 0; - // Initialize isSamSlot - usbDevice[reader_index].ccid.isSamSlot = FALSE; + // Initialize card type (ACR38U, ACR38U-SAM and SCR21U) + usbDevice[reader_index].ccid.cardType = 0; - // The 2nd interface (composite device) is a SAM slot - if ((readerID == ACS_ACR1281_1S_PICC_READER) || - (readerID == ACS_ACR1251_1S_CL_READER) || - (readerID == ACS_ACR1251U_C) || - (readerID == ACS_ACR1252_1S_CL_READER)) - { - if (interface == 1) - usbDevice[reader_index].ccid.isSamSlot = TRUE; - } -#ifdef __APPLE__ - // Initialize terminated flag to false - usbDevice[reader_index].terminated = FALSE; - usbDevice[reader_index].pTerminated = &usbDevice[reader_index].terminated; - usbDevice[reader_index].ccid.pbStatusLock = &usbDevice[reader_index].ccid.bStatusLock; - - // Create bStatus lock - ret = pthread_mutex_init(usbDevice[reader_index].ccid.pbStatusLock, NULL); - if (ret != 0) - { - free(usbDevice[reader_index].ccid.bStatus); - usb_close(dev_handle); - DEBUG_CRITICAL2("pthread_mutex_init failed with error %d", ret); - return STATUS_UNSUCCESSFUL; - } + // Initialize isSamSlot + usbDevice[reader_index].ccid.isSamSlot = FALSE; - // Create thread for card detection - ret = pthread_create(&usbDevice[reader_index].hThread, NULL, CardDetectionThread, &reader_index); - if (ret != 0) - { - pthread_mutex_destroy(usbDevice[reader_index].ccid.pbStatusLock); - free(usbDevice[reader_index].ccid.bStatus); - usb_close(dev_handle); - DEBUG_CRITICAL2("pthread_create failed with error %d", ret); - return STATUS_UNSUCCESSFUL; - } -#endif - goto end; + // The 2nd interface (composite device) is a SAM slot + if ((readerID == ACS_ACR1281_1S_PICC_READER) || + (readerID == ACS_ACR1251_1S_CL_READER) || + (readerID == ACS_ACR1251U_C) || + (readerID == ACS_ACR1252_1S_CL_READER)) + { + if (interface == 1) + usbDevice[reader_index].ccid.isSamSlot = TRUE; } - } +#ifdef __APPLE__ + // Initialize terminated flag to false + usbDevice[reader_index].terminated = FALSE; + usbDevice[reader_index].pTerminated = &usbDevice[reader_index].terminated; + usbDevice[reader_index].pTransfer = &usbDevice[reader_index].polling_transfer; + usbDevice[reader_index].pTransferLock = &usbDevice[reader_index].transferLock; + usbDevice[reader_index].ccid.pbStatusLock = &usbDevice[reader_index].ccid.bStatusLock; + + // Create transfer lock + r = pthread_mutex_init(usbDevice[reader_index].pTransferLock, NULL); + if (r != 0) + { + (void)libusb_close(dev_handle); + DEBUG_CRITICAL2("pthread_mutex_init failed with error %d", r); + return_value = STATUS_UNSUCCESSFUL; + goto end2; + } + + // Create bStatus lock + r = pthread_mutex_init(usbDevice[reader_index].ccid.pbStatusLock, NULL); + if (r != 0) + { + pthread_mutex_destroy(usbDevice[reader_index].pTransferLock); + free(usbDevice[reader_index].ccid.bStatus); + + (void)libusb_close(dev_handle); + DEBUG_CRITICAL2("pthread_mutex_init failed with error %d", r); + return_value = STATUS_UNSUCCESSFUL; + goto end2; + } + + // Create thread for card detection + r = pthread_create(&usbDevice[reader_index].hThread, NULL, CardDetectionThread, &reader_index); + if (r != 0) + { + pthread_mutex_destroy(usbDevice[reader_index].pTransferLock); + pthread_mutex_destroy(usbDevice[reader_index].ccid.pbStatusLock); + free(usbDevice[reader_index].ccid.bStatus); + + (void)libusb_close(dev_handle); + DEBUG_CRITICAL2("pthread_create failed with error %d", r); + return_value = STATUS_UNSUCCESSFUL; + goto end2; + } +#endif + goto end; + } } } end: - if (usbDevice[reader_index].handle == NULL) + if (usbDevice[reader_index].dev_handle == NULL) + { + close_libusb_if_needed(); + if (claim_failed) + return STATUS_COMM_ERROR; + DEBUG_INFO1("Device not found?"); return STATUS_NO_SUCH_DEVICE; + } /* memorise the current reader_index so we can detect * a new OpenUSBByName on a multi slot reader */ previous_reader_index = reader_index; - return STATUS_SUCCESS; +end2: + /* free the libusb allocated list & devices */ + libusb_free_device_list(devs, 1); + +end1: + /* free bundle list */ + bundleRelease(&plist); + + return return_value; } /* OpenUSBByName */ @@ -927,6 +1032,7 @@ unsigned char *buffer) { int rv; + int actual_length; char debug_header[] = "-> 121234 "; int pos; int len; @@ -935,7 +1041,15 @@ (void)snprintf(debug_header, sizeof(debug_header), "-> %06X ", (int)reader_index); - DEBUG_XXD(debug_header, buffer, length); + if (usbDevice[reader_index].ccid.zlp) + { /* Zero Length Packet */ + int dummy_length; + + /* try to read a ZLP so transfer length = 0 + * timeout of 1 ms */ + (void)libusb_bulk_transfer(usbDevice[reader_index].dev_handle, + usbDevice[reader_index].bulk_in, NULL, 0, &dummy_length, 1); + } // Fix APG8201 and ACR85 ICC cannot receive command properly // Add delay for APG8201 and ACR85 ICC @@ -954,17 +1068,19 @@ else len = length; - rv = usb_bulk_write(usbDevice[reader_index].handle, - usbDevice[reader_index].bulk_out, (char *)buffer + pos, len, - USB_WRITE_TIMEOUT); + DEBUG_XXD(debug_header, buffer + pos, len); + + rv = libusb_bulk_transfer(usbDevice[reader_index].dev_handle, + usbDevice[reader_index].bulk_out, buffer + pos, len, + &actual_length, USB_WRITE_TIMEOUT); if (rv < 0) { - DEBUG_CRITICAL4("usb_bulk_write(%s/%s): %s", - usbDevice[reader_index].dirname, usbDevice[reader_index].filename, - strerror(errno)); + DEBUG_CRITICAL5("write failed (%d/%d): %d %s", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address, rv, strerror(errno)); - if (ENODEV == errno) + if ((ENODEV == errno) || (LIBUSB_ERROR_NO_DEVICE == rv)) return STATUS_NO_SUCH_DEVICE; return STATUS_UNSUCCESSFUL; @@ -994,55 +1110,49 @@ unsigned char *buffer) { int rv; + int actual_length; char debug_header[] = "<- 121234 "; _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); int duplicate_frame = 0; - unsigned char epBuffer[64]; - int responseReceived; - int headerReceived; - unsigned int bufferLen; - unsigned int readLen; - unsigned int dataLen; - unsigned int tempLen; - (void)snprintf(debug_header, sizeof(debug_header), "<- %06X ", (int)reader_index); if (ccid_descriptor->bInterfaceProtocol == PROTOCOL_ACR38) { - responseReceived = FALSE; - headerReceived = FALSE; - bufferLen = *length; - readLen = 0; - dataLen = 0; - tempLen = 0; + unsigned char epBuffer[64]; + int responseReceived = FALSE; + int headerReceived = FALSE; + unsigned int bufferLen = *length; + unsigned int readLen = 0; + unsigned int dataLen = 0; while (!responseReceived) { // Read data from BULK IN endpoint - rv = usb_bulk_read(usbDevice[reader_index].handle, - usbDevice[reader_index].bulk_in, (char *) epBuffer, sizeof(epBuffer), - usbDevice[reader_index].ccid.readTimeout * 1000); + rv = libusb_bulk_transfer(usbDevice[reader_index].dev_handle, + usbDevice[reader_index].bulk_in, epBuffer, sizeof(epBuffer), + &actual_length, usbDevice[reader_index].ccid.readTimeout); + if (rv < 0) { *length = 0; - DEBUG_CRITICAL4("usb_bulk_read(%s/%s): %s", - usbDevice[reader_index].dirname, usbDevice[reader_index].filename, - strerror(errno)); + DEBUG_CRITICAL5("read failed (%d/%d): %d %s", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address, rv, strerror(errno)); - if (ENODEV == errno) + if ((ENODEV == errno) || (LIBUSB_ERROR_NO_DEVICE == rv)) return STATUS_NO_SUCH_DEVICE; return STATUS_UNSUCCESSFUL; } - DEBUG_XXD(debug_header, epBuffer, rv); + DEBUG_XXD(debug_header, epBuffer, actual_length); // Copy data to buffer - if (readLen + rv <= bufferLen) - memcpy(buffer + readLen, epBuffer, rv); - readLen += rv; + if (readLen + actual_length <= bufferLen) + memcpy(buffer + readLen, epBuffer, actual_length); + readLen += actual_length; if (!headerReceived) { @@ -1074,44 +1184,44 @@ DEBUG_CRITICAL("Insufficient buffer"); return STATUS_UNSUCCESSFUL; } + + return STATUS_SUCCESS; } - else - { - read_again: - rv = usb_bulk_read(usbDevice[reader_index].handle, - usbDevice[reader_index].bulk_in, (char *)buffer, *length, - usbDevice[reader_index].ccid.readTimeout * 1000); - if (rv < 0) - { - *length = 0; - DEBUG_CRITICAL4("usb_bulk_read(%s/%s): %s", - usbDevice[reader_index].dirname, usbDevice[reader_index].filename, - strerror(errno)); +read_again: + rv = libusb_bulk_transfer(usbDevice[reader_index].dev_handle, + usbDevice[reader_index].bulk_in, buffer, *length, + &actual_length, usbDevice[reader_index].ccid.readTimeout); - if (ENODEV == errno) - return STATUS_NO_SUCH_DEVICE; + if (rv < 0) + { + *length = 0; + DEBUG_CRITICAL5("read failed (%d/%d): %d %s", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address, rv, strerror(errno)); - return STATUS_UNSUCCESSFUL; - } + if ((ENODEV == errno) || (LIBUSB_ERROR_NO_DEVICE == rv)) + return STATUS_NO_SUCH_DEVICE; - *length = rv; + return STATUS_UNSUCCESSFUL; + } - DEBUG_XXD(debug_header, buffer, *length); + *length = actual_length; + + DEBUG_XXD(debug_header, buffer, *length); #define BSEQ_OFFSET 6 - if ((*length >= BSEQ_OFFSET) - && (buffer[BSEQ_OFFSET] < *ccid_descriptor->pbSeq -1)) + if ((*length >= BSEQ_OFFSET) + && (buffer[BSEQ_OFFSET] < *ccid_descriptor->pbSeq -1)) + { + duplicate_frame++; + if (duplicate_frame > 10) { - duplicate_frame++; - if (duplicate_frame > 10) - { - DEBUG_CRITICAL("Too many duplicate frame detected"); - return STATUS_UNSUCCESSFUL; - } - DEBUG_INFO("Duplicate frame detected"); - goto read_again; + DEBUG_CRITICAL("Too many duplicate frame detected"); + return STATUS_UNSUCCESSFUL; } + DEBUG_INFO1("Duplicate frame detected"); + goto read_again; } return STATUS_SUCCESS; @@ -1126,19 +1236,12 @@ status_t CloseUSB(unsigned int reader_index) { /* device not opened */ - if (usbDevice[reader_index].handle == NULL) + if (usbDevice[reader_index].dev_handle == NULL) return STATUS_UNSUCCESSFUL; - DEBUG_COMM3("Closing USB device: %s/%s", - usbDevice[reader_index].dirname, - usbDevice[reader_index].filename); - - if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates - && (usbDevice[reader_index].ccid.bCurrentSlotIndex == 0)) - { - free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates); - usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL; - } + DEBUG_COMM3("Closing USB device: %d/%d", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address); /* one slot closed */ (*usbDevice[reader_index].nb_opened_slots)--; @@ -1146,50 +1249,90 @@ /* release the allocated ressources for the last slot only */ if (0 == *usbDevice[reader_index].nb_opened_slots) { -#ifdef __APPLE__ - struct darwin_dev_handle *device; - int pipeRef; -#endif + struct usbDevice_MultiSlot_Extension *msExt; + DEBUG_COMM("Last slot closed. Release resources"); - /* reset so that bSeq starts at 0 again */ - if (DriverOptions & DRIVER_OPTION_RESET_ON_CLOSE) - (void)usb_reset(usbDevice[reader_index].handle); #ifdef __APPLE__ - DEBUG_INFO3("Terminating thread: %s/%s", - usbDevice[reader_index].dirname, usbDevice[reader_index].filename); + DEBUG_INFO3("Terminating thread: %d/%d", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address); // Terminate thread *usbDevice[reader_index].pTerminated = TRUE; - // Abort interrupt pipe - device = (struct darwin_dev_handle *) usbDevice[reader_index].handle->impl_info; - pipeRef = GetPipeRef(device, usbDevice[reader_index].interrupt); - (*(device->interface))->AbortPipe(device->interface, pipeRef); + // Lock transfer + pthread_mutex_lock(usbDevice[reader_index].pTransferLock); + + // Cancel transfer + if (*usbDevice[reader_index].pTransfer != NULL) + { + libusb_cancel_transfer(*usbDevice[reader_index].pTransfer); + *usbDevice[reader_index].pTransfer = NULL; + } + + // Unlock transfer + pthread_mutex_unlock(usbDevice[reader_index].pTransferLock); // Wait thread pthread_join(usbDevice[reader_index].hThread, NULL); // Free bStatus lock pthread_mutex_destroy(usbDevice[reader_index].ccid.pbStatusLock); -#endif - (void)usb_release_interface(usbDevice[reader_index].handle, - usbDevice[reader_index].interface); - (void)usb_close(usbDevice[reader_index].handle); + // Free transfer lock + pthread_mutex_destroy(usbDevice[reader_index].pTransferLock); +#endif // Free array of bStatus free(usbDevice[reader_index].ccid.bStatus); - free(usbDevice[reader_index].dirname); - free(usbDevice[reader_index].filename); + msExt = usbDevice[reader_index].multislot_extension; + /* If this is a multislot reader, close using the multislot stuff */ + if (msExt) + { + /* terminate the interrupt waiter thread */ + Multi_PollingTerminate(msExt); + + /* wait for the thread to actually terminate */ + pthread_join(msExt->thread_proc, NULL); + + /* release the shared objects */ + pthread_cond_destroy(&msExt->condition); + pthread_mutex_destroy(&msExt->mutex); + + /* Deallocate the extension itself */ + free(msExt); + + /* Stop the slot */ + usbDevice[reader_index].multislot_extension = NULL; + } + + if (usbDevice[reader_index].ccid.gemalto_firmware_features) + free(usbDevice[reader_index].ccid.gemalto_firmware_features); + + if (usbDevice[reader_index].ccid.sIFD_serial_number) + free(usbDevice[reader_index].ccid.sIFD_serial_number); + + if (usbDevice[reader_index].ccid.sIFD_iManufacturer) + free(usbDevice[reader_index].ccid.sIFD_iManufacturer); + + /* reset so that bSeq starts at 0 again */ + if (DriverOptions & DRIVER_OPTION_RESET_ON_CLOSE) + (void)libusb_reset_device(usbDevice[reader_index].dev_handle); + + if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates) + free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates); + + (void)libusb_release_interface(usbDevice[reader_index].dev_handle, + usbDevice[reader_index].interface); + (void)libusb_close(usbDevice[reader_index].dev_handle); } /* mark the resource unused */ - usbDevice[reader_index].handle = NULL; - usbDevice[reader_index].dirname = NULL; - usbDevice[reader_index].filename = NULL; + usbDevice[reader_index].dev_handle = NULL; usbDevice[reader_index].interface = 0; usbDevice[reader_index].ccid.bStatus = NULL; // Array of bStatus + close_libusb_if_needed(); return STATUS_SUCCESS; } /* CloseUSB */ @@ -1208,15 +1351,59 @@ /***************************************************************************** * + * get_ccid_device_descriptor + * + ****************************************************************************/ +const unsigned char *get_ccid_device_descriptor(const struct libusb_interface *usb_interface) +{ +#ifdef O2MICRO_OZ776_PATCH + uint8_t last_endpoint; +#endif + + if (54 == usb_interface->altsetting->extra_length) + return usb_interface->altsetting->extra; + + if (0 != usb_interface->altsetting->extra_length) + { + /* If extra_length is zero, the descriptor might be at + * the end, but if it's not zero, we have a + * problem. */ + DEBUG_CRITICAL2("Extra field has a wrong length: %d", + usb_interface->altsetting->extra_length); + return NULL; + } + +#ifdef O2MICRO_OZ776_PATCH + /* Some devices, such as the Oz776, Reiner SCT and bludrive II + * report the device descriptor at the end of the endpoint + * descriptors; to support those, look for it at the end as well. + */ + last_endpoint = usb_interface->altsetting->bNumEndpoints-1; + if (usb_interface->altsetting->endpoint + && usb_interface->altsetting->endpoint[last_endpoint].extra_length == 54) + return usb_interface->altsetting->endpoint[last_endpoint].extra; +#else + DEBUG_CRITICAL2("Extra field has a wrong length: %d", + usb_interface->altsetting->extra_length); +#endif + + return NULL; +} /* get_ccid_device_descriptor */ + + +/***************************************************************************** + * * get_end_points * ****************************************************************************/ -static int get_end_points(struct usb_device *dev, _usbDevice *usbdevice, - int num) +static int get_end_points(struct libusb_config_descriptor *desc, + _usbDevice *usbdevice, int num) { int i; int bEndpointAddress; - struct usb_interface *usb_interface = get_ccid_usb_interface(dev, &num); + const struct libusb_interface *usb_interface; + + usb_interface = get_ccid_usb_interface(desc, &num); /* * 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out @@ -1224,21 +1411,27 @@ for (i=0; ialtsetting->bNumEndpoints; i++) { /* interrupt end point (if available) */ - if (usb_interface->altsetting->endpoint[i].bmAttributes == USB_ENDPOINT_TYPE_INTERRUPT) + if (usb_interface->altsetting->endpoint[i].bmAttributes + == LIBUSB_TRANSFER_TYPE_INTERRUPT) { - usbdevice->interrupt = usb_interface->altsetting->endpoint[i].bEndpointAddress; + usbdevice->interrupt = + usb_interface->altsetting->endpoint[i].bEndpointAddress; continue; } - if (usb_interface->altsetting->endpoint[i].bmAttributes != USB_ENDPOINT_TYPE_BULK) + if (usb_interface->altsetting->endpoint[i].bmAttributes + != LIBUSB_TRANSFER_TYPE_BULK) continue; - bEndpointAddress = usb_interface->altsetting->endpoint[i].bEndpointAddress; + bEndpointAddress = + usb_interface->altsetting->endpoint[i].bEndpointAddress; - if ((bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) + if ((bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) + == LIBUSB_ENDPOINT_IN) usbdevice->bulk_in = bEndpointAddress; - if ((bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) + if ((bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) + == LIBUSB_ENDPOINT_OUT) { usbdevice->bulk_out = bEndpointAddress; usbdevice->bulkOutMaxPacketSize = usb_interface->altsetting->endpoint[i].wMaxPacketSize; @@ -1254,61 +1447,32 @@ * get_ccid_usb_interface * ****************************************************************************/ -/*@null@*/ EXTERNAL struct usb_interface * get_ccid_usb_interface( - struct usb_device *dev, int *num) +/*@null@*/ EXTERNAL const struct libusb_interface * get_ccid_usb_interface( + struct libusb_config_descriptor *desc, int *num) { - struct usb_interface *usb_interface = NULL; + const struct libusb_interface *usb_interface = NULL; int i; -#ifdef O2MICRO_OZ776_PATCH - int readerID; -#endif /* if multiple interfaces use the first one with CCID class type */ - for (i = *num; dev->config && iconfig->bNumInterfaces; i++) + for (i = *num; i < desc->bNumInterfaces; i++) { /* CCID Class? */ - if (dev->config->interface[i].altsetting->bInterfaceClass == 0xb + if (desc->interface[i].altsetting->bInterfaceClass == 0xb #ifdef ALLOW_PROPRIETARY_CLASS - || dev->config->interface[i].altsetting->bInterfaceClass == 0xff + || desc->interface[i].altsetting->bInterfaceClass == 0xff // bInterfaceClass is 0x00 in ACR83U, ACR88U and ACR128U - || dev->config->interface[i].altsetting->bInterfaceClass == 0x00 + || desc->interface[i].altsetting->bInterfaceClass == 0x00 #endif ) { - usb_interface = &dev->config->interface[i]; + usb_interface = &desc->interface[i]; /* store the interface number for further reference */ *num = i; break; } } -#ifdef O2MICRO_OZ776_PATCH - readerID = (dev->descriptor.idVendor << 16) + dev->descriptor.idProduct; - if (usb_interface != NULL - && ((OZ776 == readerID) || (OZ776_7772 == readerID) - || (REINER_SCT == readerID) || (BLUDRIVEII_CCID == readerID)) - && (0 == usb_interface->altsetting->extralen)) /* this is the bug */ - { - int j; - for (j=0; jaltsetting->bNumEndpoints; j++) - { - /* find the extra[] array */ - if (54 == usb_interface->altsetting->endpoint[j].extralen) - { - /* get the extra[] from the endpoint */ - usb_interface->altsetting->extralen = 54; - usb_interface->altsetting->extra = - usb_interface->altsetting->endpoint[j].extra; - /* avoid double free on close */ - usb_interface->altsetting->endpoint[j].extra = NULL; - usb_interface->altsetting->endpoint[j].extralen = 0; - break; - } - } - } -#endif - return usb_interface; } /* get_ccid_usb_interface */ @@ -1318,33 +1482,31 @@ * ccid_check_firmware * ****************************************************************************/ -int ccid_check_firmware(struct usb_device *dev) +int ccid_check_firmware(struct libusb_device_descriptor *desc) { unsigned int i; - for (i=0; idescriptor.idVendor != Bogus_firmwares[i].vendor) + if (desc->idVendor != Bogus_firmwares[i].vendor) continue; - if (dev->descriptor.idProduct != Bogus_firmwares[i].product) + if (desc->idProduct != Bogus_firmwares[i].product) continue; /* firmware too old and buggy */ - if (dev->descriptor.bcdDevice < Bogus_firmwares[i].firmware) + if (desc->bcdDevice < Bogus_firmwares[i].firmware) { if (DriverOptions & DRIVER_OPTION_USE_BOGUS_FIRMWARE) { DEBUG_INFO3("Firmware (%X.%02X) is bogus! but you choosed to use it", - dev->descriptor.bcdDevice >> 8, - dev->descriptor.bcdDevice & 0xFF); + desc->bcdDevice >> 8, desc->bcdDevice & 0xFF); return FALSE; } else { DEBUG_CRITICAL3("Firmware (%X.%02X) is bogus! Upgrade the reader firmware or get a new reader.", - dev->descriptor.bcdDevice >> 8, - dev->descriptor.bcdDevice & 0xFF); + desc->bcdDevice >> 8, desc->bcdDevice & 0xFF); return TRUE; } } @@ -1357,15 +1519,15 @@ /***************************************************************************** * - * get_data_rates + * get_data_rates * ****************************************************************************/ static unsigned int *get_data_rates(unsigned int reader_index, - struct usb_device *dev, int num) + struct libusb_config_descriptor *desc, int num) { int n, i, len; unsigned char buffer[256*sizeof(int)]; /* maximum is 256 records */ - unsigned int *int_array; + unsigned int *uint_array; /* See CCID 3.7.3 page 25 */ n = ControlUSB(reader_index, @@ -1377,8 +1539,7 @@ /* we got an error? */ if (n <= 0) { - DEBUG_INFO2("IFD does not support GET_DATA_RATES request: %s", - strerror(errno)); + DEBUG_INFO2("IFD does not support GET_DATA_RATES request: %d", n); return NULL; } @@ -1393,7 +1554,7 @@ n /= sizeof(int); /* we do not get the expected number of data rates */ - len = get_ccid_usb_interface(dev, &num)->altsetting->extra[27]; /* bNumDataRatesSupported */ + len = get_ccid_device_descriptor(get_ccid_usb_interface(desc, &num))[27]; /* bNumDataRatesSupported */ if ((n != len) && len) { DEBUG_INFO3("Got %d data rates but was expecting %d", n, len); @@ -1403,8 +1564,8 @@ n = len; } - int_array = calloc(n+1, sizeof(int)); - if (NULL == int_array) + uint_array = calloc(n+1, sizeof(uint_array[0])); + if (NULL == uint_array) { DEBUG_CRITICAL("Memory allocation failed"); return NULL; @@ -1413,20 +1574,20 @@ /* convert in correct endianess */ for (i=0; iuser_data; + *completed = 1; + /* caller interprets results and frees transfer */ +} + +/***************************************************************************** + * * InterruptRead * ****************************************************************************/ int InterruptRead(int reader_index, int timeout /* in ms */) { - int ret; - char buffer[8]; - - int bufferIndex; - int bitIndex; - int i; + int ret, actual_length; + int return_value = IFD_SUCCESS; + unsigned char buffer[8]; + struct libusb_transfer *transfer; + int completed = 0; + + /* Multislot reader: redirect to Multi_InterrupRead */ + if (usbDevice[reader_index].multislot_extension != NULL) + return Multi_InterruptRead(reader_index, timeout); DEBUG_PERIODIC2("before (%d)", reader_index); - ret = usb_interrupt_read(usbDevice[reader_index].handle, - usbDevice[reader_index].interrupt, buffer, sizeof(buffer), timeout); - DEBUG_PERIODIC3("after (%d) (%s)", reader_index, usb_strerror()); - if (ret < 0) + transfer = libusb_alloc_transfer(0); + if (NULL == transfer) + return LIBUSB_ERROR_NO_MEM; + + libusb_fill_bulk_transfer(transfer, + usbDevice[reader_index].dev_handle, + usbDevice[reader_index].interrupt, buffer, sizeof(buffer), + bulk_transfer_cb, &completed, timeout); + transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; + + ret = libusb_submit_transfer(transfer); + if (ret < 0) { + libusb_free_transfer(transfer); + DEBUG_CRITICAL2("libusb_submit_transfer failed: %d", ret); + return ret; + } + + usbDevice[reader_index].polling_transfer = transfer; + + while (!completed) { - /* if usb_interrupt_read() times out we get EILSEQ or EAGAIN */ - if ((errno != EILSEQ) && (errno != EAGAIN) && (errno != ENODEV) && (errno != 0)) - DEBUG_COMM4("usb_interrupt_read(%s/%s): %s", - usbDevice[reader_index].dirname, - usbDevice[reader_index].filename, strerror(errno)); + ret = libusb_handle_events(ctx); + if (ret < 0) + { + if (ret == LIBUSB_ERROR_INTERRUPTED) + continue; + libusb_cancel_transfer(transfer); + while (!completed) + if (libusb_handle_events(ctx) < 0) + break; + libusb_free_transfer(transfer); + DEBUG_CRITICAL2("libusb_handle_events failed: %d", ret); + return ret; + } } - else + + actual_length = transfer->actual_length; + ret = transfer->status; + + usbDevice[reader_index].polling_transfer = NULL; + libusb_free_transfer(transfer); + + DEBUG_PERIODIC3("after (%d) (%d)", reader_index, ret); + + switch (ret) { - DEBUG_XXD("NotifySlotChange: ", buffer, ret); + case LIBUSB_TRANSFER_COMPLETED: + DEBUG_XXD("NotifySlotChange: ", buffer, actual_length); - if (ret > 0) - { // If RDR_to_PC_NotifySlotChange is received - if (buffer[0] == 0x50) + if ((actual_length > 0) && (buffer[0] == 0x50)) { - DEBUG_INFO3("Reader: %s/%s", usbDevice[reader_index].dirname, - usbDevice[reader_index].filename); -#ifdef __APPLE__ - pthread_mutex_lock(usbDevice[reader_index].ccid.pbStatusLock); -#endif + int bufferIndex = 0; + int bitIndex = 0; + int i = 0; + // For each slot for (i = 0; i <= usbDevice[reader_index].ccid.bMaxSlotIndex; i++) { bufferIndex = i / 4; bitIndex = 2 * (i % 4); - if (bufferIndex + 1 < ret) + if (bufferIndex + 1 < actual_length) { if (buffer[bufferIndex + 1] & (1 << bitIndex)) usbDevice[reader_index].ccid.bStatus[i] = CCID_ICC_PRESENT_ACTIVE; else usbDevice[reader_index].ccid.bStatus[i] = CCID_ICC_ABSENT; - DEBUG_INFO3("Slot %d: 0x%02X", i, + DEBUG_INFO5("%d/%d: Slot %d: 0x%02X", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address, i, usbDevice[reader_index].ccid.bStatus[i]); } } -#ifdef __APPLE__ - pthread_mutex_unlock(usbDevice[reader_index].ccid.pbStatusLock); -#endif } - } + break; + + case LIBUSB_TRANSFER_TIMED_OUT: + break; + + default: + /* if libusb_interrupt_transfer() times out we get EILSEQ or EAGAIN */ + DEBUG_COMM4("InterruptRead (%d/%d): %s", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address, strerror(errno)); + return_value = IFD_COMMUNICATION_ERROR; } - return ret; + return return_value; } /* InterruptRead */ + +/***************************************************************************** + * + * Stop the async loop + * + ****************************************************************************/ +void InterruptStop(int reader_index) +{ + struct libusb_transfer *transfer; + + /* Multislot reader: redirect to Multi_InterrupStop */ + if (usbDevice[reader_index].multislot_extension != NULL) + { + Multi_InterruptStop(reader_index); + return; + } + + transfer = usbDevice[reader_index].polling_transfer; + usbDevice[reader_index].polling_transfer = NULL; + if (transfer) + { + int ret; + + ret = libusb_cancel_transfer(transfer); + if (ret < 0) + DEBUG_CRITICAL2("libusb_cancel_transfer failed: %d", ret); + } +} /* InterruptStop */ + + +/***************************************************************************** + * + * Multi_PollingProc + * + ****************************************************************************/ +static void *Multi_PollingProc(void *p_ext) +{ + struct usbDevice_MultiSlot_Extension *msExt = p_ext; + int rv, status, actual_length; + unsigned char buffer[CCID_INTERRUPT_SIZE]; + struct libusb_transfer *transfer; + int completed; + + DEBUG_COMM3("Multi_PollingProc (%d/%d): thread starting", + usbDevice[msExt->reader_index].bus_number, + usbDevice[msExt->reader_index].device_address); + + rv = 0; + while (!msExt->terminated) + { + DEBUG_COMM3("Multi_PollingProc (%d/%d): waiting", + usbDevice[msExt->reader_index].bus_number, + usbDevice[msExt->reader_index].device_address); + + transfer = libusb_alloc_transfer(0); + if (NULL == transfer) + { + rv = LIBUSB_ERROR_NO_MEM; + DEBUG_COMM2("libusb_alloc_transfer err %d", rv); + break; + } + + libusb_fill_bulk_transfer(transfer, + usbDevice[msExt->reader_index].dev_handle, + usbDevice[msExt->reader_index].interrupt, + buffer, CCID_INTERRUPT_SIZE, + bulk_transfer_cb, &completed, 0); /* No timeout ! */ + + transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; + + rv = libusb_submit_transfer(transfer); + if (rv < 0) + { + libusb_free_transfer(transfer); + DEBUG_COMM2("libusb_submit_transfer err %d", rv); + break; + } + + usbDevice[msExt->reader_index].polling_transfer = transfer; + + completed = 0; + while (!completed && !msExt->terminated) + { + rv = libusb_handle_events(ctx); + if (rv < 0) + { + DEBUG_COMM2("libusb_handle_events err %d", rv); + + if (rv == LIBUSB_ERROR_INTERRUPTED) + continue; + + libusb_cancel_transfer(transfer); + + while (!completed && !msExt->terminated) + { + if (libusb_handle_events(ctx) < 0) + break; + } + + break; + } + } + + usbDevice[msExt->reader_index].polling_transfer = NULL; + + if (rv < 0) + libusb_free_transfer(transfer); + else + { + int b, slot; + + actual_length = transfer->actual_length; + status = transfer->status; + + libusb_free_transfer(transfer); + + switch (status) + { + case LIBUSB_TRANSFER_COMPLETED: + DEBUG_COMM3("Multi_PollingProc (%d/%d): OK", + usbDevice[msExt->reader_index].bus_number, + usbDevice[msExt->reader_index].device_address); + DEBUG_XXD("NotifySlotChange: ", buffer, actual_length); + + // If ACR38 card status message is received, then convert it + // to RDR_to_PC_NotifySlotChange. + if ((actual_length > 1) && (buffer[0] == 0x01)) + { + buffer[0] = 0x50; + buffer[1] = (buffer[1] == 0xC0) ? 0x02 : 0x03; + actual_length = 2; + } + + /* log the RDR_to_PC_NotifySlotChange data */ + slot = 0; + for (b=0; b> (s*2)) & 3); + const char *present, *change; + + present = (slot_status & 1) ? "present" : "absent"; + change = (slot_status & 2) ? "status changed" : "no change"; + + DEBUG_COMM3("slot %d status: %d", + s + b*4, slot_status); + DEBUG_COMM3("ICC %s, %s", present, change); + } + slot += 4; + } + break; + + case LIBUSB_TRANSFER_TIMED_OUT: + DEBUG_COMM3("Multi_PollingProc (%d/%d): Timeout", + usbDevice[msExt->reader_index].bus_number, + usbDevice[msExt->reader_index].device_address); + break; + + default: + /* if libusb_interrupt_transfer() times out + * we get EILSEQ or EAGAIN */ + DEBUG_COMM4("Multi_PollingProc (%d/%d): %d", + usbDevice[msExt->reader_index].bus_number, + usbDevice[msExt->reader_index].device_address, + status); + } + + /* Tell other slots that there's a new interrupt buffer */ + DEBUG_COMM3("Multi_PollingProc (%d/%d): Broadcast to slot(s)", + usbDevice[msExt->reader_index].bus_number, + usbDevice[msExt->reader_index].device_address); + + /* Lock the mutex */ + pthread_mutex_lock(&msExt->mutex); + + /* Set the status and the interrupt buffer */ + msExt->status = status; + memset(msExt->buffer, 0, sizeof msExt->buffer); + memcpy(msExt->buffer, buffer, actual_length); + + /* Broadcast the condition and unlock */ + pthread_cond_broadcast(&msExt->condition); + pthread_mutex_unlock(&msExt->mutex); + } + } + + msExt->terminated = TRUE; + + if (rv < 0) + { + DEBUG_CRITICAL4("Multi_PollingProc (%d/%d): error %d", + usbDevice[msExt->reader_index].bus_number, + usbDevice[msExt->reader_index].device_address, rv); + } + + /* Wake up the slot threads so they will exit as well */ + + /* Lock the mutex */ + pthread_mutex_lock(&msExt->mutex); + + /* Set the status and fill-in the interrupt buffer */ + msExt->status = 0; + memset(msExt->buffer, 0xFF, sizeof msExt->buffer); + + /* Broadcast the condition */ + pthread_cond_broadcast(&msExt->condition); + + /* Unlock */ + pthread_mutex_unlock(&msExt->mutex); + + /* Now exit */ + DEBUG_COMM3("Multi_PollingProc (%d/%d): Thread terminated", + usbDevice[msExt->reader_index].bus_number, + usbDevice[msExt->reader_index].device_address); + + pthread_exit(NULL); + return NULL; +} /* Multi_PollingProc */ + + +/***************************************************************************** + * + * Multi_PollingTerminate + * + ****************************************************************************/ +static void Multi_PollingTerminate(struct usbDevice_MultiSlot_Extension *msExt) +{ + struct libusb_transfer *transfer; + + if (msExt && !msExt->terminated) + { + msExt->terminated = TRUE; + + transfer = usbDevice[msExt->reader_index].polling_transfer; + + if (transfer) + { + int ret; + + ret = libusb_cancel_transfer(transfer); + if (ret < 0) + DEBUG_CRITICAL2("libusb_cancel_transfer failed: %d", ret); + } + } +} /* Multi_PollingTerminate */ + + +/***************************************************************************** + * + * Multi_InterruptRead + * + ****************************************************************************/ +static int Multi_InterruptRead(int reader_index, int timeout /* in ms */) +{ + struct usbDevice_MultiSlot_Extension *msExt; + unsigned char buffer[CCID_INTERRUPT_SIZE]; + struct timespec cond_wait_until; + struct timeval local_time; + int rv, status, interrupt_byte, interrupt_mask; + + msExt = usbDevice[reader_index].multislot_extension; + + /* When stopped, return 0 so IFDHPolling will return IFD_NO_SUCH_DEVICE */ + if ((msExt == NULL) || msExt->terminated) + return 0; + + DEBUG_PERIODIC3("Multi_InterruptRead (%d), timeout: %d ms", + reader_index, timeout); + + /* Select the relevant bit in the interrupt buffer */ + interrupt_byte = (usbDevice[reader_index].ccid.bCurrentSlotIndex / 4) + 1; + interrupt_mask = 0x02 << (2 * (usbDevice[reader_index].ccid.bCurrentSlotIndex % 4)); + + /* Wait until the condition is signaled or a timeout occurs */ + pthread_mutex_lock(&msExt->mutex); + gettimeofday(&local_time, NULL); + cond_wait_until.tv_sec = local_time.tv_sec; + cond_wait_until.tv_nsec = local_time.tv_usec * 1000; + + cond_wait_until.tv_sec += timeout / 1000; + cond_wait_until.tv_nsec += 1000000 * (timeout % 1000); + +again: + rv = pthread_cond_timedwait(&msExt->condition, &msExt->mutex, + &cond_wait_until); + + if (0 == rv) + { + /* Retrieve interrupt buffer and request result */ + memcpy(buffer, msExt->buffer, sizeof buffer); + status = msExt->status; + } + else + if (rv == ETIMEDOUT) + status = LIBUSB_TRANSFER_TIMED_OUT; + else + status = -1; + + /* Don't forget to unlock the mutex */ + pthread_mutex_unlock(&msExt->mutex); + + /* When stopped, return 0 so IFDHPolling will return IFD_NO_SUCH_DEVICE */ + if (msExt->terminated) + return 0; + + /* Not stopped */ + if (status == LIBUSB_TRANSFER_COMPLETED) + { + if (0 == (buffer[interrupt_byte] & interrupt_mask)) + { + DEBUG_PERIODIC2("Multi_InterruptRead (%d) -- skipped", reader_index); + goto again; + } + DEBUG_PERIODIC2("Multi_InterruptRead (%d), got an interrupt", reader_index); + } + else + { + DEBUG_PERIODIC3("Multi_InterruptRead (%d), status=%d", reader_index, status); + } + + return status; +} /* Multi_InterruptRead */ + + +/***************************************************************************** + * + * Multi_InterruptStop + * + ****************************************************************************/ +static void Multi_InterruptStop(int reader_index) +{ + struct usbDevice_MultiSlot_Extension *msExt; + int interrupt_byte, interrupt_mask; + + msExt = usbDevice[reader_index].multislot_extension; + + /* Already stopped ? */ + if ((NULL == msExt) || msExt->terminated) + return; + + DEBUG_PERIODIC2("Stop (%d)", reader_index); + + interrupt_byte = (usbDevice[reader_index].ccid.bCurrentSlotIndex / 4) + 1; + interrupt_mask = 0x02 << (2 * (usbDevice[reader_index].ccid.bCurrentSlotIndex % 4)); + + pthread_mutex_lock(&msExt->mutex); + + /* Broacast an interrupt to wake-up the slot's thread */ + msExt->buffer[interrupt_byte] |= interrupt_mask; + pthread_cond_broadcast(&msExt->condition); + + pthread_mutex_unlock(&msExt->mutex); +} /* Multi_InterruptStop */ + + +/***************************************************************************** + * + * Multi_CreateFirstSlot + * + ****************************************************************************/ +static struct usbDevice_MultiSlot_Extension *Multi_CreateFirstSlot(int reader_index) +{ + struct usbDevice_MultiSlot_Extension *msExt; + + /* Allocate a new extension buffer */ + msExt = malloc(sizeof(struct usbDevice_MultiSlot_Extension)); + if (NULL == msExt) + return NULL; + + /* Remember the index */ + msExt->reader_index = reader_index; + + msExt->terminated = FALSE; + msExt->status = 0; + msExt->transfer = NULL; + + /* Create mutex and condition object for the interrupt polling */ + pthread_mutex_init(&msExt->mutex, NULL); + pthread_cond_init(&msExt->condition, NULL); + + /* create the thread in charge of the interrupt polling */ + pthread_create(&msExt->thread_proc, NULL, Multi_PollingProc, msExt); + + return msExt; +} /* Multi_CreateFirstSlot */ + + +/***************************************************************************** + * + * Multi_CreateNextSlot + * + ****************************************************************************/ +static struct usbDevice_MultiSlot_Extension *Multi_CreateNextSlot(int physical_reader_index) +{ + /* Take the extension buffer from the main slot */ + return usbDevice[physical_reader_index].multislot_extension; +} /* Multi_CreateNextSlot */ + + #ifdef __APPLE__ // Card detection thread static void *CardDetectionThread(void *pParam) { int reader_index = *((int *) pParam); + int rv = 0; + int status = 0; + int actual_length = 0; + unsigned char buffer[CCID_INTERRUPT_SIZE]; + struct libusb_transfer *transfer = NULL; + int completed = 0; + + DEBUG_COMM3("%d/%d: Enter", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address); - DEBUG_INFO2("Enter: Reader: %d", reader_index); while (!usbDevice[reader_index].terminated) - InterruptRead(reader_index, 100); + { + DEBUG_COMM3("%d/%d: Waiting...", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address); - DEBUG_INFO2("Exit: Reader: %d", reader_index); - return ((void *) 0); -} + transfer = libusb_alloc_transfer(0); + if (NULL == transfer) + { + rv = LIBUSB_ERROR_NO_MEM; + DEBUG_COMM2("libusb_alloc_transfer err %d", rv); + break; + } -// Get pipe reference from endpoint number -static int GetPipeRef(struct darwin_dev_handle *device, int ep) -{ - int i; + libusb_fill_bulk_transfer(transfer, + usbDevice[reader_index].dev_handle, + usbDevice[reader_index].interrupt, + buffer, CCID_INTERRUPT_SIZE, + bulk_transfer_cb, &completed, 0); // Infinite timeout + + transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; + + rv = libusb_submit_transfer(transfer); + if (rv < 0) + { + libusb_free_transfer(transfer); + DEBUG_COMM2("libusb_submit_transfer err %d", rv); + break; + } + + // Lock transfer + pthread_mutex_lock(usbDevice[reader_index].pTransferLock); + + *usbDevice[reader_index].pTransfer = transfer; - for (i = 0; i < device->num_endpoints; i++) - if (device->endpoint_addrs[i] == ep) - return i + 1; + // Unlock transfer + pthread_mutex_unlock(usbDevice[reader_index].pTransferLock); - return -1; + completed = 0; + while (!completed && !usbDevice[reader_index].terminated) + { + rv = libusb_handle_events(ctx); + if (rv < 0) + { + DEBUG_COMM2("libusb_handle_events err %d", rv); + + if (rv == LIBUSB_ERROR_INTERRUPTED) + continue; + + libusb_cancel_transfer(transfer); + + while (!completed && !usbDevice[reader_index].terminated) + { + if (libusb_handle_events(ctx) < 0) + break; + } + + break; + } + } + + // Lock transfer + pthread_mutex_lock(usbDevice[reader_index].pTransferLock); + + *usbDevice[reader_index].pTransfer = NULL; + + // Unlock transfer + pthread_mutex_unlock(usbDevice[reader_index].pTransferLock); + + if (rv < 0) + libusb_free_transfer(transfer); + else + { + actual_length = transfer->actual_length; + status = transfer->status; + + libusb_free_transfer(transfer); + + switch (status) + { + case LIBUSB_TRANSFER_COMPLETED: + DEBUG_COMM3("%d/%d: OK", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address); + DEBUG_XXD("NotifySlotChange: ", buffer, actual_length); + + // If RDR_to_PC_NotifySlotChange is received + if ((actual_length > 0) && (buffer[0] == 0x50)) + { + int bufferIndex = 0; + int bitIndex = 0; + int i = 0; + + // Lock bStatus + pthread_mutex_lock(usbDevice[reader_index].ccid.pbStatusLock); + + // For each slot + for (i = 0; i <= usbDevice[reader_index].ccid.bMaxSlotIndex; i++) + { + bufferIndex = i / 4; + bitIndex = 2 * (i % 4); + + if (bufferIndex + 1 < actual_length) + { + if (buffer[bufferIndex + 1] & (1 << bitIndex)) + usbDevice[reader_index].ccid.bStatus[i] = CCID_ICC_PRESENT_ACTIVE; + else + usbDevice[reader_index].ccid.bStatus[i] = CCID_ICC_ABSENT; + + DEBUG_INFO5("%d/%d: Slot %d: 0x%02X", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address, i, + usbDevice[reader_index].ccid.bStatus[i]); + } + } + + // Unlock bStatus + pthread_mutex_unlock(usbDevice[reader_index].ccid.pbStatusLock); + } + break; + + case LIBUSB_TRANSFER_TIMED_OUT: + DEBUG_COMM3("%d/%d: Timeout", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address); + break; + + default: + DEBUG_COMM4("%d/%d: Status: %d", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address, + status); + } + } + } + + usbDevice[reader_index].terminated = TRUE; + + if (rv < 0) + { + DEBUG_CRITICAL4("%d/%d: Error: %d", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address, rv); + } + + DEBUG_COMM3("%d/%d: Exit", + usbDevice[reader_index].bus_number, + usbDevice[reader_index].device_address); + + return ((void *) 0); } #endif diff -Nru acsccid-1.0.8/src/ccid_usb.h acsccid-1.1.0/src/ccid_usb.h --- acsccid-1.0.8/src/ccid_usb.h 2009-07-28 20:57:07.000000000 +0000 +++ acsccid-1.1.0/src/ccid_usb.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,6 +1,6 @@ /* ccid_usb.h: USB access routines using the libusb library - Copyright (C) 2003-2004 Ludovic Rousseau + Copyright (C) 2003-2010 Ludovic Rousseau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,7 @@ */ /* - * $Id: ccid_usb.h 4346 2009-07-28 13:39:37Z rousseau $ + * $Id: ccid_usb.h 5473 2011-01-04 09:52:26Z rousseau $ */ #ifndef __CCID_USB_H__ @@ -35,13 +35,15 @@ status_t CloseUSB(unsigned int reader_index); -#if defined (__USB_H__) || defined (_SYS_USB_LIBUSB_USB_H) -/*@null@*/ struct usb_interface *get_ccid_usb_interface( - struct usb_device *dev, int *num); -#endif +#include +/*@null@*/ const struct libusb_interface *get_ccid_usb_interface( + struct libusb_config_descriptor *desc, int *num); + +const unsigned char *get_ccid_device_descriptor(const struct libusb_interface *usb_interface); int ControlUSB(int reader_index, int requesttype, int request, int value, unsigned char *bytes, unsigned int size); int InterruptRead(int reader_index, int timeout); +void InterruptStop(int reader_index); #endif diff -Nru acsccid-1.0.8/src/commands.c acsccid-1.1.0/src/commands.c --- acsccid-1.0.8/src/commands.c 2012-01-06 03:45:02.000000000 +0000 +++ acsccid-1.1.0/src/commands.c 2014-12-10 08:32:26.000000000 +0000 @@ -1,7 +1,8 @@ /* commands.c: Commands sent to the card - Copyright (C) 2003-2004 Ludovic Rousseau - Copyright (C) 2010-2012 Advanced Card Systems Ltd. + Copyright (C) 2003-2010 Ludovic Rousseau + Copyright (C) 2005 Martin Paljak + Copyright (C) 2010-2014 Advanced Card Systems Ltd. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -19,17 +20,28 @@ */ /* - * $Id: commands.c 4235 2009-05-29 11:42:46Z rousseau $ + * $Id: commands.c 6975 2014-09-04 11:33:05Z rousseau $ */ +#include + +#ifdef HAVE_STRING_H #include +#endif +#ifdef HAVE_STDLIB_H #include +#endif +#ifdef HAVE_ERRNO_H #include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + #include #include #include -#include "config.h" #include "misc.h" #include "commands.h" #include "openct/proto-t1.h" @@ -52,11 +64,18 @@ #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif -// Fix problem using pcsc-lite 1.6.x header files -#ifndef IFD_ERROR_INSUFFICIENT_BUFFER -#define IFD_ERROR_INSUFFICIENT_BUFFER 618 +#ifndef BSWAP_16 +#define BSWAP_8(x) ((x) & 0xff) +#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8)) +#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16)) #endif +#define CHECK_STATUS(res) \ + if (STATUS_NO_SUCH_DEVICE == res) \ + return IFD_NO_SUCH_DEVICE; \ + if (STATUS_SUCCESS != res) \ + return IFD_COMMUNICATION_ERROR; + /* internal functions */ static RESPONSECODE CmdXfrBlockAPDU_extended(unsigned int reader_index, unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length, @@ -75,6 +94,7 @@ unsigned char rx_buffer[]); static void i2dw(int value, unsigned char *buffer); +static unsigned int bei2i(unsigned char *buffer); /***************************************************************************** @@ -93,7 +113,7 @@ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); #ifndef TWIN_SERIAL - if (ICCD_A == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol) { int r; unsigned char pcbuffer[SIZE_GET_SLOT_STATUS]; @@ -123,7 +143,7 @@ return IFD_SUCCESS; } - if (ICCD_B == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol) { int r; unsigned char tmp[MAX_ATR_SIZE+1]; @@ -183,19 +203,19 @@ if ((1 == voltage) && !(bVoltageSupport & 1)) { - DEBUG_INFO("5V requested but not support by reader"); + DEBUG_INFO1("5V requested but not support by reader"); voltage = 2; /* 3V */ } if ((2 == voltage) && !(bVoltageSupport & 2)) { - DEBUG_INFO("3V requested but not support by reader"); + DEBUG_INFO1("3V requested but not support by reader"); voltage = 3; /* 1.8V */ } if ((3 == voltage) && !(bVoltageSupport & 4)) { - DEBUG_INFO("1.8V requested but not support by reader"); + DEBUG_INFO1("1.8V requested but not support by reader"); voltage = 0; /* auto */ } } @@ -209,16 +229,14 @@ cmd[8] = cmd[9] = 0; /* RFU */ res = WritePort(reader_index, sizeof(cmd), cmd); - if (res != STATUS_SUCCESS) - return IFD_COMMUNICATION_ERROR; + CHECK_STATUS(res) /* reset available buffer size */ /* needed if we go back after a switch to ISO mode */ *nlength = length; res = ReadPort(reader_index, nlength, buffer); - if (res != STATUS_SUCCESS) - return IFD_COMMUNICATION_ERROR; + CHECK_STATUS(res) if (*nlength < STATUS_OFFSET+1) { @@ -239,7 +257,7 @@ unsigned int res_length = sizeof(res_tmp); if ((return_value = CmdEscape(reader_index, cmd_tmp, - sizeof(cmd_tmp), res_tmp, &res_length)) != IFD_SUCCESS) + sizeof(cmd_tmp), res_tmp, &res_length, 0)) != IFD_SUCCESS) return return_value; /* avoid looping if we can't switch mode */ @@ -252,7 +270,9 @@ /* continue with 3 volts and 5 volts */ if (voltage > 1) { +#ifndef NO_LOG const char *voltage_code[] = { "auto", "5V", "3V", "1.8V" }; +#endif DEBUG_INFO3("Power up with %s failed. Try with %s.", voltage_code[voltage], voltage_code[voltage-1]); @@ -287,10 +307,13 @@ { unsigned char cmd[11+14+TxLength]; unsigned int a, b; + PIN_VERIFY_STRUCTURE *pvs; _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); int old_read_timeout; RESPONSECODE ret; + status_t res; + pvs = (PIN_VERIFY_STRUCTURE *)TxBuffer; cmd[0] = 0x69; /* Secure */ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */ cmd[6] = (*ccid_descriptor->pbSeq)++; @@ -305,6 +328,20 @@ return IFD_NOT_SUPPORTED; } + /* On little endian machines we are all set. */ + /* If on big endian machine and caller is using host byte order */ + if ((pvs->ulDataLength + 19 == TxLength) && + (bei2i((unsigned char*)(&pvs->ulDataLength)) == pvs->ulDataLength)) + { + DEBUG_INFO1("Reversing order from big to little endian"); + /* If ulDataLength is big endian, assume others are too */ + /* reverse the byte order for 3 fields */ + pvs->wPINMaxExtraDigit = BSWAP_16(pvs->wPINMaxExtraDigit); + pvs->wLangId = BSWAP_16(pvs->wLangId); + pvs->ulDataLength = BSWAP_32(pvs->ulDataLength); + } + /* At this point we now have the above 3 variables in little endian */ + if (dw2i(TxBuffer, 15) + 19 != TxLength) /* ulDataLength field coherency */ { DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 15) + 19, TxLength); @@ -322,7 +359,8 @@ #ifdef BOGUS_PINPAD_FIRMWARE /* bug circumvention for the GemPC Pinpad */ - if (GEMPCPINPAD == ccid_descriptor->readerID) + if ((GEMPCPINPAD == ccid_descriptor->readerID) + || (VEGAALPHA == ccid_descriptor->readerID)) { /* the firmware reject the cases: 00h No string and FFh default * CCID message. The only value supported is 01h (display 1 message) */ @@ -344,7 +382,8 @@ } - if (DELLSCRK == ccid_descriptor->readerID) + if ((DELLSCRK == ccid_descriptor->readerID) + || (DELLSK == ccid_descriptor->readerID)) { /* the firmware rejects the cases: 01h-FEh and FFh default * CCID message. The only value supported is 00h (no message) */ @@ -354,6 +393,21 @@ TxBuffer[8]); TxBuffer[8] = 0x00; } + + /* avoid the command rejection because the Enter key is still + * pressed. Wait a bit for the key to be released */ + (void)usleep(250*1000); + } + + if (DELLSK == ccid_descriptor->readerID) + { + /* the 2 bytes of wPINMaxExtraDigit are reversed */ + int tmp; + + tmp = TxBuffer[6]; + TxBuffer[6] = TxBuffer[5]; + TxBuffer[5] = tmp; + DEBUG_INFO1("Correcting wPINMaxExtraDigit for Dell keyboard"); } #endif @@ -415,7 +469,7 @@ /* the SPR532 will append the PIN code without any padding */ return_value = CmdEscape(reader_index, cmd_tmp, sizeof(cmd_tmp), - res_tmp, &res_length); + res_tmp, &res_length, 0); if (return_value != IFD_SUCCESS) return return_value; @@ -428,13 +482,15 @@ i2dw(a - 10, cmd + 1); /* CCID message length */ old_read_timeout = ccid_descriptor -> readTimeout; - // Change timeout to infinite - // ccid_descriptor -> readTimeout = max(30, TxBuffer[0]+10); /* at least 30 seconds */ ccid_descriptor -> readTimeout = 0; // Infinite - if (WritePort(reader_index, a, cmd) != STATUS_SUCCESS) + res = WritePort(reader_index, a, cmd); + if (STATUS_SUCCESS != res) { - ret = IFD_COMMUNICATION_ERROR; + if (STATUS_NO_SUCH_DEVICE == res) + ret = IFD_NO_SUCH_DEVICE; + else + ret = IFD_COMMUNICATION_ERROR; goto end; } @@ -455,8 +511,72 @@ } else { - /* get only the T=1 data */ /* FIXME: manage T=1 error blocks */ + + /* defines from openct/proto-t1.c */ + #define PCB 1 + #define DATA 3 + #define T1_S_BLOCK 0xC0 + #define T1_S_RESPONSE 0x20 + #define T1_S_TYPE(pcb) ((pcb) & 0x0F) + #define T1_S_WTX 0x03 + + /* WTX S-block */ + if ((T1_S_BLOCK | T1_S_WTX) == RxBuffer[PCB]) + { +/* + * The Swiss health care card sends a WTX request before returning the + * SW code. If the reader is in TPDU the driver must manage the request + * itself. + * + * received: 00 C3 01 09 CB + * openct/proto-t1.c:432:t1_transceive() S-Block request received + * openct/proto-t1.c:489:t1_transceive() CT sent S-block with wtx=9 + * sending: 00 E3 01 09 EB + * openct/proto-t1.c:667:t1_xcv() New timeout at WTX request: 23643 sec + * received: 00 40 02 90 00 D2 +*/ + ct_buf_t tbuf; + unsigned char sblk[1]; /* we only need 1 byte of data */ + t1_state_t *t1 = &get_ccid_slot(reader_index)->t1; + unsigned int slen; + int oldReadTimeout; + + DEBUG_COMM2("CT sent S-block with wtx=%u", RxBuffer[DATA]); + t1->wtx = RxBuffer[DATA]; + + oldReadTimeout = ccid_descriptor->readTimeout; + if (t1->wtx > 1) + { + /* set the new temporary timeout at WTX card request */ + ccid_descriptor->readTimeout *= t1->wtx; + DEBUG_INFO2("New timeout at WTX request: %d sec", + ccid_descriptor->readTimeout); + } + + ct_buf_init(&tbuf, sblk, sizeof(sblk)); + t1->wtx = RxBuffer[DATA]; + ct_buf_putc(&tbuf, RxBuffer[DATA]); + + slen = t1_build(t1, RxBuffer, 0, + T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(RxBuffer[PCB]), + &tbuf, NULL); + + ret = CCID_Transmit(t1 -> lun, slen, RxBuffer, 0, t1->wtx); + if (ret != IFD_SUCCESS) + return ret; + + /* I guess we have at least 6 bytes in RxBuffer */ + *RxLength = 6; + ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL); + if (ret != IFD_SUCCESS) + return ret; + + /* Restore initial timeout */ + ccid_descriptor->readTimeout = oldReadTimeout; + } + + /* get only the T=1 data */ memmove(RxBuffer, RxBuffer+3, *RxLength -4); *RxLength -= 4; /* remove NAD, PCB, LEN and CRC */ } @@ -468,6 +588,44 @@ } /* SecurePINVerify */ +#ifdef BOGUS_PINPAD_FIRMWARE +/***************************************************************************** + * + * has_gemalto_modify_pin_bug + * + ****************************************************************************/ +static int has_gemalto_modify_pin_bug(_ccid_descriptor *ccid_descriptor) +{ + /* Bug not present by default */ + int has_bug = 0; + + /* Covadis Véga-Alpha reader */ + if (VEGAALPHA == ccid_descriptor->readerID) + { + /* This reader has the bug (uses a Gemalto firmware) */ + has_bug = 1; + } + else + { + /* Gemalto reader */ + if ((GET_VENDOR(ccid_descriptor->readerID) == VENDOR_GEMALTO)) + { + has_bug = 1; /* assume it has the bug */ + + if (ccid_descriptor->gemalto_firmware_features && + ccid_descriptor->gemalto_firmware_features->bNumberMessageFix) + { + /* A Gemalto reader has the ModifyPIN structure bug */ + /* unless it explicitly reports it has been fixed */ + has_bug = 0; + } + } + } + + return has_bug; +} /* has_gemalto_modify_pin_bug */ +#endif + /***************************************************************************** * * SecurePINModify @@ -479,13 +637,17 @@ { unsigned char cmd[11+19+TxLength]; unsigned int a, b; + PIN_MODIFY_STRUCTURE *pms; _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); int old_read_timeout; RESPONSECODE ret; + status_t res; #ifdef BOGUS_PINPAD_FIRMWARE - int bNumberMessages = 0; /* for GemPC Pinpad */ + int bNumberMessage = 0; /* for GemPC Pinpad */ + int gemalto_modify_pin_bug; #endif + pms = (PIN_MODIFY_STRUCTURE *)TxBuffer; cmd[0] = 0x69; /* Secure */ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */ cmd[6] = (*ccid_descriptor->pbSeq)++; @@ -500,6 +662,21 @@ return IFD_NOT_SUPPORTED; } + /* On little endian machines we are all set. */ + /* If on big endian machine and caller is using host byte order */ + if ((pms->ulDataLength + 24 == TxLength) && + (bei2i((unsigned char*)(&pms->ulDataLength)) == pms->ulDataLength)) + { + DEBUG_INFO1("Reversing order from big to little endian"); + /* If ulDataLength is big endian, assume others are too */ + /* reverse the byte order for 3 fields */ + pms->wPINMaxExtraDigit = BSWAP_16(pms->wPINMaxExtraDigit); + pms->wLangId = BSWAP_16(pms->wLangId); + pms->ulDataLength = BSWAP_32(pms->ulDataLength); + } + /* At this point we now have the above 3 variables in little endian */ + + if (dw2i(TxBuffer, 20) + 24 != TxLength) /* ulDataLength field coherency */ { DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 20) + 24, TxLength); @@ -532,22 +709,23 @@ if ((SPR532 == ccid_descriptor->readerID) || (CHERRYST2000 == ccid_descriptor->readerID)) { - TxBuffer[11] = 0x03; /* set bNumberMessages to 3 so that + TxBuffer[11] = 0x03; /* set bNumberMessage to 3 so that all bMsgIndex123 are filled */ TxBuffer[14] = TxBuffer[15] = TxBuffer[16] = 0; /* bMsgIndex123 */ } /* the bug is a bit different than for the Cherry ST 2000C - * with bNumberMessages < 3 the command seems to be accepted + * with bNumberMessage < 3 the command seems to be accepted * and the card sends 6B 80 */ if (CHERRYXX44 == ccid_descriptor->readerID) { - TxBuffer[11] = 0x03; /* set bNumberMessages to 3 so that + TxBuffer[11] = 0x03; /* set bNumberMessage to 3 so that all bMsgIndex123 are filled */ } /* bug circumvention for the GemPC Pinpad */ - if (GEMPCPINPAD == ccid_descriptor->readerID) + if ((GEMPCPINPAD == ccid_descriptor->readerID) + || (VEGAALPHA == ccid_descriptor->readerID)) { /* The reader does not support, and actively reject, "max size reached" * and "timeout occured" validation conditions */ @@ -557,13 +735,21 @@ TxBuffer[10]); TxBuffer[10] = 0x02; /* validation key pressed */ } + } - /* the reader does not support any other value than 3 for the number - * of messages */ - bNumberMessages = TxBuffer[11]; + gemalto_modify_pin_bug = has_gemalto_modify_pin_bug(ccid_descriptor); + if (gemalto_modify_pin_bug) + { + DEBUG_INFO1("Gemalto CCID Modify Pin Bug"); + + /* The reader requests a value for bMsgIndex2 and bMsgIndex3 + * even if they should not be present. So we fake + * bNumberMessage=3. The real number of messages will be + * corrected later in the code */ + bNumberMessage = TxBuffer[11]; if (0x03 != TxBuffer[11]) { - DEBUG_INFO2("Correct bNumberMessages for GemPC Pinpad (was %d)", + DEBUG_INFO2("Correct bNumberMessage for GemPC Pinpad (was %d)", TxBuffer[11]); TxBuffer[11] = 0x03; /* 3 messages */ } @@ -637,24 +823,26 @@ if ((SPR532 == ccid_descriptor->readerID) || (CHERRYST2000 == ccid_descriptor->readerID)) { - cmd[21] = 0x00; /* set bNumberMessages to 0 */ + cmd[21] = 0x00; /* set bNumberMessage to 0 */ } - if (GEMPCPINPAD == ccid_descriptor->readerID) - cmd[21] = bNumberMessages; /* restore the real value */ + if (gemalto_modify_pin_bug) + cmd[21] = bNumberMessage; /* restore the real value */ #endif /* We know the size of the CCID message now */ i2dw(a - 10, cmd + 1); /* command length (includes bPINOperation) */ old_read_timeout = ccid_descriptor -> readTimeout; - // Change timeout to infinite - // ccid_descriptor -> readTimeout = max(30, TxBuffer[0]+10); /* at least 30 seconds */ ccid_descriptor -> readTimeout = 0; // Infinite - if (WritePort(reader_index, a, cmd) != STATUS_SUCCESS) + res = WritePort(reader_index, a, cmd); + if (STATUS_SUCCESS != res) { - ret = IFD_COMMUNICATION_ERROR; + if (STATUS_NO_SUCH_DEVICE == res) + ret = IFD_NO_SUCH_DEVICE; + else + ret = IFD_COMMUNICATION_ERROR; goto end; } @@ -695,17 +883,24 @@ ****************************************************************************/ RESPONSECODE CmdEscape(unsigned int reader_index, const unsigned char TxBuffer[], unsigned int TxLength, - unsigned char RxBuffer[], unsigned int *RxLength) + unsigned char RxBuffer[], unsigned int *RxLength, unsigned int timeout) { unsigned char *cmd_in, *cmd_out; status_t res; unsigned int length_in, length_out; RESPONSECODE return_value = IFD_SUCCESS; - //int old_read_timeout; + int old_read_timeout; _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); - //old_read_timeout = ccid_descriptor -> readTimeout; - //ccid_descriptor -> readTimeout = 30; /* 30 seconds */ + /* a value of 0 do not change the default read timeout */ + if (timeout > 0) + { + old_read_timeout = ccid_descriptor -> readTimeout; + + // Set infinite timeout + ccid_descriptor -> readTimeout = (timeout == (unsigned int) -1) ? + 0 : timeout; + } again: /* allocate buffers */ @@ -738,10 +933,15 @@ if (res != STATUS_SUCCESS) { free(cmd_out); - return_value = IFD_COMMUNICATION_ERROR; + if (STATUS_NO_SUCH_DEVICE == res) + return_value = IFD_NO_SUCH_DEVICE; + else + return_value = IFD_COMMUNICATION_ERROR; goto end; } +time_request: + length_out = 10 + *RxLength; res = ReadPort(reader_index, &length_out, cmd_out); /* replay the command if NAK @@ -757,7 +957,10 @@ if (res != STATUS_SUCCESS) { free(cmd_out); - return_value = IFD_COMMUNICATION_ERROR; + if (STATUS_NO_SUCH_DEVICE == res) + return_value = IFD_NO_SUCH_DEVICE; + else + return_value = IFD_COMMUNICATION_ERROR; goto end; } @@ -769,6 +972,12 @@ goto end; } + if (cmd_out[STATUS_OFFSET] & CCID_TIME_EXTENSION) + { + DEBUG_COMM2("Time extension requested: 0x%02X", cmd_out[ERROR_OFFSET]); + goto time_request; + } + if (cmd_out[STATUS_OFFSET] & CCID_COMMAND_FAILED) { ccid_error(cmd_out[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */ @@ -785,7 +994,9 @@ free(cmd_out); end: - //ccid_descriptor -> readTimeout = old_read_timeout; + if (timeout > 0) + ccid_descriptor -> readTimeout = old_read_timeout; + return return_value; } /* Escape */ @@ -804,7 +1015,7 @@ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); #ifndef TWIN_SERIAL - if (ICCD_A == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol) { int r; @@ -821,7 +1032,7 @@ return IFD_SUCCESS; } - if (ICCD_B == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol) { int r; unsigned char buffer[3]; @@ -857,13 +1068,11 @@ cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */ res = WritePort(reader_index, sizeof(cmd), cmd); - if (res != STATUS_SUCCESS) - return IFD_COMMUNICATION_ERROR; + CHECK_STATUS(res) length = sizeof(cmd); res = ReadPort(reader_index, &length, cmd); - if (res != STATUS_SUCCESS) - return IFD_COMMUNICATION_ERROR; + CHECK_STATUS(res) if (length < STATUS_OFFSET+1) { @@ -895,7 +1104,7 @@ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); #ifndef TWIN_SERIAL - if (ICCD_A == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol) { int r; unsigned char status[1]; @@ -935,7 +1144,7 @@ return IFD_SUCCESS; } - if (ICCD_B == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol) { int r; unsigned char buffer_tmp[3]; @@ -977,17 +1186,11 @@ cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */ res = WritePort(reader_index, sizeof(cmd), cmd); - if (res != STATUS_SUCCESS) - { - if (STATUS_NO_SUCH_DEVICE == res) - return IFD_NO_SUCH_DEVICE; - return IFD_COMMUNICATION_ERROR; - } + CHECK_STATUS(res) length = SIZE_GET_SLOT_STATUS; res = ReadPort(reader_index, &length, buffer); - if (res != STATUS_SUCCESS) - return IFD_COMMUNICATION_ERROR; + CHECK_STATUS(res) if (length < STATUS_OFFSET+1) { @@ -1067,7 +1270,7 @@ if (protocol == T_1) return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length, tx_buffer, rx_length, rx_buffer); - else + else return_value = IFD_PROTOCOL_NOT_SUPPORTED; } break; @@ -1094,7 +1297,7 @@ status_t ret; #ifndef TWIN_SERIAL - if (ICCD_A == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol) { int r; @@ -1112,7 +1315,7 @@ return IFD_SUCCESS; } - if (ICCD_B == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol) { int r; @@ -1147,10 +1350,7 @@ memcpy(cmd+10, tx_buffer, tx_length); ret = WritePort(reader_index, 10+tx_length, cmd); - if (STATUS_NO_SUCH_DEVICE == ret) - return IFD_NO_SUCH_DEVICE; - if (ret != STATUS_SUCCESS) - return IFD_COMMUNICATION_ERROR; + CHECK_STATUS(ret) return IFD_SUCCESS; } /* CCID_Transmit */ @@ -1168,14 +1368,20 @@ unsigned int length; RESPONSECODE return_value = IFD_SUCCESS; status_t ret; - -#ifndef TWIN_SERIAL _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + unsigned int old_timeout; - if (ICCD_A == ccid_descriptor->bInterfaceProtocol) +#ifndef TWIN_SERIAL + if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol) { + unsigned char pcbuffer[SIZE_GET_SLOT_STATUS]; int r; + /* wait for ready */ + r = CmdGetSlotStatus(reader_index, pcbuffer); + if (r != IFD_SUCCESS) + return r; + /* Data Block */ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length); @@ -1192,7 +1398,7 @@ return IFD_SUCCESS; } - if (ICCD_B == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol) { int r; unsigned char rx_tmp[4]; @@ -1283,15 +1489,16 @@ } #endif + /* store the original value of read timeout*/ + old_timeout = ccid_descriptor -> readTimeout; + time_request: length = sizeof(cmd); ret = ReadPort(reader_index, &length, cmd); - if (ret != STATUS_SUCCESS) - { - if (STATUS_NO_SUCH_DEVICE == ret) - return IFD_NO_SUCH_DEVICE; - return IFD_COMMUNICATION_ERROR; - } + + /* restore the original value of read timeout */ + ccid_descriptor -> readTimeout = old_timeout; + CHECK_STATUS(ret) if (length < STATUS_OFFSET+1) { @@ -1341,6 +1548,12 @@ if (cmd[STATUS_OFFSET] & CCID_TIME_EXTENSION) { DEBUG_COMM2("Time extension requested: 0x%02X", cmd[ERROR_OFFSET]); + + /* compute the new value of read timeout */ + if (cmd[ERROR_OFFSET] > 0) + ccid_descriptor -> readTimeout *= cmd[ERROR_OFFSET]; + + DEBUG_COMM2("New timeout: %d ms", ccid_descriptor -> readTimeout); goto time_request; } @@ -1396,7 +1609,7 @@ unsigned int local_rx_length = 0, received_length; int buffer_overflow = 0; - if (ICCD_B == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol) { /* length is on 16-bits only * if a size > 0x1000 is used then usb_control_msg() fails with @@ -1622,14 +1835,15 @@ unsigned int proc_len, int is_rcv) { RESPONSECODE return_value; - unsigned int remain_len; - unsigned char tmp_buf[512]; unsigned int ret_len; DEBUG_COMM2("Enter, is_rcv = %d", is_rcv); if (is_rcv == 1) { /* Receiving mode */ + unsigned int remain_len; + unsigned char tmp_buf[512]; + if (*in_len > 0) { /* There are still available data in our buffer */ if (*in_len >= proc_len) @@ -1795,7 +2009,7 @@ DEBUG_COMM2("T=0: %d bytes", snd_len); - if (ICCD_A == ccid_descriptor->bInterfaceProtocol) + if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol) { unsigned char pcbuffer[SIZE_GET_SLOT_STATUS]; unsigned int backup_len; @@ -1829,6 +2043,7 @@ return return_value; /* wait for ready */ + pcbuffer[0] = 0; return_value = CmdGetSlotStatus(reader_index, pcbuffer); if (return_value != IFD_SUCCESS) return return_value; @@ -2031,6 +2246,7 @@ { unsigned char cmd[10+length]; /* CCID + APDU buffer */ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + status_t res; DEBUG_COMM2("length: %d bytes", length); @@ -2043,12 +2259,12 @@ memcpy(cmd+10, buffer, length); - if (WritePort(reader_index, 10+length, cmd) != STATUS_SUCCESS) - return IFD_COMMUNICATION_ERROR; + res = WritePort(reader_index, 10+length, cmd); + CHECK_STATUS(res) length = sizeof(cmd); - if (ReadPort(reader_index, &length, cmd) != STATUS_SUCCESS) - return IFD_COMMUNICATION_ERROR; + res = ReadPort(reader_index, &length, cmd); + CHECK_STATUS(res) if (length < STATUS_OFFSET+1) { @@ -2097,3 +2313,13 @@ buffer[3] = (value >> 24) & 0xFF; } /* i2dw */ +/***************************************************************************** +* +* bei2i (big endian integer to host order interger) +* +****************************************************************************/ + +static unsigned int bei2i(unsigned char buffer[]) +{ + return (buffer[0]<<24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3]; +} diff -Nru acsccid-1.0.8/src/commands.h acsccid-1.1.0/src/commands.h --- acsccid-1.0.8/src/commands.h 2009-01-06 23:14:35.000000000 +0000 +++ acsccid-1.1.0/src/commands.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,6 +1,6 @@ /* commands.h: Commands sent to the card - Copyright (C) 2003 Ludovic Rousseau + Copyright (C) 2003-2009 Ludovic Rousseau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,7 @@ */ /* - * $Id: commands.h 3270 2009-01-05 14:46:36Z rousseau $ + * $Id: commands.h 6783 2013-10-24 09:36:52Z rousseau $ */ #define SIZE_GET_SLOT_STATUS 10 @@ -39,7 +39,7 @@ RESPONSECODE CmdEscape(unsigned int reader_index, const unsigned char TxBuffer[], unsigned int TxLength, - unsigned char RxBuffer[], unsigned int *RxLength); + unsigned char RxBuffer[], unsigned int *RxLength, unsigned int timeout); RESPONSECODE CmdPowerOff(unsigned int reader_index); diff -Nru acsccid-1.0.8/src/convert_version.pl acsccid-1.1.0/src/convert_version.pl --- acsccid-1.0.8/src/convert_version.pl 2008-11-18 21:48:42.000000000 +0000 +++ acsccid-1.1.0/src/convert_version.pl 2014-12-10 08:32:26.000000000 +0000 @@ -2,7 +2,7 @@ # convert_version.pl: generate a version integer from a version text # -# Copyright (C) 2006 Ludovic Rousseau +# Copyright (C) 2006-2008 Ludovic Rousseau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru acsccid-1.0.8/src/create_Info_plist.pl acsccid-1.1.0/src/create_Info_plist.pl --- acsccid-1.0.8/src/create_Info_plist.pl 2009-07-17 16:15:52.000000000 +0000 +++ acsccid-1.1.0/src/create_Info_plist.pl 2014-12-10 08:32:26.000000000 +0000 @@ -3,7 +3,7 @@ # create_Info_plist.pl: generate Infor.plist from a template and a # list of suported readers # -# Copyright (C) 2004 Ludovic Rousseau +# Copyright (C) 2004-2009 Ludovic Rousseau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,27 +26,22 @@ my (@manuf, @product, @name); my ($manuf, $product, $name); -my $ifdCapabilities = "0x00000000"; my $target = "libccid.so"; my $version = "1.0.0"; -my $bundle = "ifd-ccid.bundle"; my $class = "CFBundleName CCIDCLASSDRIVER"; my $noclass = 0; -GetOptions("ifdCapabilities=s" => \$ifdCapabilities, +GetOptions( "target=s" => \$target, "version=s" => \$version, - "bundle=s" => \$bundle, "no-class" => \$noclass); if ($#ARGV < 1) { print "usage: $0 supported_readers.txt Info.plist - --ifdCapabilities=$ifdCapabilities --target=$target - --version=$version - --bundle=$bundle\n"; + --version=$version\n"; exit; } @@ -61,6 +56,7 @@ # print "m: $manuf, p: $product, n: $name\n"; push @manuf, $manuf; push @product, $product; + $name =~ s/&/&/g; push @name, $name } close IN; @@ -88,12 +84,6 @@ print @name; next; } - if (m/MAGIC_IFDCAPABILITIES/) - { - s/MAGIC_IFDCAPABILITIES/$ifdCapabilities/; - print; - next; - } if (m/MAGIC_TARGET/) { s/MAGIC_TARGET/$target/; @@ -106,12 +96,6 @@ print; next; } - if (m/MAGIC_BUNDLE/) - { - s/MAGIC_BUNDLE/$bundle/; - print; - next; - } if (m/MAGIC_CLASS/) { next if ($noclass); diff -Nru acsccid-1.0.8/src/debug.c acsccid-1.1.0/src/debug.c --- acsccid-1.0.8/src/debug.c 2013-06-12 11:56:24.000000000 +0000 +++ acsccid-1.1.0/src/debug.c 2014-12-10 08:32:26.000000000 +0000 @@ -18,11 +18,12 @@ */ /* - * $Id: debug.c 6646 2013-06-03 08:58:01Z rousseau $ + * $Id: debug.c 6975 2014-09-04 11:33:05Z rousseau $ */ -#include "config.h" +#include +#include "misc.h" #include "debug.h" #include @@ -66,7 +67,7 @@ unsigned int i; /* for each known color terminal */ - for (i = 0; i < sizeof(terms) / sizeof(terms[0]); i++) + for (i = 0; i < COUNT_OF(terms); i++) { /* we found a supported term? */ if (0 == strcmp(terms[i], term)) diff -Nru acsccid-1.0.8/src/debug.h acsccid-1.1.0/src/debug.h --- acsccid-1.0.8/src/debug.h 2011-08-28 15:35:58.000000000 +0000 +++ acsccid-1.1.0/src/debug.h 2014-12-10 08:32:26.000000000 +0000 @@ -18,7 +18,7 @@ */ /* - * $Id: debug.h 5916 2011-08-27 15:50:04Z rousseau $ + * $Id: debug.h 6967 2014-09-02 13:50:50Z rousseau $ */ /* @@ -65,7 +65,7 @@ #define DEBUG_CRITICAL5(fmt, data1, data2, data3, data4) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log5(PCSC_LOG_CRITICAL, fmt, data1, data2, data3, data4) /* DEBUG_INFO */ -#define DEBUG_INFO(fmt) if (LogLevel & DEBUG_LEVEL_INFO) Log1(PCSC_LOG_INFO, fmt) +#define DEBUG_INFO1(fmt) if (LogLevel & DEBUG_LEVEL_INFO) Log1(PCSC_LOG_INFO, fmt) #define DEBUG_INFO2(fmt, data) if (LogLevel & DEBUG_LEVEL_INFO) Log2(PCSC_LOG_INFO, fmt, data) @@ -73,7 +73,9 @@ #define DEBUG_INFO4(fmt, data1, data2, data3) if (LogLevel & DEBUG_LEVEL_INFO) Log4(PCSC_LOG_INFO, fmt, data1, data2, data3) -#define DEBUG_INFO_XXD(msg, buffer, size) if (LogLevel & DEBUG_LEVEL_INFO) log_xxd(PCSC_LOG_INFO, msg, buffer, size) +#define DEBUG_INFO5(fmt, data1, data2, data3, data4) if (LogLevel & DEBUG_LEVEL_INFO) Log5(PCSC_LOG_INFO, fmt, data1, data2, data3, data4) + +#define DEBUG_INFO_XXD(msg, buffer, size) if (LogLevel & DEBUG_LEVEL_INFO) LogXxd(PCSC_LOG_INFO, msg, buffer, size) /* DEBUG_PERIODIC */ #define DEBUG_PERIODIC(fmt) if (LogLevel & DEBUG_LEVEL_PERIODIC) Log1(PCSC_LOG_DEBUG, fmt) @@ -92,7 +94,7 @@ #define DEBUG_COMM4(fmt, data1, data2, data3) if (LogLevel & DEBUG_LEVEL_COMM) Log4(PCSC_LOG_DEBUG, fmt, data1, data2, data3) /* DEBUG_XXD */ -#define DEBUG_XXD(msg, buffer, size) if (LogLevel & DEBUG_LEVEL_COMM) log_xxd(PCSC_LOG_DEBUG, msg, buffer, size) +#define DEBUG_XXD(msg, buffer, size) if (LogLevel & DEBUG_LEVEL_COMM) LogXxd(PCSC_LOG_DEBUG, msg, buffer, size) #endif diff -Nru acsccid-1.0.8/src/defs.h acsccid-1.1.0/src/defs.h --- acsccid-1.0.8/src/defs.h 2012-01-06 06:40:45.000000000 +0000 +++ acsccid-1.1.0/src/defs.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,6 +1,6 @@ /* defs.h: - Copyright (C) 2003 Ludovic Rousseau + Copyright (C) 2003-2010 Ludovic Rousseau Copyright (C) 2011-2012 Advanced Card Systems Ltd. This library is free software; you can redistribute it and/or @@ -19,7 +19,7 @@ */ /* - * $Id: defs.h 4292 2009-07-01 12:28:01Z rousseau $ + * $Id: defs.h 6926 2014-06-17 09:22:00Z rousseau $ */ #include @@ -55,12 +55,12 @@ * ATR */ int nATRLength; - UCHAR pcATRBuffer[MAX_ATR_SIZE]; + unsigned char pcATRBuffer[MAX_ATR_SIZE]; /* * Card state */ - UCHAR bPowerFlags; + unsigned char bPowerFlags; /* * T=1 Protocol context @@ -108,8 +108,19 @@ #define T_0 0 #define T_1 1 -/* Default communication read timeout in seconds */ -#define DEFAULT_COM_READ_TIMEOUT 2 +/* Default communication read timeout in milliseconds */ +#define DEFAULT_COM_READ_TIMEOUT (3*1000) + +/* DWORD type formating */ +#ifdef __APPLE__ +/* Apple defines DWORD as uint32_t */ +#define DWORD_X "%X" +#define DWORD_D "%d" +#else +/* pcsc-lite defines DWORD as unsigned long */ +#define DWORD_X "%lX" +#define DWORD_D "%ld" +#endif /* * communication ports abstraction diff -Nru acsccid-1.0.8/src/ifdhandler.c acsccid-1.1.0/src/ifdhandler.c --- acsccid-1.0.8/src/ifdhandler.c 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/src/ifdhandler.c 2014-12-10 08:32:26.000000000 +0000 @@ -1,6 +1,6 @@ /* ifdhandler.c: IFDH API - Copyright (C) 2003-2009 Ludovic Rousseau + Copyright (C) 2003-2010 Ludovic Rousseau Copyright (C) 2009-2014 Advanced Card Systems Ltd. This library is free software; you can redistribute it and/or @@ -18,13 +18,26 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* $Id: ifdhandler.c 4346 2009-07-28 13:39:37Z rousseau $ */ +/* $Id: ifdhandler.c 6977 2014-09-04 11:36:54Z rousseau $ */ +#include + +#ifdef HAVE_STDIO_H #include +#endif +#ifdef HAVE_STRING_H #include +#endif +#ifdef HAVE_STDLIB_H #include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ARPA_INET_H #include -#include "config.h" +#endif + #include "misc.h" #include #include @@ -40,15 +53,12 @@ #include "towitoko/atr.h" #include "towitoko/pps.h" #include "parser.h" +#include "strlcpycat.h" #ifdef HAVE_PTHREAD #include #endif -#ifndef IFD_ERROR_INSUFFICIENT_BUFFER -#define IFD_ERROR_INSUFFICIENT_BUFFER 618 -#endif - /* Array of structures to hold the ATR and other state value of each slot */ static CcidDesc CcidSlots[CCID_DRIVER_MAX_READERS]; @@ -61,16 +71,13 @@ int DriverOptions = 0; int PowerOnVoltage = VOLTAGE_5V; static int DebugInitialized = FALSE; +int ACSDriverOptions = 0; // Card voltage and card type selection for ACR38U, ACR38U-SAM and SCR21U BYTE ACR38CardVoltage = 0; DWORD ACR38CardType = 0; /* local functions */ -#if HAVE_DECL_TAG_IFD_POLLING_THREAD && !defined(TWIN_SERIAL) && defined(USE_USB_INTERRUPT) -static RESPONSECODE IFDHPolling(DWORD Lun); -static RESPONSECODE IFDHSleep(DWORD Lun); -#endif static void init_driver(void); static void extra_egt(ATR_t *atr, _ccid_descriptor *ccid_desc, DWORD Protocol); static char find_baud_rate(unsigned int baudrate, unsigned int *list); @@ -81,7 +88,8 @@ static int get_IFSC(ATR_t *atr, int *i); -EXTERNAL RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR lpcDevice) +static RESPONSECODE CreateChannelByNameOrChannel(DWORD Lun, + LPSTR lpcDevice, DWORD Channel) { RESPONSECODE return_value = IFD_SUCCESS; int reader_index; @@ -91,7 +99,14 @@ if (! DebugInitialized) init_driver(); - DEBUG_INFO3("lun: %X, device: %s", Lun, lpcDevice); + if (lpcDevice) + { + DEBUG_INFO3("Lun: " DWORD_X ", device: %s", Lun, lpcDevice); + } + else + { + DEBUG_INFO3("Lun: " DWORD_X ", Channel: " DWORD_X, Lun, Channel); + } if (-1 == (reader_index = GetNewReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; @@ -106,13 +121,20 @@ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ; /* reader name */ - CcidSlots[reader_index].readerName = strdup(lpcDevice); + if (lpcDevice) + CcidSlots[reader_index].readerName = strdup(lpcDevice); + else + CcidSlots[reader_index].readerName = strdup("no name"); #ifdef HAVE_PTHREAD (void)pthread_mutex_lock(&ifdh_context_mutex); #endif - ret = OpenPortByName(reader_index, lpcDevice); + if (lpcDevice) + ret = OpenPortByName(reader_index, lpcDevice); + else + ret = OpenPort(reader_index, Channel); + if (ret != STATUS_SUCCESS) { DEBUG_CRITICAL("failed"); @@ -121,15 +143,13 @@ else return_value = IFD_COMMUNICATION_ERROR; - /* release the allocated reader_index */ - ReleaseReaderIndex(reader_index); + goto error; } else { unsigned char pcbuffer[SIZE_GET_SLOT_STATUS]; unsigned int oldReadTimeout; - int readerOk; - int numRetries; + RESPONSECODE cmd_ret; // Assign reader operations if (ccid_descriptor->bInterfaceProtocol == PROTOCOL_ACR38) @@ -168,54 +188,58 @@ /* Maybe we have a special treatment for this reader */ (void)ccid_open_hack_pre(reader_index); - /* save the current read timeout computed from card capabilities */ - oldReadTimeout = ccid_descriptor->readTimeout; - - /* 1 second just to resync the USB toggle bits */ - ccid_descriptor->readTimeout = 1; - /* Try to access the reader */ /* This "warm up" sequence is sometimes needed when pcscd is * restarted with the reader already connected. We get some * "usb_bulk_read: Resource temporarily unavailable" on the first * few tries. It is an empirical hack */ - readerOk = FALSE; - numRetries = 10; - while (numRetries > 0) - { - if (CcidSlots[reader_index].pGetSlotStatus(reader_index, pcbuffer) == IFD_SUCCESS) - { - readerOk = TRUE; - break; - } - numRetries--; + /* The reader may have to start here so give it some time */ + cmd_ret = CcidSlots[reader_index].pGetSlotStatus(reader_index, pcbuffer); + if (IFD_NO_SUCH_DEVICE == cmd_ret) + { + return_value = cmd_ret; + goto error; } - if (!readerOk) + /* save the current read timeout computed from card capabilities */ + oldReadTimeout = ccid_descriptor->readTimeout; + + /* 100 ms just to resync the USB toggle bits */ + ccid_descriptor->readTimeout = 100; + + if ((IFD_COMMUNICATION_ERROR == CcidSlots[reader_index].pGetSlotStatus(reader_index, pcbuffer)) + && (IFD_COMMUNICATION_ERROR == CcidSlots[reader_index].pGetSlotStatus(reader_index, pcbuffer))) { DEBUG_CRITICAL("failed"); return_value = IFD_COMMUNICATION_ERROR; - - /* release the allocated resources */ - (void)ClosePort(reader_index); - ReleaseReaderIndex(reader_index); } else { - /* set back the old timeout */ - ccid_descriptor->readTimeout = oldReadTimeout; - /* Maybe we have a special treatment for this reader */ - (void)ccid_open_hack_post(reader_index); + return_value = ccid_open_hack_post(reader_index); + if (return_value != IFD_SUCCESS) + { + DEBUG_CRITICAL("failed"); + } } + + /* set back the old timeout */ + ccid_descriptor->readTimeout = oldReadTimeout; } +error: #ifdef HAVE_PTHREAD (void)pthread_mutex_unlock(&ifdh_context_mutex); #endif - if (return_value == IFD_SUCCESS) + if (return_value != IFD_SUCCESS) + { + /* release the allocated resources */ + free(CcidSlots[reader_index].readerName); + ReleaseReaderIndex(reader_index); + } + else { DEBUG_INFO2("dwFeatures: 0x%08X", ccid_descriptor->dwFeatures); DEBUG_INFO2("wLcdLayout: 0x%04X", ccid_descriptor->wLcdLayout); @@ -232,9 +256,14 @@ } return return_value; -} /* IFDHCreateChannelByName */ +} /* CreateChannelByNameOrChannel */ +EXTERNAL RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR lpcDevice) +{ + return CreateChannelByNameOrChannel(Lun, lpcDevice, -1); +} + EXTERNAL RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel) { /* @@ -270,150 +299,7 @@ * * IFD_SUCCESS IFD_COMMUNICATION_ERROR */ - RESPONSECODE return_value = IFD_SUCCESS; - _ccid_descriptor *ccid_descriptor; - int reader_index; - - if (! DebugInitialized) - init_driver(); - - DEBUG_INFO2("lun: %X", Lun); - - if (-1 == (reader_index = GetNewReaderIndex(Lun))) - return IFD_COMMUNICATION_ERROR; - - ccid_descriptor = get_ccid_descriptor(reader_index); - - /* Reset ATR buffer */ - CcidSlots[reader_index].nATRLength = 0; - *CcidSlots[reader_index].pcATRBuffer = '\0'; - - /* Reset PowerFlags */ - CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ; - - /* reader name */ - CcidSlots[reader_index].readerName = strdup("no name"); - -#ifdef HAVE_PTHREAD - (void)pthread_mutex_lock(&ifdh_context_mutex); -#endif - - if (OpenPort(reader_index, Channel) != STATUS_SUCCESS) - { - DEBUG_CRITICAL("failed"); - return_value = IFD_COMMUNICATION_ERROR; - - /* release the allocated reader_index */ - ReleaseReaderIndex(reader_index); - } - else - { - unsigned char pcbuffer[SIZE_GET_SLOT_STATUS]; - unsigned int oldReadTimeout; - int readerOk; - int numRetries; - - // Assign reader operations - if (ccid_descriptor->bInterfaceProtocol == PROTOCOL_ACR38) - { - // ACR38 reader - CcidSlots[reader_index].pPowerOn = ACR38_CmdPowerOn; - CcidSlots[reader_index].pPowerOff = ACR38_CmdPowerOff; - CcidSlots[reader_index].pGetSlotStatus = ACR38_CmdGetSlotStatus; - CcidSlots[reader_index].pXfrBlock = ACR38_CmdXfrBlock; - CcidSlots[reader_index].pTransmitT1 = ACR38_TransmitT1; - CcidSlots[reader_index].pTransmitPPS = ACR38_TransmitPPS; - CcidSlots[reader_index].pReceive = ACR38_Receive; - CcidSlots[reader_index].pSetParameters = ACR38_SetParameters; - - // Set card voltage - (void)ACR38_SetCardVoltage(reader_index, (unsigned char *) &ACR38CardVoltage, - sizeof(ACR38CardVoltage), NULL, NULL); - - // Set card type - (void)ACR38_SetCardType(reader_index, (unsigned char *) &ACR38CardType, - sizeof(ACR38CardType), NULL, NULL); - } - else - { - // CCID reader - CcidSlots[reader_index].pPowerOn = CmdPowerOn; - CcidSlots[reader_index].pPowerOff = CmdPowerOff; - CcidSlots[reader_index].pGetSlotStatus = CmdGetSlotStatus; - CcidSlots[reader_index].pXfrBlock = CmdXfrBlock; - CcidSlots[reader_index].pTransmitT1 = CCID_Transmit; - CcidSlots[reader_index].pTransmitPPS = CCID_Transmit; - CcidSlots[reader_index].pReceive = CCID_Receive; - CcidSlots[reader_index].pSetParameters = SetParameters; - } - - /* Maybe we have a special treatment for this reader */ - (void)ccid_open_hack_pre(reader_index); - - /* save the current read timeout computed from card capabilities */ - oldReadTimeout = ccid_descriptor->readTimeout; - - /* 1 second just to resync the USB toggle bits */ - ccid_descriptor->readTimeout = 1; - - /* Try to access the reader */ - /* This "warm up" sequence is sometimes needed when pcscd is - * restarted with the reader already connected. We get some - * "usb_bulk_read: Resource temporarily unavailable" on the first - * few tries. It is an empirical hack */ - readerOk = FALSE; - numRetries = 10; - while (numRetries > 0) - { - if (CcidSlots[reader_index].pGetSlotStatus(reader_index, pcbuffer) == IFD_SUCCESS) - { - readerOk = TRUE; - break; - } - - numRetries--; - } - - if (!readerOk) - { - DEBUG_CRITICAL("failed"); - return_value = IFD_COMMUNICATION_ERROR; - - /* release the allocated resources */ - (void)ClosePort(reader_index); - ReleaseReaderIndex(reader_index); - } - else - { - /* set back the old timeout */ - ccid_descriptor->readTimeout = oldReadTimeout; - - /* Maybe we have a special treatment for this reader */ - (void)ccid_open_hack_post(reader_index); - } - } - -#ifdef HAVE_PTHREAD - (void)pthread_mutex_unlock(&ifdh_context_mutex); -#endif - - if (return_value == IFD_SUCCESS) - { - DEBUG_INFO2("dwFeatures: 0x%08X", ccid_descriptor->dwFeatures); - DEBUG_INFO2("wLcdLayout: 0x%04X", ccid_descriptor->wLcdLayout); - DEBUG_INFO2("bPINSupport: 0x%02X", ccid_descriptor->bPINSupport); - DEBUG_INFO2("dwMaxCCIDMessageLength: %d", ccid_descriptor->dwMaxCCIDMessageLength); - DEBUG_INFO2("dwMaxIFSD: %d", ccid_descriptor->dwMaxIFSD); - DEBUG_INFO2("dwDefaultClock: %d", ccid_descriptor->dwDefaultClock); - DEBUG_INFO2("dwMaxDataRate: %d", ccid_descriptor->dwMaxDataRate); - DEBUG_INFO2("bMaxSlotIndex: %d", ccid_descriptor->bMaxSlotIndex); - DEBUG_INFO2("bCurrentSlotIndex: %d", ccid_descriptor->bCurrentSlotIndex); - DEBUG_INFO2("bInterfaceProtocol: 0x%02X", ccid_descriptor->bInterfaceProtocol); - DEBUG_INFO2("bNumEndpoints: %d", ccid_descriptor->bNumEndpoints); - DEBUG_INFO2("bVoltageSupport: 0x%02X", ccid_descriptor->bVoltageSupport); - } - - return return_value; + return CreateChannelByNameOrChannel(Lun, NULL, Channel); } /* IFDHCreateChannel */ @@ -434,7 +320,8 @@ if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; - DEBUG_INFO3("%s (lun: %X)", CcidSlots[reader_index].readerName, Lun); + DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName, + Lun); /* Restore the default timeout * No need to wait too long if the reader disapeared */ @@ -461,37 +348,33 @@ } /* IFDHCloseChannel */ -#if HAVE_DECL_TAG_IFD_POLLING_THREAD && !defined(TWIN_SERIAL) && defined(USE_USB_INTERRUPT) -static RESPONSECODE IFDHPolling(DWORD Lun) +#if !defined(TWIN_SERIAL) +static RESPONSECODE IFDHPolling(DWORD Lun, int timeout) { int reader_index; - int ret; if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; /* log only if DEBUG_LEVEL_PERIODIC is set */ if (LogLevel & DEBUG_LEVEL_PERIODIC) - DEBUG_INFO3("%s (lun: %X)", CcidSlots[reader_index].readerName, Lun); + DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms", + CcidSlots[reader_index].readerName, Lun, timeout); - ret = InterruptRead(reader_index, 2*1000); /* 2 seconds */ - if (ret > 0) - return IFD_SUCCESS; - if (0 == ret) - return IFD_NO_SUCH_DEVICE; - return IFD_COMMUNICATION_ERROR; + return InterruptRead(reader_index, timeout); } /* on an ICCD device the card is always inserted * so no card movement will ever happen: just do nothing */ -static RESPONSECODE IFDHSleep(DWORD Lun) +static RESPONSECODE IFDHSleep(DWORD Lun, int timeout) { int reader_index; if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; - DEBUG_INFO3("%s (lun: %X)", CcidSlots[reader_index].readerName, Lun); + DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms", + CcidSlots[reader_index].readerName, Lun, timeout); /* just sleep for 5 seconds since the polling thread is NOT killable * so pcscd event thread must loop to exit cleanly @@ -500,7 +383,21 @@ * TAG_IFD_POLLING_THREAD_KILLABLE then we could use a much longer delay * and be killed before pcscd exits */ - (void)sleep(600); /* 10 minutes */ + (void)usleep(timeout); + return IFD_SUCCESS; +} + +static RESPONSECODE IFDHStopPolling(DWORD Lun) +{ + int reader_index; + + if (-1 == (reader_index = LunToReaderIndex(Lun))) + return IFD_COMMUNICATION_ERROR; + + DEBUG_INFO3("%s (lun: " DWORD_X ")", + CcidSlots[reader_index].readerName, Lun); + + (void)InterruptStop(reader_index); return IFD_SUCCESS; } #endif @@ -532,7 +429,7 @@ if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; - DEBUG_INFO4("tag: 0x%X, %s (lun: %X)", Tag, + DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag, CcidSlots[reader_index].readerName, Lun); switch (Tag) @@ -647,19 +544,33 @@ break; case SCARD_ATTR_VENDOR_IFD_VERSION: - /* Vendor-supplied interface device version (DWORD in the form - * 0xMMmmbbbb where MM = major version, mm = minor version, and - * bbbb = build number). */ - *Length = sizeof(DWORD); - if (Value) - *(DWORD *)Value = CCID_VERSION; + { + int IFD_bcdDevice = get_ccid_descriptor(reader_index)->IFD_bcdDevice; + + /* Vendor-supplied interface device version (DWORD in the form + * 0xMMmmbbbb where MM = major version, mm = minor version, and + * bbbb = build number). */ + *Length = 4; + if (Value) + *(uint32_t *)Value = IFD_bcdDevice << 16; + } break; case SCARD_ATTR_VENDOR_NAME: -#define VENDOR_NAME "Ludovic Rousseau" - *Length = sizeof(VENDOR_NAME); - if (Value) - memcpy(Value, VENDOR_NAME, sizeof(VENDOR_NAME)); + { + const char *sIFD_iManufacturer = get_ccid_descriptor(reader_index) -> sIFD_iManufacturer; + + if (sIFD_iManufacturer) + { + strlcpy((char *)Value, sIFD_iManufacturer, *Length); + *Length = strlen((char *)Value) +1; + } + else + { + /* not supported */ + *Length = 0; + } + } break; case SCARD_ATTR_MAXINPUT: @@ -668,8 +579,8 @@ *(uint32_t *)Value = get_ccid_descriptor(reader_index) -> dwMaxCCIDMessageLength -10; break; -#if HAVE_DECL_TAG_IFD_POLLING_THREAD && !defined(TWIN_SERIAL) && defined(USE_USB_INTERRUPT) - case TAG_IFD_POLLING_THREAD: +#if !defined(TWIN_SERIAL) + case TAG_IFD_POLLING_THREAD_WITH_TIMEOUT: { _ccid_descriptor *ccid_desc; @@ -677,8 +588,10 @@ *Length = 0; ccid_desc = get_ccid_descriptor(reader_index); + /* CCID and not ICCD */ - if ((0 == ccid_desc -> bInterfaceProtocol) + if (((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol) + || (PROTOCOL_ACR38 == ccid_desc -> bInterfaceProtocol)) /* 3 end points */ && (3 == ccid_desc -> bNumEndpoints)) { @@ -687,8 +600,8 @@ *(void **)Value = IFDHPolling; } - if ((ICCD_A == ccid_desc->bInterfaceProtocol) - || (ICCD_B == ccid_desc->bInterfaceProtocol)) + if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol) + || (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol)) { *Length = sizeof(void *); if (Value) @@ -705,8 +618,8 @@ *Length = 0; ccid_desc = get_ccid_descriptor(reader_index); - if ((ICCD_A == ccid_desc->bInterfaceProtocol) - || (ICCD_B == ccid_desc->bInterfaceProtocol)) + if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol) + || (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol)) { *Length = 1; /* 1 char */ if (Value) @@ -714,8 +627,47 @@ } } break; + + case TAG_IFD_STOP_POLLING_THREAD: + { + _ccid_descriptor *ccid_desc; + + /* default value: not supported */ + *Length = 0; + + ccid_desc = get_ccid_descriptor(reader_index); + /* CCID and not ICCD */ + if (((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol) + || (PROTOCOL_ACR38 == ccid_desc -> bInterfaceProtocol)) + /* 3 end points */ + && (3 == ccid_desc -> bNumEndpoints)) + { + *Length = sizeof(void *); + if (Value) + *(void **)Value = IFDHStopPolling; + } + } + break; #endif + case SCARD_ATTR_VENDOR_IFD_SERIAL_NO: + { + _ccid_descriptor *ccid_desc; + + ccid_desc = get_ccid_descriptor(reader_index); + if (ccid_desc->sIFD_serial_number) + { + strlcpy((char *)Value, ccid_desc->sIFD_serial_number, *Length); + *Length = strlen((char *)Value); + } + else + { + /* not supported */ + *Length = 0; + } + } + break; + default: return_value = IFD_ERROR_TAG; } @@ -752,7 +704,7 @@ if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; - DEBUG_INFO4("tag: 0x%X, %s (lun: %X)", Tag, + DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag, CcidSlots[reader_index].readerName, Lun); return IFD_NOT_SUPPORTED; @@ -786,6 +738,7 @@ unsigned int len; int convention; int reader_index; + int atr_ret; BYTE Fl; BYTE Dl; @@ -805,8 +758,8 @@ if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; - DEBUG_INFO4("protocol T=%d, %s (lun: %X)", Protocol-SCARD_PROTOCOL_T0, - CcidSlots[reader_index].readerName, Lun); + DEBUG_INFO4("protocol T=" DWORD_D ", %s (lun: " DWORD_X ")", + Protocol-SCARD_PROTOCOL_T0, CcidSlots[reader_index].readerName, Lun); /* Set to zero buffer */ memset(pps, 0, sizeof(pps)); @@ -819,11 +772,16 @@ /* Do not send CCID command SetParameters or PPS to the CCID * The CCID will do this himself */ if (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_PROP) + { + DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout); goto end; + } /* Get ATR of the card */ - (void)ATR_InitFromArray(&atr, ccid_slot->pcATRBuffer, + atr_ret = ATR_InitFromArray(&atr, ccid_slot->pcATRBuffer, ccid_slot->nATRLength); + if (ATR_MALFORMED == atr_ret) + return IFD_PROTOCOL_NOT_SUPPORTED; /* Apply Extra EGT patch for bogus cards */ extra_egt(&atr, ccid_desc, Protocol); @@ -880,7 +838,7 @@ // Check if card supports this protocol (Mac OS X) if (!(protocolTypes & Protocol)) { - DEBUG_COMM2("T=%d not supported", Protocol-SCARD_PROTOCOL_T0); + DEBUG_COMM2("T=" DWORD_D " not supported", Protocol-SCARD_PROTOCOL_T0); return IFD_ERROR_PTS_FAILURE; } @@ -987,12 +945,12 @@ ccid_desc->dwDefaultClock * d / f); /* the reader has no baud rates table */ - if ((ccid_desc->arrayOfSupportedDataRates == NULL) && - (card_baudrate <= ccid_desc->dwMaxDataRate) + if (((ccid_desc->arrayOfSupportedDataRates == NULL) + && (card_baudrate <= ccid_desc->dwMaxDataRate)) /* or explicitely support it */ - || (ccid_desc->arrayOfSupportedDataRates != NULL) && - find_baud_rate(card_baudrate, - ccid_desc->arrayOfSupportedDataRates)) + || ((ccid_desc->arrayOfSupportedDataRates != NULL) + && find_baud_rate(card_baudrate, + ccid_desc->arrayOfSupportedDataRates))) { pps[1] |= 0x10; /* PTS1 presence */ pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value; @@ -1034,8 +992,7 @@ { int default_protocol; - if (ATR_MALFORMED == ATR_GetDefaultProtocol(&atr, &default_protocol)) - return IFD_PROTOCOL_NOT_SUPPORTED; + ATR_GetDefaultProtocol(&atr, &default_protocol, NULL); /* if the requested protocol is not the default one * or a TA1/PPS1 is present */ @@ -1048,15 +1005,15 @@ { /* convert from ATR_PROTOCOL_TYPE_T? to SCARD_PROTOCOL_T? */ Protocol = default_protocol + - (SCARD_PROTOCOL_T0 - ATR_PROTOCOL_TYPE_T0); - DEBUG_INFO2("PPS not supported on O2Micro readers. Using T=%d", + (SCARD_PROTOCOL_T0 - ATR_PROTOCOL_TYPE_T0); + DEBUG_INFO2("PPS not supported on O2Micro readers. Using T=" DWORD_D, Protocol - SCARD_PROTOCOL_T0); } else #endif if (PPS_Exchange(reader_index, pps, &len, &pps1) != PPS_OK) { - DEBUG_INFO("PPS_Exchange Failed"); + DEBUG_INFO1("PPS_Exchange Failed"); if (pps[2] != 0x11) { @@ -1166,12 +1123,12 @@ param[5] = ifsc; } - DEBUG_COMM2("Timeout: %d seconds", ccid_desc->readTimeout); + DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout); ret = ccid_slot->pSetParameters(reader_index, 1, sizeof(param), param); if (IFD_SUCCESS != ret) { - DEBUG_INFO("SetParameters (T1) Failed"); + DEBUG_INFO1("SetParameters (T1) Failed"); if (param[0] != 0x11) { @@ -1227,13 +1184,12 @@ ccid_desc->readTimeout = T0_card_timeout(f, d, param[2] /* TC1 */, param[3] /* TC2 */, ccid_desc->dwDefaultClock); - DEBUG_COMM2("Communication timeout: %d seconds", - ccid_desc->readTimeout); + DEBUG_COMM2("Communication timeout: %d ms", ccid_desc->readTimeout); ret = ccid_slot->pSetParameters(reader_index, 0, sizeof(param), param); if (IFD_SUCCESS != ret) { - DEBUG_INFO("SetParameters (T0) Failed"); + DEBUG_INFO1("SetParameters (T0) Failed"); if (param[0] != 0x11) { @@ -1335,7 +1291,9 @@ RESPONSECODE return_value = IFD_SUCCESS; unsigned char pcbuffer[10+MAX_ATR_SIZE]; int reader_index; +#ifndef NO_LOG const char *actions[] = { "PowerUp", "PowerDown", "Reset" }; +#endif unsigned int oldReadTimeout; _ccid_descriptor *ccid_descriptor; @@ -1345,8 +1303,8 @@ if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; - DEBUG_INFO4("action: %s, %s (lun: %X)", actions[Action-IFD_POWER_UP], - CcidSlots[reader_index].readerName, Lun); + DEBUG_INFO4("action: %s, %s (lun: " DWORD_X ")", + actions[Action-IFD_POWER_UP], CcidSlots[reader_index].readerName, Lun); switch (Action) { @@ -1376,6 +1334,19 @@ ccid_descriptor = get_ccid_descriptor(reader_index); oldReadTimeout = ccid_descriptor->readTimeout; + /* The German eID card is bogus and need to be powered off + * before a power on */ + if (KOBIL_IDTOKEN == ccid_descriptor -> readerID) + { + /* send the command */ + if (IFD_SUCCESS != CmdPowerOff(reader_index)) + { + DEBUG_CRITICAL("PowerDown failed"); + return_value = IFD_ERROR_POWER_ACTION; + goto end; + } + } + /* use a very long timeout since the card can use up to * (9600+12)*33 ETU in total * 12 ETU per byte @@ -1384,7 +1355,7 @@ * 1 ETU = 372 cycles during ATR * with a 4 MHz clock => 29 seconds */ - ccid_descriptor->readTimeout = 10; // 60 seconds is too long + ccid_descriptor->readTimeout = 10*1000; // 60 seconds is too long nlength = sizeof(pcbuffer); return_value = CcidSlots[reader_index].pPowerOn(reader_index, &nlength, pcbuffer, @@ -1399,12 +1370,12 @@ } // Enable/Disable PICC - if (DriverOptions & DRIVER_OPTION_DISABLE_PICC) + if (ACSDriverOptions & ACS_DRIVER_OPTION_DISABLE_PICC) { if ((ccid_descriptor->firmwareFixEnabled) && - (((ccid_descriptor->readerID == ACS_ACR1222_DUAL_READER) || + ((((ccid_descriptor->readerID == ACS_ACR1222_DUAL_READER) || (ccid_descriptor->readerID == ACS_ACR1222_1SAM_DUAL_READER)) && - (ccid_descriptor->bCurrentSlotIndex == 0) || + (ccid_descriptor->bCurrentSlotIndex == 0)) || (ccid_descriptor->readerID == ACS_ACR85_PINPAD_READER_ICC))) { int i = 0; @@ -1431,8 +1402,9 @@ if ((return_value != IFD_SUCCESS) || (nlength == 0)) // ACR1222: No ATR is returned { /* used by GemCore SIM PRO: no card is present */ - get_ccid_descriptor(reader_index)->dwSlotStatus - = IFD_ICC_NOT_PRESENT;; + if (GEMCORESIMPRO == ccid_descriptor -> readerID) + get_ccid_descriptor(reader_index)->dwSlotStatus + = IFD_ICC_NOT_PRESENT; DEBUG_CRITICAL("PowerUp failed"); return_value = IFD_ERROR_POWER_ACTION; @@ -1440,12 +1412,12 @@ } // Remove PUPI from ATR - if (DriverOptions & DRIVER_OPTION_REMOVE_PUPI_FROM_ATR) + if (ACSDriverOptions & ACS_DRIVER_OPTION_REMOVE_PUPI_FROM_ATR) { if ((ccid_descriptor->firmwareFixEnabled) && - (((ccid_descriptor->readerID == ACS_ACR1222_DUAL_READER) || + ((((ccid_descriptor->readerID == ACS_ACR1222_DUAL_READER) || (ccid_descriptor->readerID == ACS_ACR1222_1SAM_DUAL_READER)) && - (ccid_descriptor->bCurrentSlotIndex == 1) || + (ccid_descriptor->bCurrentSlotIndex == 1)) || (ccid_descriptor->readerID == ACS_ACR85_PINPAD_READER_PICC))) { // ATR: 3B 8N 80 01 50 XX XX XX XX ... TCK @@ -1552,7 +1524,6 @@ RESPONSECODE return_value; unsigned int rx_length; int reader_index; - int slot_index; _ccid_descriptor *ccid_descriptor; unsigned char pcbuffer[SIZE_GET_SLOT_STATUS]; @@ -1561,10 +1532,61 @@ if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; - DEBUG_INFO3("%s (lun: %X)", CcidSlots[reader_index].readerName, Lun); + DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName, + Lun); + + /* special APDU for the Kobil IDToken (CLASS = 0xFF) */ + if (KOBIL_IDTOKEN == get_ccid_descriptor(reader_index) -> readerID) + { + char manufacturer[] = {0xFF, 0x9A, 0x01, 0x01, 0x00}; + char product_name[] = {0xFF, 0x9A, 0x01, 0x03, 0x00}; + char firmware_version[] = {0xFF, 0x9A, 0x01, 0x06, 0x00}; + char driver_version[] = {0xFF, 0x9A, 0x01, 0x07, 0x00}; + + if ((sizeof manufacturer == TxLength) + && (memcmp(TxBuffer, manufacturer, sizeof manufacturer) == 0)) + { + DEBUG_INFO1("IDToken: Manufacturer command"); + memcpy(RxBuffer, "KOBIL systems\220\0", 15); + *RxLength = 15; + return IFD_SUCCESS; + } + + if ((sizeof product_name == TxLength) + && (memcmp(TxBuffer, product_name, sizeof product_name) == 0)) + { + DEBUG_INFO1("IDToken: Product name command"); + memcpy(RxBuffer, "IDToken\220\0", 9); + *RxLength = 9; + return IFD_SUCCESS; + } + + if ((sizeof firmware_version == TxLength) + && (memcmp(TxBuffer, firmware_version, sizeof firmware_version) == 0)) + { + int IFD_bcdDevice = get_ccid_descriptor(reader_index)->IFD_bcdDevice; + + DEBUG_INFO1("IDToken: Firmware version command"); + *RxLength = sprintf((char *)RxBuffer, "%X.%02X", + IFD_bcdDevice >> 8, IFD_bcdDevice & 0xFF); + RxBuffer[(*RxLength)++] = 0x90; + RxBuffer[(*RxLength)++] = 0x00; + return IFD_SUCCESS; + } + + if ((sizeof driver_version == TxLength) + && (memcmp(TxBuffer, driver_version, sizeof driver_version) == 0)) + { + DEBUG_INFO1("IDToken: Driver version command"); +#define DRIVER_VERSION "2012.2.7\220\0" + memcpy(RxBuffer, DRIVER_VERSION, sizeof DRIVER_VERSION -1); + *RxLength = sizeof DRIVER_VERSION -1; + return IFD_SUCCESS; + } + + } ccid_descriptor = get_ccid_descriptor(reader_index); - slot_index = ccid_descriptor->bCurrentSlotIndex; // Fix reader hang problem by checking card status of ACR85 PICC before exchanging APDU if ((ccid_descriptor->readerID == ACS_ACR85_PINPAD_READER_PICC) && @@ -1703,7 +1725,6 @@ */ RESPONSECODE return_value = IFD_ERROR_NOT_SUPPORTED; int reader_index; - int old_read_timeout; _ccid_descriptor *ccid_descriptor; reader_index = LunToReaderIndex(Lun); @@ -1712,245 +1733,510 @@ ccid_descriptor = get_ccid_descriptor(reader_index); - DEBUG_INFO4("ControlCode: 0x%X, %s (lun: %X)", dwControlCode, - CcidSlots[reader_index].readerName, Lun); + DEBUG_INFO4("ControlCode: 0x" DWORD_X ", %s (lun: " DWORD_X ")", + dwControlCode, CcidSlots[reader_index].readerName, Lun); DEBUG_INFO_XXD("Control TxBuffer: ", TxBuffer, TxLength); /* Set the return length to 0 to avoid problems */ *pdwBytesReturned = 0; - if (ccid_descriptor->bInterfaceProtocol == PROTOCOL_ACR38) + // ACR38U, ACR38U-SAM and SCR21U specific I/O controls + if ((ACS_ACR38U == ccid_descriptor -> readerID) || + (ACS_ACR38U_SAM == ccid_descriptor -> readerID) || + (IRIS_SCR21U == ccid_descriptor -> readerID) || + (ACS_AET65_1SAM_ICC_READER == ccid_descriptor -> readerID)) { - // ACR38U, ACR38U-SAM and SCR21U specific I/O controls - if ((ACS_ACR38U == ccid_descriptor -> readerID) || - (ACS_ACR38U_SAM == ccid_descriptor -> readerID) || - (IRIS_SCR21U == ccid_descriptor -> readerID) || - (ACS_AET65_1SAM_ICC_READER == ccid_descriptor -> readerID)) + // Set card voltage + if (IOCTL_SMARTCARD_SET_CARD_VOLTAGE == dwControlCode) { - // Set card voltage - if (IOCTL_SMARTCARD_SET_CARD_VOLTAGE == dwControlCode) - { - unsigned int iBytesReturned; + unsigned int iBytesReturned; - iBytesReturned = RxLength; - return_value = ACR38_SetCardVoltage(reader_index, TxBuffer, TxLength, - RxBuffer, &iBytesReturned); - *pdwBytesReturned = iBytesReturned; - } + iBytesReturned = RxLength; + return_value = ACR38_SetCardVoltage(reader_index, TxBuffer, TxLength, + RxBuffer, &iBytesReturned); + *pdwBytesReturned = iBytesReturned; + } - // Set card type - if (IOCTL_SMARTCARD_SET_CARD_TYPE == dwControlCode) - { - unsigned int iBytesReturned; + // Set card type + if (IOCTL_SMARTCARD_SET_CARD_TYPE == dwControlCode) + { + unsigned int iBytesReturned; - iBytesReturned = RxLength; - return_value = ACR38_SetCardType(reader_index, TxBuffer, TxLength, - RxBuffer, &iBytesReturned); - *pdwBytesReturned = iBytesReturned; - } + iBytesReturned = RxLength; + return_value = ACR38_SetCardType(reader_index, TxBuffer, TxLength, + RxBuffer, &iBytesReturned); + *pdwBytesReturned = iBytesReturned; } + + goto err; } - else + + if (IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE == dwControlCode) { - if (IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE == dwControlCode) + int allowed = (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED); + int readerID = ccid_descriptor -> readerID; + + if (VENDOR_GEMALTO == GET_VENDOR(readerID)) { - if (FALSE == (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED)) - { - DEBUG_INFO("ifd exchange (Escape command) not allowed"); - return_value = IFD_COMMUNICATION_ERROR; - } - else - { - unsigned int iBytesReturned; + unsigned char switch_interface[] = { 0x52, 0xF8, 0x04, 0x01, 0x00 }; - iBytesReturned = RxLength; - old_read_timeout = ccid_descriptor -> readTimeout; - ccid_descriptor -> readTimeout = 0; // Infinite - return_value = CmdEscape(reader_index, TxBuffer, TxLength, RxBuffer, - &iBytesReturned); - ccid_descriptor -> readTimeout = old_read_timeout; - *pdwBytesReturned = iBytesReturned; - } - } + /* get firmware version escape command */ + if ((1 == TxLength) && (0x02 == TxBuffer[0])) + allowed = TRUE; - /* Implement the PC/SC v2.02.05 Part 10 IOCTL mechanism */ + /* switch interface escape command on the GemProx DU + * the next byte in the command is the interface: + * 0x01 switch to contactless interface + * 0x02 switch to contact interface + */ + if ((GEMALTOPROXDU == readerID) + && (6 == TxLength) + && (0 == memcmp(TxBuffer, switch_interface, sizeof(switch_interface)))) + allowed = TRUE; + } - /* Query for features */ - if (CM_IOCTL_GET_FEATURE_REQUEST == dwControlCode) + if (!allowed) + { + DEBUG_INFO1("ifd exchange (Escape command) not allowed"); + return_value = IFD_COMMUNICATION_ERROR; + } + else { - unsigned int iBytesReturned = 0; - PCSC_TLV_STRUCTURE *pcsc_tlv = (PCSC_TLV_STRUCTURE *)RxBuffer; + unsigned int iBytesReturned; - /* we need room for up to for records */ - if (RxLength < 4 * sizeof(PCSC_TLV_STRUCTURE)) - return IFD_COMMUNICATION_ERROR; + iBytesReturned = RxLength; + /* 30 seconds timeout for long commands */ + return_value = CmdEscape(reader_index, TxBuffer, TxLength, + RxBuffer, &iBytesReturned, 30*1000); + *pdwBytesReturned = iBytesReturned; + } + } - /* We can only support direct verify and/or modify currently */ - if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_VERIFY) - { - pcsc_tlv -> tag = FEATURE_VERIFY_PIN_DIRECT; - pcsc_tlv -> length = 0x04; /* always 0x04 */ - pcsc_tlv -> value = htonl(IOCTL_FEATURE_VERIFY_PIN_DIRECT); + /* Implement the PC/SC v2.02.07 Part 10 IOCTL mechanism */ - pcsc_tlv++; - iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); - } + /* Query for features */ + /* 0x313520 is the Windows value for SCARD_CTL_CODE(3400) + * This hack is needed for RDP applications */ + if ((CM_IOCTL_GET_FEATURE_REQUEST == dwControlCode) + || (0x313520 == dwControlCode)) + { + unsigned int iBytesReturned = 0; + PCSC_TLV_STRUCTURE *pcsc_tlv = (PCSC_TLV_STRUCTURE *)RxBuffer; + int readerID = ccid_descriptor -> readerID; + + /* we need room for up to five records */ + if (RxLength < 7 * sizeof(PCSC_TLV_STRUCTURE)) + return IFD_ERROR_INSUFFICIENT_BUFFER; - if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_MODIFY) - { - pcsc_tlv -> tag = FEATURE_MODIFY_PIN_DIRECT; - pcsc_tlv -> length = 0x04; /* always 0x04 */ - pcsc_tlv -> value = htonl(IOCTL_FEATURE_MODIFY_PIN_DIRECT); + /* We can only support direct verify and/or modify currently */ + if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_VERIFY) + { + pcsc_tlv -> tag = FEATURE_VERIFY_PIN_DIRECT; + pcsc_tlv -> length = 0x04; /* always 0x04 */ + pcsc_tlv -> value = htonl(IOCTL_FEATURE_VERIFY_PIN_DIRECT); - pcsc_tlv++; - iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); - } + pcsc_tlv++; + iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); + } + + if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_MODIFY) + { + pcsc_tlv -> tag = FEATURE_MODIFY_PIN_DIRECT; + pcsc_tlv -> length = 0x04; /* always 0x04 */ + pcsc_tlv -> value = htonl(IOCTL_FEATURE_MODIFY_PIN_DIRECT); + + pcsc_tlv++; + iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); + } -#ifdef FEATURE_IFD_PIN_PROPERTIES - /* We can always forward wLcdLayout */ + /* Provide IFD_PIN_PROPERTIES only for pinpad readers */ + if (ccid_descriptor -> bPINSupport) + { pcsc_tlv -> tag = FEATURE_IFD_PIN_PROPERTIES; pcsc_tlv -> length = 0x04; /* always 0x04 */ pcsc_tlv -> value = htonl(IOCTL_FEATURE_IFD_PIN_PROPERTIES); pcsc_tlv++; iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); -#endif + } - if (KOBIL_TRIBANK == ccid_descriptor -> readerID) - { - pcsc_tlv -> tag = FEATURE_MCT_READERDIRECT; - pcsc_tlv -> length = 0x04; /* always 0x04 */ - pcsc_tlv -> value = htonl(IOCTL_FEATURE_MCT_READERDIRECT); + if ((KOBIL_TRIBANK == readerID) + || (KOBIL_MIDENTITY_VISUAL == readerID)) + { + pcsc_tlv -> tag = FEATURE_MCT_READER_DIRECT; + pcsc_tlv -> length = 0x04; /* always 0x04 */ + pcsc_tlv -> value = htonl(IOCTL_FEATURE_MCT_READER_DIRECT); - pcsc_tlv++; - iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); - } + pcsc_tlv++; + iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); + } - // APG8201Z supports vendor specific feature - if (ACS_APG8201Z == ccid_descriptor -> readerID) - { - pcsc_tlv -> tag = 0x80; - pcsc_tlv -> length = 0x04; /* always 0x04 */ - pcsc_tlv -> value = 0; + pcsc_tlv -> tag = FEATURE_GET_TLV_PROPERTIES; + pcsc_tlv -> length = 0x04; /* always 0x04 */ + pcsc_tlv -> value = htonl(IOCTL_FEATURE_GET_TLV_PROPERTIES); + pcsc_tlv++; + iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); + + /* IOCTL_CCID_ESCAPE */ + pcsc_tlv -> tag = FEATURE_CCID_ESC_COMMAND; + pcsc_tlv -> length = 0x04; /* always 0x04 */ + pcsc_tlv -> value = htonl(IOCTL_CCID_ESCAPE); + pcsc_tlv++; + iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); - pcsc_tlv++; - iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); - } + // APG8201Z supports vendor specific feature + if (ACS_APG8201Z == ccid_descriptor -> readerID) + { + pcsc_tlv -> tag = 0x80; + pcsc_tlv -> length = 0x04; /* always 0x04 */ + pcsc_tlv -> value = 0; - *pdwBytesReturned = iBytesReturned; - return_value = IFD_SUCCESS; + pcsc_tlv++; + iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); } -#ifdef FEATURE_IFD_PIN_PROPERTIES - /* Get PIN handling capabilities */ - if (IOCTL_FEATURE_IFD_PIN_PROPERTIES == dwControlCode) + *pdwBytesReturned = iBytesReturned; + return_value = IFD_SUCCESS; + } + + /* Get PIN handling capabilities */ + if (IOCTL_FEATURE_IFD_PIN_PROPERTIES == dwControlCode) + { + PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)RxBuffer; + int validation; + + if (RxLength < sizeof(PIN_PROPERTIES_STRUCTURE)) + return IFD_ERROR_INSUFFICIENT_BUFFER; + + /* Only give the LCD size for now */ + caps -> wLcdLayout = ccid_descriptor -> wLcdLayout; + + /* Hardcoded special reader cases */ + switch (ccid_descriptor->readerID) { - // pcsc-lite 1.4.x header files: missing PIN_PROPERTIES_STRUCTURE - // pcsc-lite 1.5.x header files: incorrect PIN_PROPERTIES_STRUCTURE - unsigned int wLcdLayout = ccid_descriptor -> wLcdLayout; + case GEMPCPINPAD: + case VEGAALPHA: + case CHERRYST2000: + validation = 0x02; /* Validation key pressed */ + break; + default: + validation = 0x07; /* Default */ + } - if (RxLength >= 4) - { - RxBuffer[0] = wLcdLayout & 0xFF; - RxBuffer[1] = (wLcdLayout >> 8) & 0xFF; - RxBuffer[2] = 0x07; - RxBuffer[3] = 0; + /* Gemalto readers providing firmware features */ + if (ccid_descriptor -> gemalto_firmware_features) + validation = ccid_descriptor -> gemalto_firmware_features -> bEntryValidationCondition; - *pdwBytesReturned = 4; - return_value = IFD_SUCCESS; + caps -> bEntryValidationCondition = validation; + caps -> bTimeOut2 = 0x00; /* We do not distinguish bTimeOut from TimeOut2 */ + + *pdwBytesReturned = sizeof(*caps); + return_value = IFD_SUCCESS; + } + + /* Reader features */ + if (IOCTL_FEATURE_GET_TLV_PROPERTIES == dwControlCode) + { + int p = 0; + int tmp; + + /* wLcdLayout */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdLayout; /* tag */ + RxBuffer[p++] = 2; /* length */ + tmp = ccid_descriptor -> wLcdLayout; + RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */ + RxBuffer[p++] = (tmp >> 8) & 0xFF; + + /* only if the reader has a display */ + if (ccid_descriptor -> wLcdLayout) + { + /* wLcdMaxCharacters */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxCharacters; /* tag */ + RxBuffer[p++] = 2; /* length */ + tmp = ccid_descriptor -> wLcdLayout & 0xFF; + RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */ + RxBuffer[p++] = (tmp >> 8) & 0xFF; + + /* wLcdMaxLines */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxLines; /* tag */ + RxBuffer[p++] = 2; /* length */ + tmp = ccid_descriptor -> wLcdLayout >> 8; + RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */ + RxBuffer[p++] = (tmp >> 8) & 0xFF; + } + + /* bTimeOut2 */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bTimeOut2; + RxBuffer[p++] = 1; /* length */ + /* IFD does not distinguish bTimeOut from bTimeOut2 */ + RxBuffer[p++] = 0x00; + + /* sFirmwareID */ + if (VENDOR_GEMALTO == GET_VENDOR(ccid_descriptor -> readerID)) + { + unsigned char firmware[256]; + const unsigned char cmd[] = { 0x02 }; + RESPONSECODE ret; + unsigned int len; + + len = sizeof(firmware); + ret = CmdEscape(reader_index, cmd, sizeof(cmd), firmware, &len, 0); + + if (IFD_SUCCESS == ret) + { + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_sFirmwareID; + RxBuffer[p++] = len; + memcpy(&RxBuffer[p], firmware, len); + p += len; } } -#endif - /* Verify a PIN, plain CCID */ - if (IOCTL_FEATURE_VERIFY_PIN_DIRECT == dwControlCode) + /* Gemalto PC Pinpad V1 */ + if (((GEMPCPINPAD == ccid_descriptor -> readerID) + && (0x0100 == ccid_descriptor -> IFD_bcdDevice)) + /* Covadis Véga-Alpha */ + || (VEGAALPHA == ccid_descriptor->readerID)) { - unsigned int iBytesReturned; + /* bMinPINSize */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 4; /* min PIN size */ - iBytesReturned = RxLength; - return_value = SecurePINVerify(reader_index, TxBuffer, TxLength, - RxBuffer, &iBytesReturned); - *pdwBytesReturned = iBytesReturned; + /* bMaxPINSize */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 8; /* max PIN size */ + + /* bEntryValidationCondition */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 0x02; /* validation key pressed */ } - /* Modify a PIN, plain CCID */ - if (IOCTL_FEATURE_MODIFY_PIN_DIRECT == dwControlCode) + /* Cherry GmbH SmartTerminal ST-2xxx */ + if (CHERRYST2000 == ccid_descriptor -> readerID) { - unsigned int iBytesReturned; + /* bMinPINSize */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 0; /* min PIN size */ - iBytesReturned = RxLength; - return_value = SecurePINModify(reader_index, TxBuffer, TxLength, - RxBuffer, &iBytesReturned); - *pdwBytesReturned = iBytesReturned; + /* bMaxPINSize */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 25; /* max PIN size */ + + /* bEntryValidationCondition */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 0x02; /* validation key pressed */ } - /* MCT: Multifunctional Card Terminal */ - if (IOCTL_FEATURE_MCT_READERDIRECT == dwControlCode) + /* Gemalto readers providing firmware features */ + if (ccid_descriptor -> gemalto_firmware_features) { - if ( (TxBuffer[0] != 0x20) /* CLA */ - || ((TxBuffer[1] & 0xF0) != 0x70) /* INS */ - /* valid INS are - * 0x70: SECODER INFO - * 0x71: SECODER SELECT APPLICATION - * 0x72: SECODER APPLICATION ACTIVE - * 0x73: SECODER DATA CONFIRMATION - * 0x74: SECODER PROCESS AUTHENTICATION TOKEN */ - || ((TxBuffer[1] & 0x0F) > 4) - || (TxBuffer[2] != 0x00) /* P1 */ - || (TxBuffer[3] != 0x00) /* P2 */ - || (TxBuffer[4] != 0x00) /* Lind */ - ) - { - DEBUG_INFO("MCT Command refused by driver"); - return_value = IFD_COMMUNICATION_ERROR; - } - else - { - unsigned int iBytesReturned; + struct GEMALTO_FIRMWARE_FEATURES *features = ccid_descriptor -> gemalto_firmware_features; - /* we just transmit the buffer as a CCID Escape command */ - iBytesReturned = RxLength; - old_read_timeout = ccid_descriptor -> readTimeout; - ccid_descriptor -> readTimeout = 0; // Infinite - return_value = CmdEscape(reader_index, TxBuffer, TxLength, RxBuffer, - &iBytesReturned); - ccid_descriptor -> readTimeout = old_read_timeout; - *pdwBytesReturned = iBytesReturned; - } + /* bMinPINSize */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = features -> MinimumPINSize; /* min PIN size */ + + /* bMaxPINSize */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = features -> MaximumPINSize; /* max PIN size */ + + /* bEntryValidationCondition */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = features -> bEntryValidationCondition; /* validation key pressed */ + } + + /* ACR83, APG8201 and APG8201Z */ + if ((ACS_ACR83U == ccid_descriptor -> readerID) + || (ACS_APG8201 == ccid_descriptor -> readerID) + || (ACS_APG8201Z == ccid_descriptor -> readerID)) + { + /* bMinPINSize */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 1; /* min PIN size */ + + /* bMaxPINSize */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 16; /* max PIN size */ + + /* bEntryValidationCondition */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 0x07; /* default */ + } + + /* bPPDUSupport */ + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bPPDUSupport; + RxBuffer[p++] = 1; /* length */ + RxBuffer[p++] = 1; + /* bit0: PPDU is supported over SCardControl using + * FEATURE_CCID_ESC_COMMAND */ + + /* wIdVendor */ + { + int idVendor = ccid_descriptor -> readerID >> 16; + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdVendor; + RxBuffer[p++] = 2; /* length */ + RxBuffer[p++] = idVendor & 0xFF; + RxBuffer[p++] = idVendor >> 8; + } + + /* wIdProduct */ + { + int idProduct = ccid_descriptor -> readerID & 0xFFFF; + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdProduct; + RxBuffer[p++] = 2; /* length */ + RxBuffer[p++] = idProduct & 0xFF; + RxBuffer[p++] = idProduct >> 8; + } + + /* dwMaxAPDUDataSize */ + { + int MaxAPDUDataSize = 0; /* short APDU only by default */ + + /* reader is TPDU or extended APDU */ + if ((ccid_descriptor -> dwFeatures & CCID_CLASS_EXTENDED_APDU) + || (ccid_descriptor -> dwFeatures & CCID_CLASS_TPDU)) + MaxAPDUDataSize = 0x10000; + + RxBuffer[p++] = PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize; + RxBuffer[p++] = 4; /* length */ + RxBuffer[p++] = MaxAPDUDataSize & 0xFF; + RxBuffer[p++] = (MaxAPDUDataSize >> 8) & 0xFF; + RxBuffer[p++] = (MaxAPDUDataSize >> 16) & 0xFF; + RxBuffer[p++] = (MaxAPDUDataSize >> 24) & 0xFF; } - // MS CCID I/O control code for escape command - if (IOCTL_CCID_ESCAPE == dwControlCode) + *pdwBytesReturned = p; + return_value = IFD_SUCCESS; + } + + /* Verify a PIN, plain CCID */ + if (IOCTL_FEATURE_VERIFY_PIN_DIRECT == dwControlCode) + { + unsigned int iBytesReturned; + + iBytesReturned = RxLength; + return_value = SecurePINVerify(reader_index, TxBuffer, TxLength, + RxBuffer, &iBytesReturned); + *pdwBytesReturned = iBytesReturned; + } + + /* Modify a PIN, plain CCID */ + if (IOCTL_FEATURE_MODIFY_PIN_DIRECT == dwControlCode) + { + unsigned int iBytesReturned; + + iBytesReturned = RxLength; + return_value = SecurePINModify(reader_index, TxBuffer, TxLength, + RxBuffer, &iBytesReturned); + *pdwBytesReturned = iBytesReturned; + } + + /* MCT: Multifunctional Card Terminal */ + if (IOCTL_FEATURE_MCT_READER_DIRECT == dwControlCode) + { + if ( (TxBuffer[0] != 0x20) /* CLA */ + || ((TxBuffer[1] & 0xF0) != 0x70) /* INS */ + /* valid INS are + * 0x70: SECODER INFO + * 0x71: SECODER SELECT APPLICATION + * 0x72: SECODER APPLICATION ACTIVE + * 0x73: SECODER DATA CONFIRMATION + * 0x74: SECODER PROCESS AUTHENTICATION TOKEN */ + || ((TxBuffer[1] & 0x0F) > 4) + || (TxBuffer[2] != 0x00) /* P1 */ + || (TxBuffer[3] != 0x00) /* P2 */ + || (TxBuffer[4] != 0x00) /* Lind */ + ) + { + DEBUG_INFO1("MCT Command refused by driver"); + return_value = IFD_COMMUNICATION_ERROR; + } + else { unsigned int iBytesReturned; + /* we just transmit the buffer as a CCID Escape command */ iBytesReturned = RxLength; - old_read_timeout = ccid_descriptor -> readTimeout; - ccid_descriptor -> readTimeout = 0; // Infinite - return_value = CmdEscape(reader_index, TxBuffer, TxLength, RxBuffer, - &iBytesReturned); - ccid_descriptor -> readTimeout = old_read_timeout; + return_value = CmdEscape(reader_index, TxBuffer, TxLength, + RxBuffer, &iBytesReturned, 0); *pdwBytesReturned = iBytesReturned; } + } + + // MS CCID I/O control code for escape command + if (IOCTL_CCID_ESCAPE == dwControlCode) + { + unsigned int iBytesReturned; - // ACR83U, ACR85, APG8201 and APG8201Z specific I/O controls - if ((ACS_ACR83U == ccid_descriptor -> readerID) || - (ACS_ACR85_PINPAD_READER_ICC == ccid_descriptor -> readerID) || - (ACS_APG8201 == ccid_descriptor -> readerID) || - (ACS_APG8201Z == ccid_descriptor -> readerID)) - { - // Get firmware version - if (IOCTL_SMARTCARD_GET_FIRMWARE_VERSION == dwControlCode) - { - unsigned char command[] = { 0x04, 0x00, 0x00, 0x00, 0x00 }; - unsigned int commandLen = sizeof(command); - unsigned char response[3 + 6]; - unsigned int responseLen = sizeof(response); + iBytesReturned = RxLength; + return_value = CmdEscape(reader_index, TxBuffer, TxLength, + RxBuffer, &iBytesReturned, -1); // Infinite + *pdwBytesReturned = iBytesReturned; + } + + // ACR83U, ACR85, APG8201 and APG8201Z specific I/O controls + if ((ACS_ACR83U == ccid_descriptor -> readerID) || + (ACS_ACR85_PINPAD_READER_ICC == ccid_descriptor -> readerID) || + (ACS_APG8201 == ccid_descriptor -> readerID) || + (ACS_APG8201Z == ccid_descriptor -> readerID)) + { + // Get firmware version + if (IOCTL_SMARTCARD_GET_FIRMWARE_VERSION == dwControlCode) + { + unsigned char command[] = { 0x04, 0x00, 0x00, 0x00, 0x00 }; + unsigned int commandLen = sizeof(command); + unsigned char response[3 + 6]; + unsigned int responseLen = sizeof(response); - return_value = CmdEscape(reader_index, command, commandLen, response, &responseLen); + return_value = CmdEscape(reader_index, command, commandLen, + response, &responseLen, 0); + if (return_value == IFD_SUCCESS) + { + if ((responseLen > 3) && (response[0] == 0x84)) + { + *pdwBytesReturned = responseLen - 3; + if (RxLength < *pdwBytesReturned) + return_value = IFD_COMMUNICATION_ERROR; + else + memcpy(RxBuffer, response + 3, *pdwBytesReturned); + } + else + return_value = IFD_COMMUNICATION_ERROR; + } + } + + // Display LCD message + if (IOCTL_SMARTCARD_DISPLAY_LCD_MESSAGE == dwControlCode) + { + unsigned char command[5 + 32] = { 0x05, 0x00, 0x20, 0x00, 0x00 }; + unsigned int commandLen = sizeof(command); + unsigned char response[3 + 2]; + unsigned int responseLen = sizeof(response); + + if ((TxLength > 0) && (TxLength <= 32)) + { + // Fill memory with spaces + memset(command + 5, 0x20, 32); + + // Copy message to command + memcpy(command + 5, TxBuffer, TxLength); + + return_value = CmdEscape(reader_index, command, commandLen, + response, &responseLen, 0); if (return_value == IFD_SUCCESS) { - if ((responseLen > 3) && (response[0] == 0x84)) + if ((responseLen > 3) && (response[0] == 0x85)) { *pdwBytesReturned = responseLen - 3; if (RxLength < *pdwBytesReturned) @@ -1962,111 +2248,74 @@ return_value = IFD_COMMUNICATION_ERROR; } } + } + + // Read key + if (IOCTL_SMARTCARD_READ_KEY == dwControlCode) + { + unsigned char command[5 + 6] = { 0x06, 0x00, 0x06, 0x00, 0x00 }; + unsigned int commandLen = sizeof(command); + unsigned char response[3 + 35]; + unsigned int responseLen = sizeof(response); - // Display LCD message - if (IOCTL_SMARTCARD_DISPLAY_LCD_MESSAGE == dwControlCode) + if (TxLength == 6) { - unsigned char command[5 + 32] = { 0x05, 0x00, 0x20, 0x00, 0x00 }; - unsigned int commandLen = sizeof(command); - unsigned char response[3 + 2]; - unsigned int responseLen = sizeof(response); + // Copy message to command + memcpy(command + 5, TxBuffer, TxLength); - if ((TxLength > 0) && (TxLength <= 32)) + return_value = CmdEscape(reader_index, command, commandLen, + response, &responseLen, -1); // Infinite + if (return_value == IFD_SUCCESS) { - // Fill memory with spaces - memset(command + 5, 0x20, 32); - - // Copy message to command - memcpy(command + 5, TxBuffer, TxLength); - - return_value = CmdEscape(reader_index, command, commandLen, response, &responseLen); - if (return_value == IFD_SUCCESS) + if ((responseLen > 3) && (response[0] == 0x86)) { - if ((responseLen > 3) && (response[0] == 0x85)) - { - *pdwBytesReturned = responseLen - 3; - if (RxLength < *pdwBytesReturned) - return_value = IFD_COMMUNICATION_ERROR; - else - memcpy(RxBuffer, response + 3, *pdwBytesReturned); - } - else + *pdwBytesReturned = responseLen - 3; + if (RxLength < *pdwBytesReturned) return_value = IFD_COMMUNICATION_ERROR; - } - } - } - - // Read key - if (IOCTL_SMARTCARD_READ_KEY == dwControlCode) - { - unsigned char command[5 + 6] = { 0x06, 0x00, 0x06, 0x00, 0x00 }; - unsigned int commandLen = sizeof(command); - unsigned char response[3 + 35]; - unsigned int responseLen = sizeof(response); - - if (TxLength == 6) - { - // Copy message to command - memcpy(command + 5, TxBuffer, TxLength); - - old_read_timeout = ccid_descriptor -> readTimeout; - ccid_descriptor -> readTimeout = 0; // Infinite - return_value = CmdEscape(reader_index, command, commandLen, response, &responseLen); - ccid_descriptor -> readTimeout = old_read_timeout; - if (return_value == IFD_SUCCESS) - { - if ((responseLen > 3) && (response[0] == 0x86)) - { - *pdwBytesReturned = responseLen - 3; - if (RxLength < *pdwBytesReturned) - return_value = IFD_COMMUNICATION_ERROR; - else - memcpy(RxBuffer, response + 3, *pdwBytesReturned); - } else - return_value = IFD_COMMUNICATION_ERROR; + memcpy(RxBuffer, response + 3, *pdwBytesReturned); } + else + return_value = IFD_COMMUNICATION_ERROR; } } } - else + } + else + { + // ACR128 I/O control code for escape command + if (IOCTL_ACR128_READER_COMMAND == dwControlCode) { - // ACR128 I/O control code for escape command - if (IOCTL_ACR128_READER_COMMAND == dwControlCode) + unsigned char *command; + unsigned int commandLen = 3 + TxLength; + unsigned int iBytesReturned; + + // Allocate command + command = (unsigned char *) malloc(commandLen); + if (command == NULL) + return_value = IFD_COMMUNICATION_ERROR; + else { - unsigned char *command; - unsigned int commandLen = 3 + TxLength; - unsigned int iBytesReturned; - - // Allocate command - command = (unsigned char *) malloc(commandLen); - if (command == NULL) - return_value = IFD_COMMUNICATION_ERROR; - else - { - // Fill command header - command[0] = 0xE0; - command[1] = 0x00; - command[2] = 0x00; - - // Copy command - memcpy(command + 3, TxBuffer, TxLength); - - iBytesReturned = RxLength; - old_read_timeout = ccid_descriptor -> readTimeout; - ccid_descriptor -> readTimeout = 0; // Infinite - return_value = CmdEscape(reader_index, command, commandLen, RxBuffer, - &iBytesReturned); - ccid_descriptor -> readTimeout = old_read_timeout; - *pdwBytesReturned = iBytesReturned; + // Fill command header + command[0] = 0xE0; + command[1] = 0x00; + command[2] = 0x00; - // Free command - free(command); - } + // Copy command + memcpy(command + 3, TxBuffer, TxLength); + + iBytesReturned = RxLength; + return_value = CmdEscape(reader_index, command, commandLen, + RxBuffer, &iBytesReturned, -1); // Infinite + *pdwBytesReturned = iBytesReturned; + + // Free command + free(command); } } } +err: if (IFD_SUCCESS != return_value) *pdwBytesReturned = 0; @@ -2096,7 +2345,7 @@ if (-1 == (reader_index = LunToReaderIndex(Lun))) return IFD_COMMUNICATION_ERROR; - DEBUG_PERIODIC3("%s (lun: %X)", CcidSlots[reader_index].readerName, Lun); + DEBUG_PERIODIC3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName, Lun); ccid_descriptor = get_ccid_descriptor(reader_index); @@ -2104,9 +2353,12 @@ slot_index = ccid_descriptor->bCurrentSlotIndex; // Return dwSlotstatus if it is a SAM slot or reader is GEMCORESIMPRO - if ((ccid_descriptor->isSamSlot) || - (GEMCORESIMPRO == ccid_descriptor->readerID)) + if ((ccid_descriptor->isSamSlot) + || ((GEMCORESIMPRO == ccid_descriptor->readerID) + && (ccid_descriptor->IFD_bcdDevice < 0x0200))) { + /* GemCore SIM Pro firmware 2.00 and up features + * a full independant second slot */ return_value = ccid_descriptor->dwSlotStatus; goto end; } @@ -2125,12 +2377,9 @@ // ACR122U v2.00 - v2.04 // Simulate bStatus by reading bmSlotIccState from interrupt endpoint if ((ccid_descriptor->readerID == ACS_ACR122U) && - (ccid_descriptor->bcdDevice >= 0x0200) && - (ccid_descriptor->bcdDevice <= 0x0204)) + (ccid_descriptor->IFD_bcdDevice >= 0x0200) && + (ccid_descriptor->IFD_bcdDevice <= 0x0204)) { -#ifndef __APPLE__ - InterruptRead(reader_index, 100); -#endif #ifdef __APPLE__ pthread_mutex_lock(ccid_descriptor->pbStatusLock); #endif @@ -2153,9 +2402,9 @@ } // Enable/disable PICC else if ((ccid_descriptor->firmwareFixEnabled) && - (((ccid_descriptor->readerID == ACS_ACR1222_DUAL_READER) || + ((((ccid_descriptor->readerID == ACS_ACR1222_DUAL_READER) || (ccid_descriptor->readerID == ACS_ACR1222_1SAM_DUAL_READER)) && - (ccid_descriptor->bCurrentSlotIndex == 1) || + (ccid_descriptor->bCurrentSlotIndex == 1)) || (ccid_descriptor->readerID == ACS_ACR85_PINPAD_READER_PICC))) { if (*(ccid_descriptor->pPiccEnabled)) @@ -2171,9 +2420,6 @@ } else { -#ifndef __APPLE__ - InterruptRead(reader_index, 10); -#endif return_value = CcidSlots[reader_index].pGetSlotStatus(reader_index, pcbuffer); } @@ -2242,14 +2488,14 @@ if (! (LogLevel & DEBUG_LEVEL_PERIODIC)) LogLevel &= ~DEBUG_LEVEL_COMM; - ret = CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res); + ret = CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0); /* set back the old LogLevel */ LogLevel = oldLogLevel; if (ret != IFD_SUCCESS) { - DEBUG_INFO("CmdEscape failed"); + DEBUG_INFO1("CmdEscape failed"); /* simulate a card absent */ res[0] = 0; } @@ -2271,12 +2517,12 @@ #endif // Enable/disable PICC - if (DriverOptions & DRIVER_OPTION_DISABLE_PICC) + if (ACSDriverOptions & ACS_DRIVER_OPTION_DISABLE_PICC) { if ((ccid_descriptor->firmwareFixEnabled) && - (((ccid_descriptor->readerID == ACS_ACR1222_DUAL_READER) || + ((((ccid_descriptor->readerID == ACS_ACR1222_DUAL_READER) || (ccid_descriptor->readerID == ACS_ACR1222_1SAM_DUAL_READER)) && - (ccid_descriptor->bCurrentSlotIndex == 0) || + (ccid_descriptor->bCurrentSlotIndex == 0)) || (ccid_descriptor->readerID == ACS_ACR85_PINPAD_READER_ICC))) { int piccReaderIndex = *(ccid_descriptor->pPiccReaderIndex); @@ -2288,7 +2534,7 @@ // Disable PICC if (*(ccid_descriptor->pPiccEnabled)) { - DEBUG_INFO("Disabling PICC..."); + DEBUG_INFO1("Disabling PICC..."); EnablePicc(piccReaderIndex, FALSE); *(ccid_descriptor->pPiccEnabled) = FALSE; } @@ -2298,7 +2544,7 @@ if (!*(ccid_descriptor->pPiccEnabled)) { // Enable PICC - DEBUG_INFO("Enabling PICC..."); + DEBUG_INFO1("Enabling PICC..."); EnablePicc(piccReaderIndex, TRUE); *(ccid_descriptor->pPiccEnabled) = TRUE; } @@ -2323,24 +2569,67 @@ void init_driver(void) { - char keyValue[TOKEN_MAX_VALUE_SIZE]; char infofile[FILENAME_MAX]; char *e; + int rv; + list_t plist, *values; - DEBUG_INFO("Driver version: " VERSION); + DEBUG_INFO1("Driver version: " VERSION); /* Info.plist full patch filename */ (void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist", PCSCLITE_HP_DROPDIR, BUNDLE); - /* Log level */ - if (0 == LTPBundleFindValueWithKey(infofile, "ifdLogLevel", keyValue, 0)) + rv = bundleParse(infofile, &plist); + if (0 == rv) { - /* convert from hex or dec or octal */ - LogLevel = strtoul(keyValue, NULL, 0); + /* Log level */ + rv = LTPBundleFindValueWithKey(&plist, "ifdLogLevel", &values); + if (0 == rv) + { + /* convert from hex or dec or octal */ + LogLevel = strtoul(list_get_at(values, 0), NULL, 0); - /* print the log level used */ - DEBUG_INFO2("LogLevel: 0x%.4X", LogLevel); + /* print the log level used */ + DEBUG_INFO2("LogLevel: 0x%.4X", LogLevel); + } + + /* Driver options */ + rv = LTPBundleFindValueWithKey(&plist, "ifdDriverOptions", &values); + if (0 == rv) + { + /* convert from hex or dec or octal */ + DriverOptions = strtoul(list_get_at(values, 0), NULL, 0); + + /* print the log level used */ + DEBUG_INFO2("DriverOptions: 0x%.4X", DriverOptions); + } + + // ACS driver options + rv = LTPBundleFindValueWithKey(&plist, "ifdACSDriverOptions", &values); + if (0 == rv) + { + ACSDriverOptions = strtoul(list_get_at(values, 0), NULL, 0); + DEBUG_INFO2("ACSDriverOptions: 0x%.4X", ACSDriverOptions); + } + + // Card voltage selection for ACR38U, ACR38U-SAM and SCR21U + rv = LTPBundleFindValueWithKey(&plist, "ifdACR38CardVoltage", &values); + if (0 == rv) + { + ACR38CardVoltage = strtoul(list_get_at(values, 0), NULL, 0); + DEBUG_INFO2("ACR38CardVoltage: %d", ACR38CardVoltage); + } + + // Card type selection for ACR38U, ACR38U-SAM and SCR21U + rv = LTPBundleFindValueWithKey(&plist, "ifdACR38CardType", &values); + if (0 == rv) + { + ACR38CardType = strtoul(list_get_at(values, 0), NULL, 0); + DEBUG_INFO2("ACR38CardType: " DWORD_D "", ACR38CardType); + } + + bundleRelease(&plist); } e = getenv("LIBCCID_ifdLogLevel"); @@ -2353,16 +2642,6 @@ DEBUG_INFO2("LogLevel from LIBCCID_ifdLogLevel: 0x%.4X", LogLevel); } - /* Driver options */ - if (0 == LTPBundleFindValueWithKey(infofile, "ifdDriverOptions", keyValue, 0)) - { - /* convert from hex or dec or octal */ - DriverOptions = strtoul(keyValue, NULL, 0); - - /* print the log level used */ - DEBUG_INFO2("DriverOptions: 0x%.4X", DriverOptions); - } - /* get the voltage parameter */ switch ((DriverOptions >> 4) & 0x03) { @@ -2383,20 +2662,6 @@ break; } - // Card voltage selection for ACR38U, ACR38U-SAM and SCR21U - if (0 == LTPBundleFindValueWithKey(infofile, "ifdACR38CardVoltage", keyValue, 0)) - { - ACR38CardVoltage = strtoul(keyValue, NULL, 0); - DEBUG_INFO2("ACR38CardVoltage: %d", ACR38CardVoltage); - } - - // Card type selection for ACR38U, ACR38U-SAM and SCR21U - if (0 == LTPBundleFindValueWithKey(infofile, "ifdACR38CardType", keyValue, 0)) - { - ACR38CardType = strtoul(keyValue, NULL, 0); - DEBUG_INFO2("ACR38CardType: %d", ACR38CardType); - } - /* initialise the Lun to reader_index mapping */ InitReaderIndex(); @@ -2421,7 +2686,6 @@ unsigned int card_baudrate; unsigned int default_baudrate; double f, d; - int i; /* if TA1 not present */ if (! atr->ib[0][ATR_INTERFACE_BYTE_TA].present) @@ -2454,11 +2718,13 @@ /* Init TC1 */ atr->ib[0][ATR_INTERFACE_BYTE_TC].present = TRUE; atr->ib[0][ATR_INTERFACE_BYTE_TC].value = 2; - DEBUG_INFO("Extra EGT patch applied"); + DEBUG_INFO1("Extra EGT patch applied"); } if (SCARD_PROTOCOL_T1 == Protocol) { + int i; + /* TBi (i>2) present? BWI/CWI */ for (i=2; iib[0][ATR_INTERFACE_BYTE_TC].present = TRUE; atr->ib[0][ATR_INTERFACE_BYTE_TC].value = 2; - DEBUG_INFO("Extra EGT patch applied"); + DEBUG_INFO1("Extra EGT patch applied"); /* only the first TBi (i>2) must be used */ break; @@ -2521,13 +2787,13 @@ * 5 bytes header cmd -> * <- Procedure byte * 256 data bytes -> - * <- SW1-SW2 + * <- SW1-SW2 * = 261 EGT + 3 WWT + 3 WWT * * ISO_OUT Timeout is the sum of: * Terminal: Smart card: * 5 bytes header cmd -> - * <- Procedure byte + 256 data bytes + SW1-SW2 + * <- Procedure byte + 256 data bytes + SW1-SW2 * = 5 EGT + 1 WWT + 259 WWT */ @@ -2536,7 +2802,7 @@ /* may happen with non ISO cards */ if ((0 == f) || (0 == d) || (0 == clock_frequency)) - return 60; /* 60 seconds */ + return 60 * 1000; /* 60 seconds */ /* EGT */ /* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */ @@ -2548,16 +2814,11 @@ /* ISO in */ t = 261 * EGT + (3 + 3) * WWT; - /* Convert from milliseonds to seconds rouned to the upper value - * use +1 instead of ceil() to round up to the nearest integer - * so we can avoid a dependency on the math library */ - t = t/1000 +1; if (timeout < t) timeout = t; /* ISO out */ t = 5 * EGT + (1 + 259) * WWT; - t = t/1000 +1; if (timeout < t) timeout = t; @@ -2586,7 +2847,7 @@ /* may happen with non ISO cards */ if ((0 == f) || (0 == d) || (0 == clock_frequency)) - return 60; /* 60 seconds */ + return 60 * 1000; /* 60 seconds */ /* see ch. 6.5.2 Transmission factors F and D, page 12 of ISO 7816-3 */ etu = f / d / clock_frequency; @@ -2605,10 +2866,9 @@ timeout = 260*EGT + BWT + 260*CWT; - /* Convert from milliseonds to seconds rounded to the upper value - * we use +1 instead of ceil() to round up to the nearest greater integer - * so we can avoid a dependency on the math library */ - timeout = timeout/1000 +1; + /* This is the card/reader timeout. Add 1 second for the libusb + * timeout so we get the error from the reader. */ + timeout += 1000; return timeout; } /* T1_card_timeout */ diff -Nru acsccid-1.0.8/src/Info.plist.src acsccid-1.1.0/src/Info.plist.src --- acsccid-1.0.8/src/Info.plist.src 2011-10-20 02:13:56.000000000 +0000 +++ acsccid-1.1.0/src/Info.plist.src 2014-12-10 08:32:26.000000000 +0000 @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion English CFBundleExecutable - MAGIC_BUNDLE + MAGIC_TARGET CFBundleIdentifier hk.com.acs.ccid CFBundleInfoDictionaryVersion @@ -20,7 +20,7 @@ CFBundleVersion 0.0.1d1 ifdCapabilities - MAGIC_IFDCAPABILITIES + 0x00000000 ifdDriverOptions - 0x00C0 + 0x0000 + + ifdACSDriverOptions + 0x0003 + + ifdACR38CardVoltage @@ -154,9 +166,6 @@ Default value: 0 --> - CFBundleExecutable - MAGIC_TARGET - ifdManufacturerString Advanced Card Systems Ltd. diff -Nru acsccid-1.0.8/src/Makefile.am acsccid-1.1.0/src/Makefile.am --- acsccid-1.0.8/src/Makefile.am 2014-04-17 07:42:57.000000000 +0000 +++ acsccid-1.1.0/src/Makefile.am 2014-12-10 08:32:26.000000000 +0000 @@ -30,7 +30,9 @@ TOKEN_PARSER = tokenparser.l parser.h \ strlcpy.c \ misc.h \ - strlcpycat.h + strlcpycat.h \ + simclist.c \ + simclist.h if WITHOUT_PCSC PROVIDED_BY_PCSC = debug.c @@ -45,18 +47,12 @@ EXTRA_DIST = Info.plist.src create_Info_plist.pl supported_readers.txt \ towitoko/COPYING towitoko/README openct/LICENSE \ - convert_version.pl pcscd_acsccid.rules 92_pcscd_acsccid.rules \ - 92_pcscd_acsccid_group.rules + convert_version.pl 92_pcscd_acsccid.rules -if UDEV -ifdCapabilities=0x00000001 -INSTALL_UDEV_RULE_FILE=@echo -e "\n\33[01;31m***************\n" ; echo "copy the src/pcscd_acsccid.rules file (pcsc-lite < 1.6.5) or src/92_pcscd_acsccid.rules (pcsc-lite >= 1.6.5) to udev directory (/etc/udev/rules.d/)" ; echo -e "\n***************\n\33[0m" -else -ifdCapabilities=0x00000000 -endif +INSTALL_UDEV_RULE_FILE=@/bin/echo -e "\n\33[01;31m***************\n" ; echo "copy the src/92_pcscd_acsccid.rules file in udev directory (/etc/udev/rules.d/)" ; /bin/echo -e "\n***************\n\33[0m" Info.plist: Info.plist.src $(srcdir)/supported_readers.txt - $(srcdir)/create_Info_plist.pl $(srcdir)/supported_readers.txt $(srcdir)/Info.plist.src --ifdCapabilities=$(ifdCapabilities) --target=$(CCID_LIB) --version=$(VERSION) --bundle=$(CCID_BUNDLE) $(NOCLASS) > Info.plist + $(srcdir)/create_Info_plist.pl $(srcdir)/supported_readers.txt $(srcdir)/Info.plist.src --target=$(CCID_LIB) --version=$(VERSION) $(NOCLASS) > Info.plist DISTCLEANFILES = tokenparser.c Info.plist diff -Nru acsccid-1.0.8/src/Makefile.in acsccid-1.1.0/src/Makefile.in --- acsccid-1.0.8/src/Makefile.in 2014-07-03 02:07:54.000000000 +0000 +++ acsccid-1.1.0/src/Makefile.in 2014-12-10 08:34:13.000000000 +0000 @@ -128,16 +128,17 @@ am__libacsccid_la_SOURCES_DIST = ccid.c ccid.h ccid_ifdhandler.h \ commands.c commands.h acr38cmd.c acr38cmd.h debug.h defs.h \ ifdhandler.c utils.c utils.h ccid_usb.c ccid_usb.h \ - tokenparser.l parser.h strlcpy.c misc.h strlcpycat.h debug.c \ - towitoko/atr.c towitoko/atr.h towitoko/defines.h \ - towitoko/pps.c towitoko/pps.h openct/buffer.c openct/buffer.h \ - openct/checksum.c openct/checksum.h openct/proto-t1.c \ - openct/proto-t1.h + tokenparser.l parser.h strlcpy.c misc.h strlcpycat.h \ + simclist.c simclist.h debug.c towitoko/atr.c towitoko/atr.h \ + towitoko/defines.h towitoko/pps.c towitoko/pps.h \ + openct/buffer.c openct/buffer.h openct/checksum.c \ + openct/checksum.h openct/proto-t1.c openct/proto-t1.h am__objects_1 = libacsccid_la-ccid.lo libacsccid_la-commands.lo \ libacsccid_la-acr38cmd.lo libacsccid_la-ifdhandler.lo \ libacsccid_la-utils.lo am__objects_2 = libacsccid_la-ccid_usb.lo -am__objects_3 = libacsccid_la-tokenparser.lo libacsccid_la-strlcpy.lo +am__objects_3 = libacsccid_la-tokenparser.lo libacsccid_la-strlcpy.lo \ + libacsccid_la-simclist.lo @WITHOUT_PCSC_TRUE@am__objects_4 = libacsccid_la-debug.lo am__dirstamp = $(am__leading_dot)dirstamp am__objects_5 = towitoko/libacsccid_la-atr.lo \ @@ -266,7 +267,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ -LIBUSBCONFIG = @LIBUSBCONFIG@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIPO = @LIPO@ @@ -394,7 +394,9 @@ TOKEN_PARSER = tokenparser.l parser.h \ strlcpy.c \ misc.h \ - strlcpycat.h + strlcpycat.h \ + simclist.c \ + simclist.h @WITHOUT_PCSC_TRUE@PROVIDED_BY_PCSC = debug.c lib_LTLIBRARIES = libacsccid.la @@ -406,12 +408,9 @@ libacsccid_la_LDFLAGS = -avoid-version EXTRA_DIST = Info.plist.src create_Info_plist.pl supported_readers.txt \ towitoko/COPYING towitoko/README openct/LICENSE \ - convert_version.pl pcscd_acsccid.rules 92_pcscd_acsccid.rules \ - 92_pcscd_acsccid_group.rules + convert_version.pl 92_pcscd_acsccid.rules -@UDEV_FALSE@ifdCapabilities = 0x00000000 -@UDEV_TRUE@ifdCapabilities = 0x00000001 -@UDEV_TRUE@INSTALL_UDEV_RULE_FILE = @echo -e "\n\33[01;31m***************\n" ; echo "copy the src/pcscd_acsccid.rules file (pcsc-lite < 1.6.5) or src/92_pcscd_acsccid.rules (pcsc-lite >= 1.6.5) to udev directory (/etc/udev/rules.d/)" ; echo -e "\n***************\n\33[0m" +INSTALL_UDEV_RULE_FILE = @/bin/echo -e "\n\33[01;31m***************\n" ; echo "copy the src/92_pcscd_acsccid.rules file in udev directory (/etc/udev/rules.d/)" ; /bin/echo -e "\n***************\n\33[0m" DISTCLEANFILES = tokenparser.c Info.plist all: all-am @@ -524,6 +523,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libacsccid_la-commands.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libacsccid_la-debug.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libacsccid_la-ifdhandler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libacsccid_la-simclist.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libacsccid_la-strlcpy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libacsccid_la-tokenparser.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libacsccid_la-utils.Plo@am__quote@ @@ -613,6 +613,13 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libacsccid_la_CFLAGS) $(CFLAGS) -c -o libacsccid_la-strlcpy.lo `test -f 'strlcpy.c' || echo '$(srcdir)/'`strlcpy.c +libacsccid_la-simclist.lo: simclist.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libacsccid_la_CFLAGS) $(CFLAGS) -MT libacsccid_la-simclist.lo -MD -MP -MF $(DEPDIR)/libacsccid_la-simclist.Tpo -c -o libacsccid_la-simclist.lo `test -f 'simclist.c' || echo '$(srcdir)/'`simclist.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libacsccid_la-simclist.Tpo $(DEPDIR)/libacsccid_la-simclist.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='simclist.c' object='libacsccid_la-simclist.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libacsccid_la_CFLAGS) $(CFLAGS) -c -o libacsccid_la-simclist.lo `test -f 'simclist.c' || echo '$(srcdir)/'`simclist.c + libacsccid_la-debug.lo: debug.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libacsccid_la_CFLAGS) $(CFLAGS) -MT libacsccid_la-debug.lo -MD -MP -MF $(DEPDIR)/libacsccid_la-debug.Tpo -c -o libacsccid_la-debug.lo `test -f 'debug.c' || echo '$(srcdir)/'`debug.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libacsccid_la-debug.Tpo $(DEPDIR)/libacsccid_la-debug.Plo @@ -878,7 +885,7 @@ Info.plist: Info.plist.src $(srcdir)/supported_readers.txt - $(srcdir)/create_Info_plist.pl $(srcdir)/supported_readers.txt $(srcdir)/Info.plist.src --ifdCapabilities=$(ifdCapabilities) --target=$(CCID_LIB) --version=$(VERSION) --bundle=$(CCID_BUNDLE) $(NOCLASS) > Info.plist + $(srcdir)/create_Info_plist.pl $(srcdir)/supported_readers.txt $(srcdir)/Info.plist.src --target=$(CCID_LIB) --version=$(VERSION) $(NOCLASS) > Info.plist install: libacsccid.la Info.plist $(mkinstalldirs) $(DESTDIR)$(usbdropdir)/$(CCID_BUNDLE)/Contents/$(BUNDLE_HOST)/ diff -Nru acsccid-1.0.8/src/misc.h acsccid-1.1.0/src/misc.h --- acsccid-1.0.8/src/misc.h 2008-05-09 14:59:08.000000000 +0000 +++ acsccid-1.1.0/src/misc.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,22 +1,43 @@ /* * This handles GCC attributes * - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) + * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) * - * Copyright (C) 2005 + * Copyright (C) 2005-2010 * Ludovic Rousseau * - * $Id: misc.h 2481 2007-03-15 08:23:07Z rousseau $ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +Changes to this license can be made only by the copyright author with +explicit written consent. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: misc.h 6851 2014-02-14 15:43:32Z rousseau $ */ #ifndef __misc_h__ #define __misc_h__ -#ifdef __cplusplus -extern "C" -{ -#endif - /* * Declare the function as internal to the library: the function name is * not exported and can't be used by a program linked to the library @@ -24,9 +45,13 @@ * see http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gcc/Function-Attributes.html#Function-Attributes * see http://www.nedprod.com/programs/gccvisibility.html */ -#if defined __GNUC__ && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) +#if defined __GNUC__ && (! defined (__sun)) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) #define INTERNAL __attribute__ ((visibility("hidden"))) #define PCSC_API __attribute__ ((visibility("default"))) +#elif (! defined __GNUC__ ) && defined (__sun) +/* http://wikis.sun.com/display/SunStudio/Macros+for+Shared+Library+Symbol+Visibility */ +#define INTERNAL __hidden +#define PCSC_API __global #else #define INTERNAL #define PCSC_API @@ -56,8 +81,8 @@ #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif -#ifdef __cplusplus -} +#ifndef COUNT_OF +#define COUNT_OF(arr) (sizeof(arr)/sizeof(arr[0])) #endif #endif /* __misc_h__ */ diff -Nru acsccid-1.0.8/src/openct/buffer.c acsccid-1.1.0/src/openct/buffer.c --- acsccid-1.0.8/src/openct/buffer.c 2008-11-18 21:48:42.000000000 +0000 +++ acsccid-1.1.0/src/openct/buffer.c 2014-12-10 08:32:26.000000000 +0000 @@ -4,12 +4,12 @@ * Copyright (C) 2003, Olaf Kirch */ -#ifdef HAVE_CONFIG_H #include -#endif -#include + +#ifdef HAVE_STRING_H #include -#include +#endif + #include void diff -Nru acsccid-1.0.8/src/openct/buffer.h acsccid-1.1.0/src/openct/buffer.h --- acsccid-1.0.8/src/openct/buffer.h 2008-11-18 21:48:42.000000000 +0000 +++ acsccid-1.1.0/src/openct/buffer.h 2014-12-10 08:32:26.000000000 +0000 @@ -11,7 +11,9 @@ extern "C" { #endif +#ifdef HAVE_SYS_TYPES_H #include +#endif typedef struct ct_buf { unsigned char * base; diff -Nru acsccid-1.0.8/src/openct/checksum.c acsccid-1.1.0/src/openct/checksum.c --- acsccid-1.0.8/src/openct/checksum.c 2008-11-18 21:48:42.000000000 +0000 +++ acsccid-1.1.0/src/openct/checksum.c 2014-12-10 08:32:26.000000000 +0000 @@ -5,11 +5,10 @@ * For licensing, see the file LICENCE */ -#include "config.h" +#include #ifdef HAVE_STDINT_H #include #endif -#include #include "checksum.h" #define min( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) diff -Nru acsccid-1.0.8/src/openct/checksum.h acsccid-1.1.0/src/openct/checksum.h --- acsccid-1.0.8/src/openct/checksum.h 2008-11-18 21:48:42.000000000 +0000 +++ acsccid-1.1.0/src/openct/checksum.h 2014-12-10 08:32:26.000000000 +0000 @@ -17,16 +17,18 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* $Id: checksum.h 2974 2008-05-28 18:32:52Z rousseau $ */ +/* $Id: checksum.h 6975 2014-09-04 11:33:05Z rousseau $ */ #ifndef __CHECKSUM_H__ #define __CHECKSUM_H__ -#include "config.h" +#include #ifdef HAVE_STDINT_H #include #endif +#ifdef HAVE_UNISTD_H #include +#endif extern unsigned int csum_lrc_compute(const uint8_t *, size_t, unsigned char *); extern unsigned int csum_crc_compute(const uint8_t *, size_t, unsigned char *); diff -Nru acsccid-1.0.8/src/openct/proto-t1.c acsccid-1.1.0/src/openct/proto-t1.c --- acsccid-1.0.8/src/openct/proto-t1.c 2014-04-17 07:42:57.000000000 +0000 +++ acsccid-1.1.0/src/openct/proto-t1.c 2014-12-10 08:32:26.000000000 +0000 @@ -8,6 +8,8 @@ * Copyright (C) 2011 Advanced Card Systems Ltd. */ +#include + #include #include #include "commands.h" @@ -18,10 +20,9 @@ #include "ccid.h" -#include -#include -#include +#ifdef HAVE_STRING_H #include +#endif #include "defs.h" #include "ccid_ifdhandler.h" diff -Nru acsccid-1.0.8/src/openct/proto-t1.h acsccid-1.1.0/src/openct/proto-t1.h --- acsccid-1.0.8/src/openct/proto-t1.h 2009-01-28 13:08:41.000000000 +0000 +++ acsccid-1.1.0/src/openct/proto-t1.h 2014-12-10 08:32:26.000000000 +0000 @@ -17,16 +17,15 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* $Id: proto-t1.h 3292 2009-01-26 13:02:58Z rousseau $ */ +/* $Id: proto-t1.h 6975 2014-09-04 11:33:05Z rousseau $ */ #ifndef __PROTO_T1_H__ #define __PROTO_T1_H__ -#include "config.h" +#include #ifdef HAVE_STDINT_H #include #endif -#include #include "buffer.h" diff -Nru acsccid-1.0.8/src/parser.h acsccid-1.1.0/src/parser.h --- acsccid-1.0.8/src/parser.h 2009-06-12 13:06:28.000000000 +0000 +++ acsccid-1.1.0/src/parser.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,11 +1,38 @@ /* - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) + * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) * * Copyright (C) 2003 * Toni Andjelkovic + * Copyright (C) 2003-2009 * Ludovic Rousseau * - * $Id: parser.h 4248 2009-06-05 08:41:19Z rousseau $ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +Changes to this license can be made only by the copyright author with +explicit written consent. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: parser.h 6851 2014-02-14 15:43:32Z rousseau $ */ /** @@ -16,25 +43,16 @@ #ifndef __parser_h__ #define __parser_h__ -#ifdef __cplusplus -extern "C" -{ -#endif - -#define TOKEN_MAX_KEY_SIZE 200 -#define TOKEN_MAX_VALUE_SIZE 200 - -#define TOKEN_TYPE_KEY 1 -#define TOKEN_TYPE_STRING 2 +#include "simclist.h" -int LTPBundleFindValueWithKey(const char *fileName, const char *tokenKey, - /*@out@*/ char *tokenValue, int tokenIndice); - -int LTPBundleFindOptionalValueWithKey(const char *fileName, - const char *tokenKey, /*@out@*/ char *tokenValue, int tokenIndice); - -#ifdef __cplusplus -} -#endif +struct bundleElt +{ + char *key; + list_t values; +}; + +int LTPBundleFindValueWithKey(list_t *l, const char *key, list_t **values); +int bundleParse(const char *fileName, list_t *l); +void bundleRelease(list_t *l); #endif diff -Nru acsccid-1.0.8/src/pcscd_acsccid.rules acsccid-1.1.0/src/pcscd_acsccid.rules --- acsccid-1.0.8/src/pcscd_acsccid.rules 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/src/pcscd_acsccid.rules 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -# udev rules for pcscd and ACS CCID readers - -# If not adding the device, go away -ACTION!="add", GOTO="pcscd_acsccid_rules_end" - -# generic CCID device -SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="0b", RUN+="/usr/sbin/pcscd --hotplug" - -# -# non CCID generic (InterfaceClass: 0x00) -# - -# ACS ACR83U -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90d2", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS ACR88U -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2011", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS ACR1251 1S Dual Reader -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2242", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS ACR1261 1S Dual Reader -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2211", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS ACR128U -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2100", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS ACR1281 1S Dual Reader -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2224", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS ACR1281 2S CL Reader -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2215", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS APG8201 -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="8201", RUN+="/usr/sbin/pcscd --hotplug" - -# -# non-CCID readers -# - -# ACS ACR38U -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="9000", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS ACR38U-SAM -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90cf", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS AET65 1SAM ICC Reader -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="0101", RUN+="/usr/sbin/pcscd --hotplug" - -# IRIS SCR21U -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90ce", RUN+="/usr/sbin/pcscd --hotplug" - -# ACS CryptoMate -SUBSYSTEMS=="usb", ATTRS{idVendor}=="072f", ATTRS{idProduct}=="9006", RUN+="/usr/sbin/pcscd --hotplug" - -# All done -LABEL="pcscd_acsccid_rules_end" diff -Nru acsccid-1.0.8/src/simclist.c acsccid-1.1.0/src/simclist.c --- acsccid-1.0.8/src/simclist.c 1970-01-01 00:00:00.000000000 +0000 +++ acsccid-1.1.0/src/simclist.c 2014-12-10 08:32:26.000000000 +0000 @@ -0,0 +1,1525 @@ +/* + * Copyright (c) 2007,2008,2009,2010,2011 Mij + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +/* + * SimCList library. See http://mij.oltrelinux.com/devel/simclist + */ + +/* SimCList implementation, version 1.6 */ + +#include +#include +#include /* for setting errno */ +#include +#ifndef _WIN32 + /* not in Windows! */ +# include +# include +#endif +#ifndef SIMCLIST_NO_DUMPRESTORE + /* includes for dump/restore */ +# include +# include /* for READ_ERRCHECK() and write() */ +# include /* for open() etc */ +# ifndef _WIN32 +# include /* for htons() on UNIX */ +# else +# include /* for htons() on Windows */ +# endif +#endif + +/* disable asserts */ +#ifndef SIMCLIST_DEBUG +#define NDEBUG +#endif + +#include + + +#include /* for open()'s access modes S_IRUSR etc */ +#include + +#if defined(_MSC_VER) || defined(__MINGW32__) +/* provide gettimeofday() missing in Windows */ +int gettimeofday(struct timeval *tp, void *tzp) { + DWORD t; + + /* XSI says: "If tzp is not a null pointer, the behavior is unspecified" */ + assert(tzp == NULL); + + t = timeGetTime(); + tp->tv_sec = t / 1000; + tp->tv_usec = t % 1000; + return 0; +} +#endif + + +/* work around lack of inttypes.h support in broken Microsoft Visual Studio compilers */ +#if !defined(_WIN32) || !defined(_MSC_VER) +# include /* (u)int*_t */ +#else +# include +typedef UINT8 uint8_t; +typedef UINT16 uint16_t; +typedef ULONG32 uint32_t; +typedef UINT64 uint64_t; +typedef INT8 int8_t; +typedef INT16 int16_t; +typedef LONG32 int32_t; +typedef INT64 int64_t; +#endif + + +/* define some commodity macros for Dump/Restore functionality */ +#ifndef SIMCLIST_NO_DUMPRESTORE +/* write() decorated with error checking logic */ +#define WRITE_ERRCHECK(fd, msgbuf, msglen) do { \ + if (write(fd, msgbuf, msglen) < 0) return -1; \ + } while (0); +/* READ_ERRCHECK() decorated with error checking logic */ +#define READ_ERRCHECK(fd, msgbuf, msglen) do { \ + if (read(fd, msgbuf, msglen) != msglen) { \ + /*errno = EPROTO;*/ \ + return -1; \ + } \ + } while (0); + +/* convert 64bit integers from host to network format */ +#define hton64(x) (\ + htons(1) == 1 ? \ + (uint64_t)x /* big endian */ \ + : /* little endian */ \ + ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \ + (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \ + (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \ + (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ + (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ + (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \ + (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \ + (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) \ + ) + +/* convert 64bit integers from network to host format */ +#define ntoh64(x) (hton64(x)) +#endif + +/* some OSes don't have EPROTO (eg OpenBSD) */ +#ifndef EPROTO +#define EPROTO EIO +#endif + +#ifdef SIMCLIST_WITH_THREADS +/* limit (approx) to the number of threads running + * for threaded operations. Only meant when + * SIMCLIST_WITH_THREADS is defined */ +#define SIMCLIST_MAXTHREADS 2 +#endif + +/* + * how many elems to keep as spare. During a deletion, an element + * can be saved in a "free-list", not free()d immediately. When + * latter insertions are performed, spare elems can be used instead + * of malloc()ing new elems. + * + * about this param, some values for appending + * 10 million elems into an empty list: + * (#, time[sec], gain[%], gain/no[%]) + * 0 2,164 0,00 0,00 <-- feature disabled + * 1 1,815 34,9 34,9 + * 2 1,446 71,8 35,9 <-- MAX gain/no + * 3 1,347 81,7 27,23 + * 5 1,213 95,1 19,02 + * 8 1,064 110,0 13,75 + * 10 1,015 114,9 11,49 <-- MAX gain w/ likely sol + * 15 1,019 114,5 7,63 + * 25 0,985 117,9 4,72 + * 50 1,088 107,6 2,15 + * 75 1,016 114,8 1,53 + * 100 0,988 117,6 1,18 + * 150 1,022 114,2 0,76 + * 200 0,939 122,5 0,61 <-- MIN time + */ +#ifndef SIMCLIST_MAX_SPARE_ELEMS +#define SIMCLIST_MAX_SPARE_ELEMS 5 +#endif + + +#ifdef SIMCLIST_WITH_THREADS +#include +#endif + +#include "simclist.h" + + +/* minumum number of elements for sorting with quicksort instead of insertion */ +#define SIMCLIST_MINQUICKSORTELS 24 + + +/* list dump declarations */ +#define SIMCLIST_DUMPFORMAT_VERSION 1 /* (short integer) version of fileformat managed by _dump* and _restore* functions */ + +#define SIMCLIST_DUMPFORMAT_HEADERLEN 30 /* length of the header */ + +/* header for a list dump */ +struct list_dump_header_s { + uint16_t ver; /* version */ + int32_t timestamp_sec; /* dump timestamp, seconds since UNIX Epoch */ + int32_t timestamp_usec; /* dump timestamp, microseconds since timestamp_sec */ + int32_t rndterm; /* random value terminator -- terminates the data sequence */ + + uint32_t totlistlen; /* sum of every element' size, bytes */ + uint32_t numels; /* number of elements */ + uint32_t elemlen; /* bytes length of an element, for constant-size lists, <= 0 otherwise */ + int32_t listhash; /* hash of the list at the time of dumping, or 0 if to be ignored */ +}; + + + +/* deletes tmp from list, with care wrt its position (head, tail, middle) */ +static int list_drop_elem(list_t *restrict l, struct list_entry_s *tmp, unsigned int pos); + +/* set default values for initialized lists */ +static int list_attributes_setdefaults(list_t *restrict l); + +#ifndef NDEBUG +/* check whether the list internal REPresentation is valid -- Costs O(n) */ +static int list_repOk(const list_t *restrict l); + +/* check whether the list attribute set is valid -- Costs O(1) */ +static int list_attrOk(const list_t *restrict l); +#endif + +/* do not inline, this is recursive */ +static void list_sort_quicksort(list_t *restrict l, int versus, + unsigned int first, struct list_entry_s *fel, + unsigned int last, struct list_entry_s *lel); + +static inline void list_sort_selectionsort(list_t *restrict l, int versus, + unsigned int first, struct list_entry_s *fel, + unsigned int last, struct list_entry_s *lel); + +static void *list_get_minmax(const list_t *restrict l, int versus); + +static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart); + +/* + * Random Number Generator + * + * The user is expected to seed the RNG (ie call srand()) if + * SIMCLIST_SYSTEM_RNG is defined. + * + * Otherwise, a self-contained RNG based on LCG is used; see + * http://en.wikipedia.org/wiki/Linear_congruential_generator . + * + * Facts pro local RNG: + * 1. no need for the user to call srand() on his own + * 2. very fast, possibly faster than OS + * 3. avoid interference with user's RNG + * + * Facts pro system RNG: + * 1. may be more accurate (irrelevant for SimCList randno purposes) + * 2. why reinvent the wheel + * + * Default to local RNG for user's ease of use. + */ + +#ifdef SIMCLIST_SYSTEM_RNG +/* keep track whether we initialized already (non-0) or not (0) */ +static unsigned random_seed = 0; + +/* use local RNG */ +static inline void seed_random(void) { + if (random_seed == 0) + random_seed = (unsigned)getpid() ^ (unsigned)time(NULL); +} + +static inline long get_random(void) { + random_seed = (1664525 * random_seed + 1013904223); + return random_seed; +} + +#else +/* use OS's random generator */ +# define seed_random() +# define get_random() (rand()) +#endif + + +/* list initialization */ +int list_init(list_t *restrict l) { + if (l == NULL) return -1; + + seed_random(); + + l->numels = 0; + + /* head/tail sentinels and mid pointer */ + l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); + l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); + l->head_sentinel->next = l->tail_sentinel; + l->tail_sentinel->prev = l->head_sentinel; + l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL; + l->head_sentinel->data = l->tail_sentinel->data = NULL; + + /* iteration attributes */ + l->iter_active = 0; + l->iter_pos = 0; + l->iter_curentry = NULL; + + /* free-list attributes */ + l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *)); + l->spareelsnum = 0; + +#ifdef SIMCLIST_WITH_THREADS + l->threadcount = 0; +#endif + + list_attributes_setdefaults(l); + + assert(list_repOk(l)); + assert(list_attrOk(l)); + + return 0; +} + +void list_destroy(list_t *restrict l) { + unsigned int i; + + list_clear(l); + for (i = 0; i < l->spareelsnum; i++) { + free(l->spareels[i]); + } + free(l->spareels); + free(l->head_sentinel); + free(l->tail_sentinel); +} + +int list_attributes_setdefaults(list_t *restrict l) { + l->attrs.comparator = NULL; + l->attrs.seeker = NULL; + + /* also free() element data when removing and element from the list */ + l->attrs.meter = NULL; + l->attrs.copy_data = 0; + + l->attrs.hasher = NULL; + + /* serializer/unserializer */ + l->attrs.serializer = NULL; + l->attrs.unserializer = NULL; + + assert(list_attrOk(l)); + + return 0; +} + +/* setting list properties */ +int list_attributes_comparator(list_t *restrict l, element_comparator comparator_fun) { + if (l == NULL) return -1; + + l->attrs.comparator = comparator_fun; + + assert(list_attrOk(l)); + + return 0; +} + +int list_attributes_seeker(list_t *restrict l, element_seeker seeker_fun) { + if (l == NULL) return -1; + + l->attrs.seeker = seeker_fun; + assert(list_attrOk(l)); + + return 0; +} + +int list_attributes_copy(list_t *restrict l, element_meter metric_fun, int copy_data) { + if (l == NULL || (metric_fun == NULL && copy_data != 0)) return -1; + + l->attrs.meter = metric_fun; + l->attrs.copy_data = copy_data; + + assert(list_attrOk(l)); + + return 0; +} + +int list_attributes_hash_computer(list_t *restrict l, element_hash_computer hash_computer_fun) { + if (l == NULL) return -1; + + l->attrs.hasher = hash_computer_fun; + assert(list_attrOk(l)); + return 0; +} + +int list_attributes_serializer(list_t *restrict l, element_serializer serializer_fun) { + if (l == NULL) return -1; + + l->attrs.serializer = serializer_fun; + assert(list_attrOk(l)); + return 0; +} + +int list_attributes_unserializer(list_t *restrict l, element_unserializer unserializer_fun) { + if (l == NULL) return -1; + + l->attrs.unserializer = unserializer_fun; + assert(list_attrOk(l)); + return 0; +} + +int list_append(list_t *restrict l, const void *data) { + return list_insert_at(l, data, l->numels); +} + +int list_prepend(list_t *restrict l, const void *data) { + return list_insert_at(l, data, 0); +} + +void *list_fetch(list_t *restrict l) { + return list_extract_at(l, 0); +} + +void *list_get_at(const list_t *restrict l, unsigned int pos) { + struct list_entry_s *tmp; + + tmp = list_findpos(l, pos); + + return (tmp != NULL ? tmp->data : NULL); +} + +void *list_get_max(const list_t *restrict l) { + return list_get_minmax(l, +1); +} + +void *list_get_min(const list_t *restrict l) { + return list_get_minmax(l, -1); +} + +/* REQUIRES {list->numels >= 1} + * return the min (versus < 0) or max value (v > 0) in l */ +static void *list_get_minmax(const list_t *restrict l, int versus) { + void *curminmax; + struct list_entry_s *s; + + if (l->attrs.comparator == NULL || l->numels == 0) + return NULL; + + curminmax = l->head_sentinel->next->data; + for (s = l->head_sentinel->next->next; s != l->tail_sentinel; s = s->next) { + if (l->attrs.comparator(curminmax, s->data) * versus > 0) + curminmax = s->data; + } + + return curminmax; +} + +/* set tmp to point to element at index posstart in l */ +static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart) { + struct list_entry_s *ptr; + float x; + int i; + + /* accept 1 slot overflow for fetching head and tail sentinels */ + if (posstart < -1 || posstart > (int)l->numels) return NULL; + + x = (float)(posstart+1) / l->numels; + if (x <= 0.25) { + /* first quarter: get to posstart from head */ + for (i = -1, ptr = l->head_sentinel; i < posstart; ptr = ptr->next, i++); + } else if (x < 0.5) { + /* second quarter: get to posstart from mid */ + for (i = (l->numels-1)/2, ptr = l->mid; i > posstart; ptr = ptr->prev, i--); + } else if (x <= 0.75) { + /* third quarter: get to posstart from mid */ + for (i = (l->numels-1)/2, ptr = l->mid; i < posstart; ptr = ptr->next, i++); + } else { + /* fourth quarter: get to posstart from tail */ + for (i = l->numels, ptr = l->tail_sentinel; i > posstart; ptr = ptr->prev, i--); + } + + return ptr; +} + +void *list_extract_at(list_t *restrict l, unsigned int pos) { + struct list_entry_s *tmp; + void *data; + + if (l->iter_active || pos >= l->numels) return NULL; + + tmp = list_findpos(l, pos); + data = tmp->data; + + tmp->data = NULL; /* save data from list_drop_elem() free() */ + list_drop_elem(l, tmp, pos); + l->numels--; + + assert(list_repOk(l)); + + return data; +} + +int list_insert_at(list_t *restrict l, const void *data, unsigned int pos) { + struct list_entry_s *lent, *succ, *prec; + + if (l->iter_active || pos > l->numels) return -1; + + /* this code optimizes malloc() with a free-list */ + if (l->spareelsnum > 0) { + lent = l->spareels[l->spareelsnum-1]; + l->spareelsnum--; + } else { + lent = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); + if (lent == NULL) + return -1; + } + + if (l->attrs.copy_data) { + /* make room for user' data (has to be copied) */ + size_t datalen = l->attrs.meter(data); + lent->data = (struct list_entry_s *)malloc(datalen); + memcpy(lent->data, data, datalen); + } else { + lent->data = (void*)data; + } + + /* actually append element */ + prec = list_findpos(l, pos-1); + succ = prec->next; + + prec->next = lent; + lent->prev = prec; + lent->next = succ; + succ->prev = lent; + + l->numels++; + + /* fix mid pointer */ + if (l->numels == 1) { /* first element, set pointer */ + l->mid = lent; + } else if (l->numels % 2) { /* now odd */ + if (pos >= (l->numels-1)/2) l->mid = l->mid->next; + } else { /* now even */ + if (pos <= (l->numels-1)/2) l->mid = l->mid->prev; + } + + assert(list_repOk(l)); + + return 1; +} + +int list_delete(list_t *restrict l, const void *data) { + int pos, r; + + pos = list_locate(l, data); + if (pos < 0) + return -1; + + r = list_delete_at(l, pos); + if (r < 0) + return -1; + + assert(list_repOk(l)); + + return 0; +} + +int list_delete_at(list_t *restrict l, unsigned int pos) { + struct list_entry_s *delendo; + + + if (l->iter_active || pos >= l->numels) return -1; + + delendo = list_findpos(l, pos); + + list_drop_elem(l, delendo, pos); + + l->numels--; + + + assert(list_repOk(l)); + + return 0; +} + +int list_delete_range(list_t *restrict l, unsigned int posstart, unsigned int posend) { + struct list_entry_s *lastvalid, *tmp, *tmp2; + unsigned int numdel, midposafter, i; + int movedx; + + if (l->iter_active || posend < posstart || posend >= l->numels) return -1; + + numdel = posend - posstart + 1; + if (numdel == l->numels) return list_clear(l); + + tmp = list_findpos(l, posstart); /* first el to be deleted */ + lastvalid = tmp->prev; /* last valid element */ + + midposafter = (l->numels-1-numdel)/2; + + midposafter = midposafter < posstart ? midposafter : midposafter+numdel; + movedx = midposafter - (l->numels-1)/2; + + if (movedx > 0) { /* move right */ + for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->next, i++); + } else { /* move left */ + movedx = -movedx; + for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->prev, i++); + } + + assert(posstart == 0 || lastvalid != l->head_sentinel); + i = posstart; + if (l->attrs.copy_data) { + /* also free element data */ + for (; i <= posend; i++) { + tmp2 = tmp; + tmp = tmp->next; + if (tmp2->data != NULL) free(tmp2->data); + if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { + l->spareels[l->spareelsnum++] = tmp2; + } else { + free(tmp2); + } + } + } else { + /* only free containers */ + for (; i <= posend; i++) { + tmp2 = tmp; + tmp = tmp->next; + if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { + l->spareels[l->spareelsnum++] = tmp2; + } else { + free(tmp2); + } + } + } + assert(i == posend+1 && (posend != l->numels || tmp == l->tail_sentinel)); + + lastvalid->next = tmp; + tmp->prev = lastvalid; + + l->numels -= posend - posstart + 1; + + assert(list_repOk(l)); + + return numdel; +} + +int list_clear(list_t *restrict l) { + struct list_entry_s *s; + unsigned int numels; + + /* will be returned */ + numels = l->numels; + + if (l->iter_active) return -1; + + if (l->attrs.copy_data) { /* also free user data */ + /* spare a loop conditional with two loops: spareing elems and freeing elems */ + for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) { + /* move elements as spares as long as there is room */ + if (s->data != NULL) free(s->data); + l->spareels[l->spareelsnum++] = s; + } + while (s != l->tail_sentinel) { + /* free the remaining elems */ + if (s->data != NULL) free(s->data); + s = s->next; + free(s->prev); + } + l->head_sentinel->next = l->tail_sentinel; + l->tail_sentinel->prev = l->head_sentinel; + } else { /* only free element containers */ + /* spare a loop conditional with two loops: spareing elems and freeing elems */ + for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) { + /* move elements as spares as long as there is room */ + l->spareels[l->spareelsnum++] = s; + } + while (s != l->tail_sentinel) { + /* free the remaining elems */ + s = s->next; + free(s->prev); + } + l->head_sentinel->next = l->tail_sentinel; + l->tail_sentinel->prev = l->head_sentinel; + } + l->numels = 0; + l->mid = NULL; + + assert(list_repOk(l)); + + return numels; +} + +unsigned int list_size(const list_t *restrict l) { + return l->numels; +} + +int list_empty(const list_t *restrict l) { + return (l->numels == 0); +} + +int list_locate(const list_t *restrict l, const void *data) { + struct list_entry_s *el; + int pos = 0; + + if (l->attrs.comparator != NULL) { + /* use comparator */ + for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) { + if (l->attrs.comparator(data, el->data) == 0) break; + } + } else { + /* compare references */ + for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) { + if (el->data == data) break; + } + } + if (el == l->tail_sentinel) return -1; + + return pos; +} + +void *list_seek(list_t *restrict l, const void *indicator) { + const struct list_entry_s *iter; + + if (l->attrs.seeker == NULL) return NULL; + + for (iter = l->head_sentinel->next; iter != l->tail_sentinel; iter = iter->next) { + if (l->attrs.seeker(iter->data, indicator) != 0) return iter->data; + } + + return NULL; +} + +int list_contains(const list_t *restrict l, const void *data) { + return (list_locate(l, data) >= 0); +} + +int list_concat(const list_t *l1, const list_t *l2, list_t *restrict dest) { + struct list_entry_s *el, *srcel; + unsigned int cnt; + int err; + + + if (l1 == NULL || l2 == NULL || dest == NULL || l1 == dest || l2 == dest) + return -1; + + list_init(dest); + + dest->numels = l1->numels + l2->numels; + if (dest->numels == 0) + return 0; + + /* copy list1 */ + srcel = l1->head_sentinel->next; + el = dest->head_sentinel; + while (srcel != l1->tail_sentinel) { + el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); + el->next->prev = el; + el = el->next; + el->data = srcel->data; + srcel = srcel->next; + } + dest->mid = el; /* approximate position (adjust later) */ + /* copy list 2 */ + srcel = l2->head_sentinel->next; + while (srcel != l2->tail_sentinel) { + el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); + el->next->prev = el; + el = el->next; + el->data = srcel->data; + srcel = srcel->next; + } + el->next = dest->tail_sentinel; + dest->tail_sentinel->prev = el; + + /* fix mid pointer */ + err = l2->numels - l1->numels; + if ((err+1)/2 > 0) { /* correct pos RIGHT (err-1)/2 moves */ + err = (err+1)/2; + for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->next; + } else if (err/2 < 0) { /* correct pos LEFT (err/2)-1 moves */ + err = -err/2; + for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->prev; + } + + assert(!(list_repOk(l1) && list_repOk(l2)) || list_repOk(dest)); + + return 0; +} + +int list_sort(list_t *restrict l, int versus) { + if (l->iter_active || l->attrs.comparator == NULL) /* cannot modify list in the middle of an iteration */ + return -1; + + if (l->numels <= 1) + return 0; + list_sort_quicksort(l, versus, 0, l->head_sentinel->next, l->numels-1, l->tail_sentinel->prev); + assert(list_repOk(l)); + return 0; +} + +#ifdef SIMCLIST_WITH_THREADS +struct list_sort_wrappedparams { + list_t *restrict l; + int versus; + unsigned int first, last; + struct list_entry_s *fel, *lel; +}; + +static void *list_sort_quicksort_threadwrapper(void *wrapped_params) { + struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)wrapped_params; + list_sort_quicksort(wp->l, wp->versus, wp->first, wp->fel, wp->last, wp->lel); + free(wp); + pthread_exit(NULL); + return NULL; +} +#endif + +static inline void list_sort_selectionsort(list_t *restrict l, int versus, + unsigned int first, struct list_entry_s *fel, + unsigned int last, struct list_entry_s *lel) { + struct list_entry_s *cursor, *toswap, *firstunsorted; + void *tmpdata; + + if (last <= first) /* <= 1-element lists are always sorted */ + return; + + for (firstunsorted = fel; firstunsorted != lel; firstunsorted = firstunsorted->next) { + /* find min or max in the remainder of the list */ + for (toswap = firstunsorted, cursor = firstunsorted->next; cursor != lel->next; cursor = cursor->next) + if (l->attrs.comparator(toswap->data, cursor->data) * -versus > 0) toswap = cursor; + if (toswap != firstunsorted) { /* swap firstunsorted with toswap */ + tmpdata = firstunsorted->data; + firstunsorted->data = toswap->data; + toswap->data = tmpdata; + } + } +} + +static void list_sort_quicksort(list_t *restrict l, int versus, + unsigned int first, struct list_entry_s *fel, + unsigned int last, struct list_entry_s *lel) { + unsigned int pivotid; + unsigned int i; + register struct list_entry_s *pivot; + struct list_entry_s *left, *right; + void *tmpdata; +#ifdef SIMCLIST_WITH_THREADS + pthread_t tid; + int traised; +#endif + + + if (last <= first) /* <= 1-element lists are always sorted */ + return; + + if (last - first+1 <= SIMCLIST_MINQUICKSORTELS) { + list_sort_selectionsort(l, versus, first, fel, last, lel); + return; + } + + /* base of iteration: one element list */ + if (! (last > first)) return; + + pivotid = (get_random() % (last - first + 1)); + /* pivotid = (last - first + 1) / 2; */ + + /* find pivot */ + if (pivotid < (last - first + 1)/2) { + for (i = 0, pivot = fel; i < pivotid; pivot = pivot->next, i++); + } else { + for (i = last - first, pivot = lel; i > pivotid; pivot = pivot->prev, i--); + } + + /* smaller PIVOT bigger */ + left = fel; + right = lel; + /* iterate --- left ---> PIV <--- right --- */ + while (left != pivot && right != pivot) { + for (; left != pivot && (l->attrs.comparator(left->data, pivot->data) * -versus <= 0); left = left->next); + /* left points to a smaller element, or to pivot */ + for (; right != pivot && (l->attrs.comparator(right->data, pivot->data) * -versus >= 0); right = right->prev); + /* right points to a bigger element, or to pivot */ + if (left != pivot && right != pivot) { + /* swap, then move iterators */ + tmpdata = left->data; + left->data = right->data; + right->data = tmpdata; + + left = left->next; + right = right->prev; + } + } + + /* now either left points to pivot (end run), or right */ + if (right == pivot) { /* left part longer */ + while (left != pivot) { + if (l->attrs.comparator(left->data, pivot->data) * -versus > 0) { + tmpdata = left->data; + left->data = pivot->prev->data; + pivot->prev->data = pivot->data; + pivot->data = tmpdata; + pivot = pivot->prev; + pivotid--; + if (pivot == left) break; + } else { + left = left->next; + } + } + } else { /* right part longer */ + while (right != pivot) { + if (l->attrs.comparator(right->data, pivot->data) * -versus < 0) { + /* move current right before pivot */ + tmpdata = right->data; + right->data = pivot->next->data; + pivot->next->data = pivot->data; + pivot->data = tmpdata; + pivot = pivot->next; + pivotid++; + if (pivot == right) break; + } else { + right = right->prev; + } + } + } + + /* sort sublists A and B : |---A---| pivot |---B---| */ + +#ifdef SIMCLIST_WITH_THREADS + traised = 0; + if (pivotid > 0) { + /* prepare wrapped args, then start thread */ + if (l->threadcount < SIMCLIST_MAXTHREADS-1) { + struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)malloc(sizeof(struct list_sort_wrappedparams)); + l->threadcount++; + traised = 1; + wp->l = l; + wp->versus = versus; + wp->first = first; + wp->fel = fel; + wp->last = first+pivotid-1; + wp->lel = pivot->prev; + if (pthread_create(&tid, NULL, list_sort_quicksort_threadwrapper, wp) != 0) { + free(wp); + traised = 0; + list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev); + } + } else { + list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev); + } + } + if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel); + if (traised) { + pthread_join(tid, (void **)NULL); + l->threadcount--; + } +#else + if (pivotid > 0) list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev); + if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel); +#endif +} + +int list_iterator_start(list_t *restrict l) { + if (l->iter_active) return 0; + l->iter_pos = 0; + l->iter_active = 1; + l->iter_curentry = l->head_sentinel->next; + return 1; +} + +void *list_iterator_next(list_t *restrict l) { + void *toret; + + if (! l->iter_active) return NULL; + + toret = l->iter_curentry->data; + l->iter_curentry = l->iter_curentry->next; + l->iter_pos++; + + return toret; +} + +int list_iterator_hasnext(const list_t *restrict l) { + if (! l->iter_active) return 0; + return (l->iter_pos < l->numels); +} + +int list_iterator_stop(list_t *restrict l) { + if (! l->iter_active) return 0; + l->iter_pos = 0; + l->iter_active = 0; + return 1; +} + +int list_hash(const list_t *restrict l, list_hash_t *restrict hash) { + struct list_entry_s *x; + list_hash_t tmphash; + + assert(hash != NULL); + + tmphash = l->numels * 2 + 100; + if (l->attrs.hasher == NULL) { +#ifdef SIMCLIST_ALLOW_LOCATIONBASED_HASHES + /* ENABLE WITH CARE !! */ +#warning "Memlocation-based hash is consistent only for testing modification in the same program run." + int i; + + /* only use element references */ + for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { + for (i = 0; i < sizeof(x->data); i++) { + tmphash += (tmphash ^ (uintptr_t)x->data); + } + tmphash += tmphash % l->numels; + } +#else + return -1; +#endif + } else { + /* hash each element with the user-given function */ + for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { + tmphash += tmphash ^ l->attrs.hasher(x->data); + tmphash += tmphash % l->numels; + } + } + + *hash = tmphash; + + return 0; +} + +#ifndef SIMCLIST_NO_DUMPRESTORE +int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *restrict info) { + int32_t terminator_head, terminator_tail; + uint32_t elemlen; + off_t hop; + + + /* version */ + READ_ERRCHECK(fd, & info->version, sizeof(info->version)); + info->version = ntohs(info->version); + if (info->version > SIMCLIST_DUMPFORMAT_VERSION) { + errno = EILSEQ; + return -1; + } + + /* timestamp.tv_sec and timestamp.tv_usec */ + READ_ERRCHECK(fd, & info->timestamp.tv_sec, sizeof(info->timestamp.tv_sec)); + info->timestamp.tv_sec = ntohl(info->timestamp.tv_sec); + READ_ERRCHECK(fd, & info->timestamp.tv_usec, sizeof(info->timestamp.tv_usec)); + info->timestamp.tv_usec = ntohl(info->timestamp.tv_usec); + + /* list terminator (to check thereafter) */ + READ_ERRCHECK(fd, & terminator_head, sizeof(terminator_head)); + terminator_head = ntohl(terminator_head); + + /* list size */ + READ_ERRCHECK(fd, & info->list_size, sizeof(info->list_size)); + info->list_size = ntohl(info->list_size); + + /* number of elements */ + READ_ERRCHECK(fd, & info->list_numels, sizeof(info->list_numels)); + info->list_numels = ntohl(info->list_numels); + + /* length of each element (for checking for consistency) */ + READ_ERRCHECK(fd, & elemlen, sizeof(elemlen)); + elemlen = ntohl(elemlen); + + /* list hash */ + READ_ERRCHECK(fd, & info->list_hash, sizeof(info->list_hash)); + info->list_hash = ntohl(info->list_hash); + + /* check consistency */ + if (elemlen > 0) { + /* constant length, hop by size only */ + hop = info->list_size; + } else { + /* non-constant length, hop by size + all element length blocks */ + hop = info->list_size + elemlen*info->list_numels; + } + if (lseek(fd, hop, SEEK_CUR) == -1) { + return -1; + } + + /* read the trailing value and compare with terminator_head */ + READ_ERRCHECK(fd, & terminator_tail, sizeof(terminator_tail)); + terminator_tail = ntohl(terminator_tail); + + if (terminator_head == terminator_tail) + info->consistent = 1; + else + info->consistent = 0; + + return 0; +} + +int list_dump_getinfo_file(const char *restrict filename, list_dump_info_t *restrict info) { + int fd, ret; + + fd = open(filename, O_RDONLY, 0); + if (fd < 0) return -1; + + ret = list_dump_getinfo_filedescriptor(fd, info); + close(fd); + + return ret; +} + +int list_dump_filedescriptor(const list_t *restrict l, int fd, size_t *restrict len) { + struct list_entry_s *x; + void *ser_buf; + uint32_t bufsize; + struct timeval timeofday; + struct list_dump_header_s header; + + if (l->attrs.meter == NULL && l->attrs.serializer == NULL) { + errno = ENOTTY; + return -1; + } + + /**** DUMP FORMAT **** + + [ ver timestamp | totlen numels elemlen hash | DATA ] + + where DATA can be: + @ for constant-size list (element size is constant; elemlen > 0) + [ elem elem ... elem ] + @ for other lists (element size dictated by element_meter each time; elemlen <= 0) + [ size elem size elem ... size elem ] + + all integers are encoded in NETWORK BYTE FORMAT + *****/ + + + /* prepare HEADER */ + /* version */ + header.ver = htons( SIMCLIST_DUMPFORMAT_VERSION ); + + /* timestamp */ + gettimeofday(&timeofday, NULL); + header.timestamp_sec = htonl(timeofday.tv_sec); + header.timestamp_usec = htonl(timeofday.tv_usec); + + header.rndterm = htonl((int32_t)get_random()); + + /* total list size is postprocessed afterwards */ + + /* number of elements */ + header.numels = htonl(l->numels); + + /* include an hash, if possible */ + if (l->attrs.hasher != NULL) { + if (htonl(list_hash(l, & header.listhash)) != 0) { + /* could not compute list hash! */ + return -1; + } + } else { + header.listhash = htonl(0); + } + + header.totlistlen = header.elemlen = 0; + + /* leave room for the header at the beginning of the file */ + if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) { + /* errno set by lseek() */ + return -1; + } + + /* write CONTENT */ + if (l->numels > 0) { + /* SPECULATE that the list has constant element size */ + + if (l->attrs.serializer != NULL) { /* user user-specified serializer */ + /* get preliminary length of serialized element in header.elemlen */ + ser_buf = l->attrs.serializer(l->head_sentinel->next->data, & header.elemlen); + free(ser_buf); + /* request custom serialization of each element */ + for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { + ser_buf = l->attrs.serializer(x->data, &bufsize); + header.totlistlen += bufsize; + if (header.elemlen != 0) { /* continue on speculation */ + if (header.elemlen != bufsize) { + free(ser_buf); + /* constant element length speculation broken! */ + header.elemlen = 0; + header.totlistlen = 0; + x = l->head_sentinel; + if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) { + /* errno set by lseek() */ + return -1; + } + /* restart from the beginning */ + continue; + } + /* speculation confirmed */ + WRITE_ERRCHECK(fd, ser_buf, bufsize); + } else { /* speculation found broken */ + WRITE_ERRCHECK(fd, & bufsize, sizeof(size_t)); + WRITE_ERRCHECK(fd, ser_buf, bufsize); + } + free(ser_buf); + } + } else if (l->attrs.meter != NULL) { + header.elemlen = (uint32_t)l->attrs.meter(l->head_sentinel->next->data); + + /* serialize the element straight from its data */ + for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { + bufsize = l->attrs.meter(x->data); + header.totlistlen += bufsize; + if (header.elemlen != 0) { + if (header.elemlen != bufsize) { + /* constant element length speculation broken! */ + header.elemlen = 0; + header.totlistlen = 0; + x = l->head_sentinel; + /* restart from the beginning */ + continue; + } + WRITE_ERRCHECK(fd, x->data, bufsize); + } else { + WRITE_ERRCHECK(fd, &bufsize, sizeof(size_t)); + WRITE_ERRCHECK(fd, x->data, bufsize); + } + } + } + /* adjust endianness */ + header.elemlen = htonl(header.elemlen); + header.totlistlen = htonl(header.totlistlen); + } + + /* write random terminator */ + WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); /* list terminator */ + + + /* write header */ + lseek(fd, 0, SEEK_SET); + + WRITE_ERRCHECK(fd, & header.ver, sizeof(header.ver)); /* version */ + WRITE_ERRCHECK(fd, & header.timestamp_sec, sizeof(header.timestamp_sec)); /* timestamp seconds */ + WRITE_ERRCHECK(fd, & header.timestamp_usec, sizeof(header.timestamp_usec)); /* timestamp microseconds */ + WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); /* random terminator */ + + WRITE_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen)); /* total length of elements */ + WRITE_ERRCHECK(fd, & header.numels, sizeof(header.numels)); /* number of elements */ + WRITE_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen)); /* size of each element, or 0 for independent */ + WRITE_ERRCHECK(fd, & header.listhash, sizeof(header.listhash)); /* list hash, or 0 for "ignore" */ + + + /* possibly store total written length in "len" */ + if (len != NULL) { + *len = sizeof(header) + ntohl(header.totlistlen); + } + + return 0; +} + +int list_restore_filedescriptor(list_t *restrict l, int fd, size_t *restrict len) { + struct list_dump_header_s header; + unsigned long cnt; + void *buf; + uint32_t elsize, totreadlen, totmemorylen; + + memset(& header, 0, sizeof(header)); + + /* read header */ + + /* version */ + READ_ERRCHECK(fd, &header.ver, sizeof(header.ver)); + header.ver = ntohs(header.ver); + if (header.ver != SIMCLIST_DUMPFORMAT_VERSION) { + errno = EILSEQ; + return -1; + } + + /* timestamp */ + READ_ERRCHECK(fd, & header.timestamp_sec, sizeof(header.timestamp_sec)); + header.timestamp_sec = ntohl(header.timestamp_sec); + READ_ERRCHECK(fd, & header.timestamp_usec, sizeof(header.timestamp_usec)); + header.timestamp_usec = ntohl(header.timestamp_usec); + + /* list terminator */ + READ_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); + + header.rndterm = ntohl(header.rndterm); + + /* total list size */ + READ_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen)); + header.totlistlen = ntohl(header.totlistlen); + + /* number of elements */ + READ_ERRCHECK(fd, & header.numels, sizeof(header.numels)); + header.numels = ntohl(header.numels); + + /* length of every element, or '0' = variable */ + READ_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen)); + header.elemlen = ntohl(header.elemlen); + + /* list hash, or 0 = 'ignore' */ + READ_ERRCHECK(fd, & header.listhash, sizeof(header.listhash)); + header.listhash = ntohl(header.listhash); + + + /* read content */ + totreadlen = totmemorylen = 0; + if (header.elemlen > 0) { + /* elements have constant size = header.elemlen */ + if (l->attrs.unserializer != NULL) { + /* use unserializer */ + buf = malloc(header.elemlen); + for (cnt = 0; cnt < header.numels; cnt++) { + READ_ERRCHECK(fd, buf, header.elemlen); + list_append(l, l->attrs.unserializer(buf, & elsize)); + totmemorylen += elsize; + } + } else { + /* copy verbatim into memory */ + for (cnt = 0; cnt < header.numels; cnt++) { + buf = malloc(header.elemlen); + READ_ERRCHECK(fd, buf, header.elemlen); + list_append(l, buf); + } + totmemorylen = header.numels * header.elemlen; + } + totreadlen = header.numels * header.elemlen; + } else { + /* elements have variable size. Each element is preceded by its size */ + if (l->attrs.unserializer != NULL) { + /* use unserializer */ + for (cnt = 0; cnt < header.numels; cnt++) { + READ_ERRCHECK(fd, & elsize, sizeof(elsize)); + buf = malloc((size_t)elsize); + READ_ERRCHECK(fd, buf, elsize); + totreadlen += elsize; + list_append(l, l->attrs.unserializer(buf, & elsize)); + totmemorylen += elsize; + } + } else { + /* copy verbatim into memory */ + for (cnt = 0; cnt < header.numels; cnt++) { + READ_ERRCHECK(fd, & elsize, sizeof(elsize)); + buf = malloc(elsize); + READ_ERRCHECK(fd, buf, elsize); + totreadlen += elsize; + list_append(l, buf); + } + totmemorylen = totreadlen; + } + } + + READ_ERRCHECK(fd, &elsize, sizeof(elsize)); /* read list terminator */ + elsize = ntohl(elsize); + + /* possibly verify the list consistency */ + /* wrt hash */ + /* don't do that + if (header.listhash != 0 && header.listhash != list_hash(l)) { + errno = ECANCELED; + return -1; + } + */ + + /* wrt header */ + if (totreadlen != header.totlistlen && (int32_t)elsize == header.rndterm) { + errno = EPROTO; + return -1; + } + + /* wrt file */ + if (lseek(fd, 0, SEEK_CUR) != lseek(fd, 0, SEEK_END)) { + errno = EPROTO; + return -1; + } + + if (len != NULL) { + *len = totmemorylen; + } + + return 0; +} + +int list_dump_file(const list_t *restrict l, const char *restrict filename, size_t *restrict len) { + int fd, oflag, mode; + +#ifndef _WIN32 + oflag = O_RDWR | O_CREAT | O_TRUNC; + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; +#else + oflag = _O_RDWR | _O_CREAT | _O_TRUNC; + mode = _S_IRUSR | _S_IWUSR | _S_IRGRP | _S_IROTH; +#endif + fd = open(filename, oflag, mode); + if (fd < 0) return -1; + + list_dump_filedescriptor(l, fd, len); + close(fd); + + return 0; +} + +int list_restore_file(list_t *restrict l, const char *restrict filename, size_t *restrict len) { + int fd; + + fd = open(filename, O_RDONLY, 0); + if (fd < 0) return -1; + + list_restore_filedescriptor(l, fd, len); + close(fd); + + return 0; +} +#endif /* ifndef SIMCLIST_NO_DUMPRESTORE */ + + +static int list_drop_elem(list_t *restrict l, struct list_entry_s *tmp, unsigned int pos) { + if (tmp == NULL) return -1; + + /* fix mid pointer. This is wrt the PRE situation */ + if (l->numels % 2) { /* now odd */ + /* sort out the base case by hand */ + if (l->numels == 1) l->mid = NULL; + else if (pos >= l->numels/2) l->mid = l->mid->prev; + } else { /* now even */ + if (pos < l->numels/2) l->mid = l->mid->next; + } + + tmp->prev->next = tmp->next; + tmp->next->prev = tmp->prev; + + /* free what's to be freed */ + if (l->attrs.copy_data && tmp->data != NULL) + free(tmp->data); + + if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { + l->spareels[l->spareelsnum++] = tmp; + } else { + free(tmp); + } + + return 0; +} + +/* ready-made comparators and meters */ +#define SIMCLIST_NUMBER_COMPARATOR(type) int list_comparator_##type(const void *a, const void *b) { return( *(type *)a < *(type *)b) - (*(type *)a > *(type *)b); } + +SIMCLIST_NUMBER_COMPARATOR(int8_t) +SIMCLIST_NUMBER_COMPARATOR(int16_t) +SIMCLIST_NUMBER_COMPARATOR(int32_t) +SIMCLIST_NUMBER_COMPARATOR(int64_t) + +SIMCLIST_NUMBER_COMPARATOR(uint8_t) +SIMCLIST_NUMBER_COMPARATOR(uint16_t) +SIMCLIST_NUMBER_COMPARATOR(uint32_t) +SIMCLIST_NUMBER_COMPARATOR(uint64_t) + +SIMCLIST_NUMBER_COMPARATOR(float) +SIMCLIST_NUMBER_COMPARATOR(double) + +int list_comparator_string(const void *a, const void *b) { return strcmp((const char *)b, (const char *)a); } + +/* ready-made metric functions */ +#define SIMCLIST_METER(type) size_t list_meter_##type(const void *el) { if (el) { /* kill compiler whinge */ } return sizeof(type); } + +SIMCLIST_METER(int8_t) +SIMCLIST_METER(int16_t) +SIMCLIST_METER(int32_t) +SIMCLIST_METER(int64_t) + +SIMCLIST_METER(uint8_t) +SIMCLIST_METER(uint16_t) +SIMCLIST_METER(uint32_t) +SIMCLIST_METER(uint64_t) + +SIMCLIST_METER(float) +SIMCLIST_METER(double) + +size_t list_meter_string(const void *el) { return strlen((const char *)el) + 1; } + +/* ready-made hashing functions */ +#define SIMCLIST_HASHCOMPUTER(type) list_hash_t list_hashcomputer_##type(const void *el) { return (list_hash_t)(*(type *)el); } + +SIMCLIST_HASHCOMPUTER(int8_t) +SIMCLIST_HASHCOMPUTER(int16_t) +SIMCLIST_HASHCOMPUTER(int32_t) +SIMCLIST_HASHCOMPUTER(int64_t) + +SIMCLIST_HASHCOMPUTER(uint8_t) +SIMCLIST_HASHCOMPUTER(uint16_t) +SIMCLIST_HASHCOMPUTER(uint32_t) +SIMCLIST_HASHCOMPUTER(uint64_t) + +SIMCLIST_HASHCOMPUTER(float) +SIMCLIST_HASHCOMPUTER(double) + +list_hash_t list_hashcomputer_string(const void *el) { + size_t l; + list_hash_t hash = 123; + const char *str = (const char *)el; + char plus; + + for (l = 0; str[l] != '\0'; l++) { + if (l) plus = hash ^ str[l]; + else plus = hash ^ (str[l] - str[0]); + hash += (plus << (CHAR_BIT * (l % sizeof(list_hash_t)))); + } + + return hash; +} + + +#ifndef NDEBUG +static int list_repOk(const list_t *restrict l) { + int ok, i; + struct list_entry_s *s; + + ok = (l != NULL) && ( + /* head/tail checks */ + (l->head_sentinel != NULL && l->tail_sentinel != NULL) && + (l->head_sentinel != l->tail_sentinel) && (l->head_sentinel->prev == NULL && l->tail_sentinel->next == NULL) && + /* empty list */ + (l->numels > 0 || (l->mid == NULL && l->head_sentinel->next == l->tail_sentinel && l->tail_sentinel->prev == l->head_sentinel)) && + /* spare elements checks */ + l->spareelsnum <= SIMCLIST_MAX_SPARE_ELEMS + ); + + if (!ok) return 0; + + if (l->numels >= 1) { + /* correct referencing */ + for (i = -1, s = l->head_sentinel; i < (int)(l->numels-1)/2 && s->next != NULL; i++, s = s->next) { + if (s->next->prev != s) break; + } + ok = (i == (int)(l->numels-1)/2 && l->mid == s); + if (!ok) return 0; + for (; s->next != NULL; i++, s = s->next) { + if (s->next->prev != s) break; + } + ok = (i == (int)l->numels && s == l->tail_sentinel); + } + + return ok; +} + +static int list_attrOk(const list_t *restrict l) { + int ok; + + ok = (l->attrs.copy_data == 0 || l->attrs.meter != NULL); + return ok; +} + +#endif + diff -Nru acsccid-1.0.8/src/simclist.h acsccid-1.1.0/src/simclist.h --- acsccid-1.0.8/src/simclist.h 1970-01-01 00:00:00.000000000 +0000 +++ acsccid-1.1.0/src/simclist.h 2014-12-10 08:32:26.000000000 +0000 @@ -0,0 +1,980 @@ +/* + * Copyright (c) 2007,2008 Mij + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +/* + * SimCList library. See http://mij.oltrelinux.com/devel/simclist + */ + + +#ifndef SIMCLIST_H +#define SIMCLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#ifndef SIMCLIST_NO_DUMPRESTORE +# ifndef _WIN32 +# include /* list_dump_info_t's struct timeval */ +# else +# include +# endif +#endif + + +/* Be friend of both C90 and C99 compilers */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + /* "inline" and "restrict" are keywords */ +#else +# define inline /* inline */ +# define restrict /* restrict */ +#endif + + +/** + * Type representing list hashes. + * + * This is a signed integer value. + */ +typedef int32_t list_hash_t; + +#ifndef SIMCLIST_NO_DUMPRESTORE +typedef struct { + uint16_t version; /* dump version */ + struct timeval timestamp; /* when the list has been dumped, seconds since UNIX epoch */ + uint32_t list_size; + uint32_t list_numels; + list_hash_t list_hash; /* hash of the list when dumped, or 0 if invalid */ + uint32_t dumpsize; + int consistent; /* 1 if the dump is verified complete/consistent; 0 otherwise */ +} list_dump_info_t; +#endif + +/** + * a comparator of elements. + * + * A comparator of elements is a function that: + * -# receives two references to elements a and b + * -# returns {<0, 0, >0} if (a > b), (a == b), (a < b) respectively + * + * It is responsability of the function to handle possible NULL values. + */ +typedef int (*element_comparator)(const void *a, const void *b); + +/** + * a seeker of elements. + * + * An element seeker is a function that: + * -# receives a reference to an element el + * -# receives a reference to some indicator data + * -# returns non-0 if the element matches the indicator, 0 otherwise + * + * It is responsability of the function to handle possible NULL values in any + * argument. + */ +typedef int (*element_seeker)(const void *el, const void *indicator); + +/** + * an element lenght meter. + * + * An element meter is a function that: + * -# receives the reference to an element el + * -# returns its size in bytes + * + * It is responsability of the function to handle possible NULL values. + */ +typedef size_t (*element_meter)(const void *el); + +/** + * a function computing the hash of elements. + * + * An hash computing function is a function that: + * -# receives the reference to an element el + * -# returns a hash value for el + * + * It is responsability of the function to handle possible NULL values. + */ +typedef list_hash_t (*element_hash_computer)(const void *el); + +/** + * a function for serializing an element. + * + * A serializer function is one that gets a reference to an element, + * and returns a reference to a buffer that contains its serialization + * along with the length of this buffer. + * It is responsability of the function to handle possible NULL values, + * returning a NULL buffer and a 0 buffer length. + * + * These functions have 3 goals: + * -# "freeze" and "flatten" the memory representation of the element + * -# provide a portable (wrt byte order, or type size) representation of the element, if the dump can be used on different sw/hw combinations + * -# possibly extract a compressed representation of the element + * + * @param el reference to the element data + * @param serialize_buffer reference to fill with the length of the buffer + * @return reference to the buffer with the serialized data + */ +typedef void *(*element_serializer)(const void *restrict el, uint32_t *restrict serializ_len); + +/** + * a function for un-serializing an element. + * + * An unserializer function accomplishes the inverse operation of the + * serializer function. An unserializer function is one that gets a + * serialized representation of an element and turns it backe to the original + * element. The serialized representation is passed as a reference to a buffer + * with its data, and the function allocates and returns the buffer containing + * the original element, and it sets the length of this buffer into the + * integer passed by reference. + * + * @param data reference to the buffer with the serialized representation of the element + * @param data_len reference to the location where to store the length of the data in the buffer returned + * @return reference to a buffer with the original, unserialized representation of the element + */ +typedef void *(*element_unserializer)(const void *restrict data, uint32_t *restrict data_len); + +/* [private-use] list entry -- olds actual user datum */ +struct list_entry_s { + void *data; + + /* doubly-linked list service references */ + struct list_entry_s *next; + struct list_entry_s *prev; +}; + +/* [private-use] list attributes */ +struct list_attributes_s { + /* user-set routine for comparing list elements */ + element_comparator comparator; + /* user-set routing for seeking elements */ + element_seeker seeker; + /* user-set routine for determining the length of an element */ + element_meter meter; + int copy_data; + /* user-set routine for computing the hash of an element */ + element_hash_computer hasher; + /* user-set routine for serializing an element */ + element_serializer serializer; + /* user-set routine for unserializing an element */ + element_unserializer unserializer; +}; + +/** list object */ +typedef struct { + struct list_entry_s *head_sentinel; + struct list_entry_s *tail_sentinel; + struct list_entry_s *mid; + + unsigned int numels; + + /* array of spare elements */ + struct list_entry_s **spareels; + unsigned int spareelsnum; + +#ifdef SIMCLIST_WITH_THREADS + /* how many threads are currently running */ + unsigned int threadcount; +#endif + + /* service variables for list iteration */ + int iter_active; + unsigned int iter_pos; + struct list_entry_s *iter_curentry; + + /* list attributes */ + struct list_attributes_s attrs; +} list_t; + +/** + * initialize a list object for use. + * + * @param l must point to a user-provided memory location + * @return 0 for success. -1 for failure + */ +int list_init(list_t *restrict l); + +/** + * completely remove the list from memory. + * + * This function is the inverse of list_init(). It is meant to be called when + * the list is no longer going to be used. Elements and possible memory taken + * for internal use are freed. + * + * @param l list to destroy + */ +void list_destroy(list_t *restrict l); + +/** + * set the comparator function for list elements. + * + * Comparator functions are used for searching and sorting. If NULL is passed + * as reference to the function, the comparator is disabled. + * + * @param l list to operate + * @param comparator_fun pointer to the actual comparator function + * @return 0 if the attribute was successfully set; -1 otherwise + * + * @see element_comparator() + */ +int list_attributes_comparator(list_t *restrict l, element_comparator comparator_fun); + +/** + * set a seeker function for list elements. + * + * Seeker functions are used for finding elements. If NULL is passed as reference + * to the function, the seeker is disabled. + * + * @param l list to operate + * @param seeker_fun pointer to the actual seeker function + * @return 0 if the attribute was successfully set; -1 otherwise + * + * @see element_seeker() + */ +int list_attributes_seeker(list_t *restrict l, element_seeker seeker_fun); + +/** + * require to free element data when list entry is removed (default: don't free). + * + * [ advanced preference ] + * + * By default, when an element is removed from the list, it disappears from + * the list by its actual data is not free()d. With this option, every + * deletion causes element data to be freed. + * + * It is responsability of this function to correctly handle NULL values, if + * NULL elements are inserted into the list. + * + * @param l list to operate + * @param metric_fun pointer to the actual metric function + * @param copy_data 0: do not free element data (default); non-0: do free + * @return 0 if the attribute was successfully set; -1 otherwise + * + * @see element_meter() + * @see list_meter_int8_t() + * @see list_meter_int16_t() + * @see list_meter_int32_t() + * @see list_meter_int64_t() + * @see list_meter_uint8_t() + * @see list_meter_uint16_t() + * @see list_meter_uint32_t() + * @see list_meter_uint64_t() + * @see list_meter_float() + * @see list_meter_double() + * @see list_meter_string() + */ +int list_attributes_copy(list_t *restrict l, element_meter metric_fun, int copy_data); + +/** + * set the element hash computing function for the list elements. + * + * [ advanced preference ] + * + * An hash can be requested depicting the list status at a given time. An hash + * only depends on the elements and their order. By default, the hash of an + * element is only computed on its reference. With this function, the user can + * set a custom function computing the hash of an element. If such function is + * provided, the list_hash() function automatically computes the list hash using + * the custom function instead of simply referring to element references. + * + * @param l list to operate + * @param hash_computer_fun pointer to the actual hash computing function + * @return 0 if the attribute was successfully set; -1 otherwise + * + * @see element_hash_computer() + */ +int list_attributes_hash_computer(list_t *restrict l, element_hash_computer hash_computer_fun); + +/** + * set the element serializer function for the list elements. + * + * [ advanced preference ] + * + * Serialize functions are used for dumping the list to some persistent + * storage. The serializer function is called for each element; it is passed + * a reference to the element and a reference to a size_t object. It will + * provide (and return) the buffer with the serialization of the element and + * fill the size_t object with the length of this serialization data. + * + * @param l list to operate + * @param serializer_fun pointer to the actual serializer function + * @return 0 if the attribute was successfully set; -1 otherwise + * + * @see element_serializer() + * @see list_dump_filedescriptor() + * @see list_restore_filedescriptor() + */ +int list_attributes_serializer(list_t *restrict l, element_serializer serializer_fun); + +/** + * set the element unserializer function for the list elements. + * + * [ advanced preference ] + * + * Unserialize functions are used for restoring the list from some persistent + * storage. The unserializer function is called for each element segment read + * from the storage; it is passed the segment and a reference to an integer. + * It shall allocate and return a buffer compiled with the resumed memory + * representation of the element, and set the integer value to the length of + * this buffer. + * + * @param l list to operate + * @param unserializer_fun pointer to the actual unserializer function + * @return 0 if the attribute was successfully set; -1 otherwise + * + * @see element_unserializer() + * @see list_dump_filedescriptor() + * @see list_restore_filedescriptor() + */ +int list_attributes_unserializer(list_t *restrict l, element_unserializer unserializer_fun); + +/** + * append data at the end of the list. + * + * This function is useful for adding elements with a FIFO/queue policy. + * + * @param l list to operate + * @param data pointer to user data to append + * + * @return 1 for success. < 0 for failure + */ +int list_append(list_t *restrict l, const void *data); + +/** + * insert data in the head of the list. + * + * This function is useful for adding elements with a LIFO/Stack policy. + * + * @param l list to operate + * @param data pointer to user data to append + * + * @return 1 for success. < 0 for failure + */ +int list_prepend(list_t *restrict l, const void *restrict data); + +/** + * extract the element in the top of the list. + * + * This function is for using a list with a FIFO/queue policy. + * + * @param l list to operate + * @return reference to user datum, or NULL on errors + */ +void *list_fetch(list_t *restrict l); + +/** + * retrieve an element at a given position. + * + * @param l list to operate + * @param pos [0,size-1] position index of the element wanted + * @return reference to user datum, or NULL on errors + */ +void *list_get_at(const list_t *restrict l, unsigned int pos); + +/** + * return the maximum element of the list. + * + * @warning Requires a comparator function to be set for the list. + * + * Returns the maximum element with respect to the comparator function output. + * + * @see list_attributes_comparator() + * + * @param l list to operate + * @return the reference to the element, or NULL + */ +void *list_get_max(const list_t *restrict l); + +/** + * return the minimum element of the list. + * + * @warning Requires a comparator function to be set for the list. + * + * Returns the minimum element with respect to the comparator function output. + * + * @see list_attributes_comparator() + * + * @param l list to operate + * @return the reference to the element, or NULL + */ +void *list_get_min(const list_t *restrict l); + +/** + * retrieve and remove from list an element at a given position. + * + * @param l list to operate + * @param pos [0,size-1] position index of the element wanted + * @return reference to user datum, or NULL on errors + */ +void *list_extract_at(list_t *restrict l, unsigned int pos); + +/** + * insert an element at a given position. + * + * @param l list to operate + * @param data reference to data to be inserted + * @param pos [0,size-1] position index to insert the element at + * @return positive value on success. Negative on failure + */ +int list_insert_at(list_t *restrict l, const void *data, unsigned int pos); + +/** + * expunge the first found given element from the list. + * + * Inspects the given list looking for the given element; if the element + * is found, it is removed. Only the first occurence is removed. + * If a comparator function was not set, elements are compared by reference. + * Otherwise, the comparator is used to match the element. + * + * @param l list to operate + * @param data reference of the element to search for + * @return 0 on success. Negative value on failure + * + * @see list_attributes_comparator() + * @see list_delete_at() + */ +int list_delete(list_t *restrict l, const void *data); + +/** + * expunge an element at a given position from the list. + * + * @param l list to operate + * @param pos [0,size-1] position index of the element to be deleted + * @return 0 on success. Negative value on failure + */ +int list_delete_at(list_t *restrict l, unsigned int pos); + +/** + * expunge an array of elements from the list, given their position range. + * + * @param l list to operate + * @param posstart [0,size-1] position index of the first element to be deleted + * @param posend [posstart,size-1] position of the last element to be deleted + * @return the number of elements successfully removed on success, <0 on error + */ +int list_delete_range(list_t *restrict l, unsigned int posstart, unsigned int posend); + +/** + * clear all the elements off of the list. + * + * The element datums will not be freed. + * + * @see list_delete_range() + * @see list_size() + * + * @param l list to operate + * @return the number of elements removed on success, <0 on error + */ +int list_clear(list_t *restrict l); + +/** + * inspect the number of elements in the list. + * + * @param l list to operate + * @return number of elements currently held by the list + */ +unsigned int list_size(const list_t *restrict l); + +/** + * inspect whether the list is empty. + * + * @param l list to operate + * @return 0 iff the list is not empty + * + * @see list_size() + */ +int list_empty(const list_t *restrict l); + +/** + * find the position of an element in a list. + * + * @warning Requires a comparator function to be set for the list. + * + * Inspects the given list looking for the given element; if the element + * is found, its position into the list is returned. + * Elements are inspected comparing references if a comparator has not been + * set. Otherwise, the comparator is used to find the element. + * + * @param l list to operate + * @param data reference of the element to search for + * @return position of element in the list, or <0 if not found + * + * @see list_attributes_comparator() + * @see list_get_at() + */ +int list_locate(const list_t *restrict l, const void *data); + +/** + * returns an element given an indicator. + * + * @warning Requires a seeker function to be set for the list. + * + * Inspect the given list looking with the seeker if an element matches + * an indicator. If such element is found, the reference to the element + * is returned. + * + * @param l list to operate + * @param indicator indicator data to pass to the seeker along with elements + * @return reference to the element accepted by the seeker, or NULL if none found + */ +void *list_seek(list_t *restrict l, const void *indicator); + +/** + * inspect whether some data is member of the list. + * + * @warning Requires a comparator function to be set for the list. + * + * By default, a per-reference comparison is accomplished. That is, + * the data is in list if any element of the list points to the same + * location of data. + * A "semantic" comparison is accomplished, otherwise, if a comparator + * function has been set previously, with list_attributes_comparator(); + * in which case, the given data reference is believed to be in list iff + * comparator_fun(elementdata, userdata) == 0 for any element in the list. + * + * @param l list to operate + * @param data reference to the data to search + * @return 0 iff the list does not contain data as an element + * + * @see list_attributes_comparator() + */ +int list_contains(const list_t *restrict l, const void *data); + +/** + * concatenate two lists + * + * Concatenates one list with another, and stores the result into a + * user-provided list object, which must be different from both the + * lists to concatenate. Attributes from the original lists are not + * cloned. + * The destination list referred is threated as virgin room: if it + * is an existing list containing elements, memory leaks will happen. + * It is OK to specify the same list twice as source, for "doubling" + * it in the destination. + * + * @param l1 base list + * @param l2 list to append to the base + * @param dest reference to the destination list + * @return 0 for success, -1 for errors + */ +int list_concat(const list_t *l1, const list_t *l2, list_t *restrict dest); + +/** + * sort list elements. + * + * @warning Requires a comparator function to be set for the list. + * + * Sorts the list in ascending or descending order as specified by the versus + * flag. The algorithm chooses autonomously what algorithm is best suited for + * sorting the list wrt its current status. + * + * @param l list to operate + * @param versus positive: order small to big; negative: order big to small + * @return 0 iff sorting was successful + * + * @see list_attributes_comparator() + */ +int list_sort(list_t *restrict l, int versus); + +/** + * start an iteration session. + * + * This function prepares the list to be iterated. + * + * @param l list to operate + * @return 0 if the list cannot be currently iterated. >0 otherwise + * + * @see list_iterator_stop() + */ +int list_iterator_start(list_t *restrict l); + +/** + * return the next element in the iteration session. + * + * @param l list to operate + * @return element datum, or NULL on errors + */ +void *list_iterator_next(list_t *restrict l); + +/** + * inspect whether more elements are available in the iteration session. + * + * @param l list to operate + * @return 0 iff no more elements are available. + */ +int list_iterator_hasnext(const list_t *restrict l); + +/** + * end an iteration session. + * + * @param l list to operate + * @return 0 iff the iteration session cannot be stopped + */ +int list_iterator_stop(list_t *restrict l); + +/** + * return the hash of the current status of the list. + * + * @param l list to operate + * @param hash where the resulting hash is put + * + * @return 0 for success; <0 for failure + */ +int list_hash(const list_t *restrict l, list_hash_t *restrict hash); + +#ifndef SIMCLIST_NO_DUMPRESTORE +/** + * get meta informations on a list dump on filedescriptor. + * + * [ advanced function ] + * + * Extracts the meta information from a SimCList dump located in a file + * descriptor. The file descriptor must be open and positioned at the + * beginning of the SimCList dump block. + * + * @param fd file descriptor to get metadata from + * @param info reference to a dump metainformation structure to fill + * @return 0 for success; <0 for failure + * + * @see list_dump_filedescriptor() + */ +int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *restrict info); + +/** + * get meta informations on a list dump on file. + * + * [ advanced function ] + * + * Extracts the meta information from a SimCList dump located in a file. + * + * @param filename filename of the file to fetch from + * @param info reference to a dump metainformation structure to fill + * @return 0 for success; <0 for failure + * + * @see list_dump_filedescriptor() + */ +int list_dump_getinfo_file(const char *restrict filename, list_dump_info_t *restrict info); + +/** + * dump the list into an open, writable file descriptor. + * + * This function "dumps" the list to a persistent storage so it can be + * preserved across process terminations. + * When called, the file descriptor must be open for writing and positioned + * where the serialized data must begin. It writes its serialization of the + * list in a form which is portable across different architectures. Dump can + * be safely performed on stream-only (non seekable) descriptors. The file + * descriptor is not closed at the end of the operations. + * + * To use dump functions, either of these conditions must be satisfied: + * -# a metric function has been specified with list_attributes_copy() + * -# a serializer function has been specified with list_attributes_serializer() + * + * If a metric function has been specified, each element of the list is dumped + * as-is from memory, copying it from its pointer for its length down to the + * file descriptor. This might have impacts on portability of the dump to + * different architectures. + * + * If a serializer function has been specified, its result for each element is + * dumped to the file descriptor. + * + * + * @param l list to operate + * @param fd file descriptor to write to + * @param len location to store the resulting length of the dump (bytes), or NULL + * + * @return 0 if successful; -1 otherwise + * + * @see element_serializer() + * @see list_attributes_copy() + * @see list_attributes_serializer() + */ +int list_dump_filedescriptor(const list_t *restrict l, int fd, size_t *restrict len); + +/** + * dump the list to a file name. + * + * This function creates a filename and dumps the current content of the list + * to it. If the file exists it is overwritten. The number of bytes written to + * the file can be returned in a specified argument. + * + * @param l list to operate + * @param filename filename to write to + * @param len location to store the resulting length of the dump (bytes), or NULL + * + * @return 0 if successful; -1 otherwise + * + * @see list_attributes_copy() + * @see element_serializer() + * @see list_attributes_serializer() + * @see list_dump_filedescriptor() + * @see list_restore_file() + * + * This function stores a representation of the list + */ +int list_dump_file(const list_t *restrict l, const char *restrict filename, size_t *restrict len); + +/** + * restore the list from an open, readable file descriptor to memory. + * + * This function is the "inverse" of list_dump_filedescriptor(). It restores + * the list content from a (open, read-ready) file descriptor to memory. An + * unserializer might be needed to restore elements from the persistent + * representation back into memory-consistent format. List attributes can not + * be restored and must be set manually. + * + * @see list_dump_filedescriptor() + * @see list_attributes_serializer() + * @see list_attributes_unserializer() + * + * @param l list to restore to + * @param fd file descriptor to read from. + * @param len location to store the length of the dump read (bytes), or NULL + * @return 0 if successful; -1 otherwise + */ +int list_restore_filedescriptor(list_t *restrict l, int fd, size_t *restrict len); + +/** + * restore the list from a file name. + * + * This function restores the content of a list from a file into memory. It is + * the inverse of list_dump_file(). + * + * @see element_unserializer() + * @see list_attributes_unserializer() + * @see list_dump_file() + * @see list_restore_filedescriptor() + * + * @param l list to restore to + * @param filename filename to read data from + * @param len location to store the length of the dump read (bytes), or NULL + * @return 0 if successful; -1 otherwise + */ +int list_restore_file(list_t *restrict l, const char *restrict filename, size_t *len); +#endif + +/* ready-made comparators, meters and hash computers */ + /* comparator functions */ +/** + * ready-made comparator for int8_t elements. + * @see list_attributes_comparator() + */ +int list_comparator_int8_t(const void *a, const void *b); + +/** + * ready-made comparator for int16_t elements. + * @see list_attributes_comparator() + */ +int list_comparator_int16_t(const void *a, const void *b); + +/** + * ready-made comparator for int32_t elements. + * @see list_attributes_comparator() + */ +int list_comparator_int32_t(const void *a, const void *b); + +/** + * ready-made comparator for int64_t elements. + * @see list_attributes_comparator() + */ +int list_comparator_int64_t(const void *a, const void *b); + +/** + * ready-made comparator for uint8_t elements. + * @see list_attributes_comparator() + */ +int list_comparator_uint8_t(const void *a, const void *b); + +/** + * ready-made comparator for uint16_t elements. + * @see list_attributes_comparator() + */ +int list_comparator_uint16_t(const void *a, const void *b); + +/** + * ready-made comparator for uint32_t elements. + * @see list_attributes_comparator() + */ +int list_comparator_uint32_t(const void *a, const void *b); + +/** + * ready-made comparator for uint64_t elements. + * @see list_attributes_comparator() + */ +int list_comparator_uint64_t(const void *a, const void *b); + +/** + * ready-made comparator for float elements. + * @see list_attributes_comparator() + */ +int list_comparator_float(const void *a, const void *b); + +/** + * ready-made comparator for double elements. + * @see list_attributes_comparator() + */ +int list_comparator_double(const void *a, const void *b); + +/** + * ready-made comparator for string elements. + * @see list_attributes_comparator() + */ +int list_comparator_string(const void *a, const void *b); + + /* metric functions */ +/** + * ready-made metric function for int8_t elements. + * @see list_attributes_copy() + */ +size_t list_meter_int8_t(const void *el); + +/** + * ready-made metric function for int16_t elements. + * @see list_attributes_copy() + */ +size_t list_meter_int16_t(const void *el); + +/** + * ready-made metric function for int32_t elements. + * @see list_attributes_copy() + */ +size_t list_meter_int32_t(const void *el); + +/** + * ready-made metric function for int64_t elements. + * @see list_attributes_copy() + */ +size_t list_meter_int64_t(const void *el); + +/** + * ready-made metric function for uint8_t elements. + * @see list_attributes_copy() + */ +size_t list_meter_uint8_t(const void *el); + +/** + * ready-made metric function for uint16_t elements. + * @see list_attributes_copy() + */ +size_t list_meter_uint16_t(const void *el); + +/** + * ready-made metric function for uint32_t elements. + * @see list_attributes_copy() + */ +size_t list_meter_uint32_t(const void *el); + +/** + * ready-made metric function for uint64_t elements. + * @see list_attributes_copy() + */ +size_t list_meter_uint64_t(const void *el); + +/** + * ready-made metric function for float elements. + * @see list_attributes_copy() + */ +size_t list_meter_float(const void *el); + +/** + * ready-made metric function for double elements. + * @see list_attributes_copy() + */ +size_t list_meter_double(const void *el); + +/** + * ready-made metric function for string elements. + * @see list_attributes_copy() + */ +size_t list_meter_string(const void *el); + + /* hash functions */ +/** + * ready-made hash function for int8_t elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_int8_t(const void *el); + +/** + * ready-made hash function for int16_t elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_int16_t(const void *el); + +/** + * ready-made hash function for int32_t elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_int32_t(const void *el); + +/** + * ready-made hash function for int64_t elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_int64_t(const void *el); + +/** + * ready-made hash function for uint8_t elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_uint8_t(const void *el); + +/** + * ready-made hash function for uint16_t elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_uint16_t(const void *el); + +/** + * ready-made hash function for uint32_t elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_uint32_t(const void *el); + +/** + * ready-made hash function for uint64_t elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_uint64_t(const void *el); + +/** + * ready-made hash function for float elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_float(const void *el); + +/** + * ready-made hash function for double elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_double(const void *el); + +/** + * ready-made hash function for string elements. + * @see list_attributes_hash_computer() + */ +list_hash_t list_hashcomputer_string(const void *el); + +#ifdef __cplusplus +} +#endif + +#endif + diff -Nru acsccid-1.0.8/src/strlcpycat.h acsccid-1.1.0/src/strlcpycat.h --- acsccid-1.0.8/src/strlcpycat.h 2008-05-09 14:59:08.000000000 +0000 +++ acsccid-1.1.0/src/strlcpycat.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,10 +1,36 @@ /* - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) + * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) * - * Copyright (C) 2004 + * Copyright (C) 2004-2010 * Ludovic Rousseau * - * $Id: strlcpycat.h 1421 2005-04-12 12:09:21Z rousseau $ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +Changes to this license can be made only by the copyright author with +explicit written consent. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: strlcpycat.h 6851 2014-02-14 15:43:32Z rousseau $ */ /** @@ -12,7 +38,9 @@ * @brief prototypes of strlcpy()/strlcat() imported from OpenBSD */ -#ifndef HAVE_STRLCPY +#ifdef HAVE_STRLCPY +#include +#else size_t strlcpy(char *dst, const char *src, size_t siz); #endif diff -Nru acsccid-1.0.8/src/supported_readers.txt acsccid-1.1.0/src/supported_readers.txt --- acsccid-1.0.8/src/supported_readers.txt 2014-07-03 02:06:08.000000000 +0000 +++ acsccid-1.1.0/src/supported_readers.txt 2014-11-18 07:13:34.000000000 +0000 @@ -58,7 +58,7 @@ # ACR89U-A2 0x072f:0x8901:ACS ACR89 Dual Reader -# ACR89U-A3 +# ACR89U-FP 0x072f:0x8902:ACS ACR89 FP Reader # ACR100I @@ -114,7 +114,7 @@ # ACR1251UK 0x072f:0x2232:ACS ACR1251K Dual Reader -# ACR1251U-C1 +# ACR1251U-C3 0x072f:0x2242:ACS ACR1251 1S Dual Reader # ACR1252U-A1 @@ -129,6 +129,9 @@ # ACR1252U-A1 (PICC) 0x072f:0x2244:ACS ACR1252U BADANAMU MAGIC READER +# ACR1255U-J1 +0x072f:0x223f:ACS ACR1255U-J1 PICC Reader + # ACR1256U 0x072f:0x2239:ACS ACR1256U PICC Reader diff -Nru acsccid-1.0.8/src/tokenparser.c acsccid-1.1.0/src/tokenparser.c --- acsccid-1.0.8/src/tokenparser.c 2014-07-03 02:08:17.000000000 +0000 +++ acsccid-1.1.0/src/tokenparser.c 2014-12-10 08:34:34.000000000 +0000 @@ -396,11 +396,11 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 4, 1, 8, + 7, 7, 7, 7, 7, 7, 7, 4, 4, 8, 4, 9, 4, 4, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 1, 1, 1, 4, 4, 1, 11, 11, 11, 11, + 4, 1, 4, 4, 4, 1, 11, 11, 11, 11, 12, 11, 13, 11, 14, 11, 15, 11, 11, 16, 11, 11, 11, 17, 18, 19, 11, 11, 11, 11, @@ -485,43 +485,69 @@ /* * Reads lexical config files and updates database. * - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) + * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) * * Copyright (C) 2001-2003 - * David Corcoran + * David Corcoran + * Copyright (C) 2003-2010 * Ludovic Rousseau * - * $Id: tokenparser.l 4294 2009-07-03 09:55:05Z rousseau $ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +Changes to this license can be made only by the copyright author with +explicit written consent. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: tokenparser.l 6851 2014-02-14 15:43:32Z rousseau $ */ /** * @file - * @brief provides LTPBundleFindValueWithKey() function on non-MacOS X + * @brief provides parsing functions for Info.plist files * platforms */ -#line 20 "tokenparser.l" +#line 47 "tokenparser.l" #include "config.h" #include #include #include +#define NDEBUG +#include -#include "misc.h" -#include "debug.h" +#include "simclist.h" +#include "debuglog.h" #include "parser.h" #include "strlcpycat.h" -void tpevalToken(char *pcToken, int tokType); - -static const char *pcDesiredKey = NULL; -static char pcKey[TOKEN_MAX_KEY_SIZE]; -static char pcValue[TOKEN_MAX_VALUE_SIZE]; -static char pcFinValue[TOKEN_MAX_VALUE_SIZE]; -static int valueIndex = 0; -static int desiredIndex = 0; - +static void eval_key(char *pcToken, list_t *list_key); +static void eval_value(char *pcToken, list_t *list_values); void tperrorCheck (char *pcToken_error); -#line 525 "tokenparser.c" +static list_t *ListKeys; +static list_t *ListValues; + +#define YY_NO_INPUT 1 +#line 551 "tokenparser.c" #define INITIAL 0 @@ -733,10 +759,10 @@ } { -#line 47 "tokenparser.l" +#line 73 "tokenparser.l" -#line 740 "tokenparser.c" +#line 766 "tokenparser.c" while ( 1 ) /* loops until end-of-file is reached */ { @@ -795,41 +821,41 @@ case 1: YY_RULE_SETUP -#line 49 "tokenparser.l" +#line 75 "tokenparser.l" {} YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP -#line 50 "tokenparser.l" +#line 76 "tokenparser.l" {} YY_BREAK case 3: YY_RULE_SETUP -#line 51 "tokenparser.l" -{ valueIndex = 0; tpevalToken(yytext, TOKEN_TYPE_KEY); } +#line 77 "tokenparser.l" +{ eval_key(yytext, ListKeys); } YY_BREAK case 4: YY_RULE_SETUP -#line 52 "tokenparser.l" +#line 78 "tokenparser.l" {} YY_BREAK case 5: YY_RULE_SETUP -#line 53 "tokenparser.l" -{tpevalToken(yytext, TOKEN_TYPE_STRING); valueIndex += 1;} +#line 79 "tokenparser.l" +{ eval_value(yytext, ListValues); } YY_BREAK case 6: YY_RULE_SETUP -#line 54 "tokenparser.l" +#line 80 "tokenparser.l" { tperrorCheck(yytext); } YY_BREAK case 7: YY_RULE_SETUP -#line 55 "tokenparser.l" +#line 81 "tokenparser.l" ECHO; YY_BREAK -#line 833 "tokenparser.c" +#line 859 "tokenparser.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1787,130 +1813,212 @@ #define YYTABLES_NAME "yytables" -#line 54 "tokenparser.l" +#line 80 "tokenparser.l" -void tpevalToken(char *pcToken, int tokType) +static void eval_key(char *pcToken, list_t *list_key) { - unsigned int len; - len = 0; + struct bundleElt *elt; + int r; + size_t len; - if (tokType == TOKEN_TYPE_KEY) - { - /* foobar - * 012345 : 5 is the first key character index */ + /* create a new list element */ + elt = malloc(sizeof(*elt)); + assert(elt); - /* calculate the argument length */ - for (len=0; pcToken[len+5] != '<'; len++) - ; - len++; /* final NULL byte */ + /* foobar + * 012345 : 5 is the first key character index */ - if (len > sizeof(pcKey)) - (void)strlcpy(pcKey, &pcToken[5], sizeof(pcKey)); - else - (void)strlcpy(pcKey, &pcToken[5], len); - } + /* calculate the argument length */ + for (len=0; pcToken[len+5] != '<'; len++) + ; + len++; /* final NULL byte */ - if (tokType == TOKEN_TYPE_STRING) - { - /* foobar - * 012345678 : 8 is the first string character index */ + elt->key = malloc(len); + (void)strlcpy(elt->key, &pcToken[5], len); - /* calculate the argument length */ - for (len=0; pcToken[len+8] != '<'; len++) - ; - len++; /* final NULL byte */ + r = list_init(&elt->values); + assert(r >= 0); + (void)r; - if (len > sizeof(pcValue)) - (void)strlcpy(pcValue, &pcToken[8], sizeof(pcValue)); - else - (void)strlcpy(pcValue, &pcToken[8], len); + /* add the key/values */ + list_append(list_key, elt); + + /* set the list to store the values */ + ListValues = &elt->values; +} + +static void eval_value(char *pcToken, list_t *list_values) +{ + int r; + size_t len; + char *value; + char *amp; + + /* foobar + * 012345678 : 8 is the first string character index */ + + /* calculate the argument length */ + for (len=0; pcToken[len+8] != '<'; len++) + ; + len++; /* final NULL byte */ + + value = malloc(len); + assert(value); - if (strcmp(pcKey, pcDesiredKey) == 0) - if (desiredIndex == valueIndex) - (void)strlcpy(pcFinValue, pcValue, sizeof(pcFinValue)); + (void)strlcpy(value, &pcToken[8], len); + + /* for all & in the string */ + amp = value; + while ((amp = strstr(amp, "&")) != NULL) + { + char *p; + + /* just skip "amp;" substring (4 letters) */ + for (p = amp+1; *(p+4); p++) + { + *p = *(p+4); + } + /* terminate the now shorter string */ + *p = '\0'; + + /* skip the & and continue */ + amp++; } + + r = list_append(list_values, value); + assert(r >= 0); + (void)r; } void tperrorCheck (char *token_error) { + (void)token_error; } /** * Find an optional key in a configuration file * No error is logged if the key is not found * + * @param l list generated by bundleParse() + * @param key searched key + * @param[out] values list of token value (if key found) + * @retval 0 OK + * @retval 1 key not found + */ +int LTPBundleFindValueWithKey(list_t *l, const char *key, list_t **values) +{ + unsigned int i; + int ret = 1; + + for (i=0; i < list_size(l); i++) + { + struct bundleElt *elt; + + elt = list_get_at(l, i); + assert(elt); + + if (0 == strcmp(elt->key, key)) + { + *values = &elt->values; + ret = 0; + } + } + + return ret; +} + + +/** + * Parse a Info.plist file and file a list + * * @param fileName file name - * @param tokenKey key value - * @param[out] tokenValue token value (if key found) - * @param tokenIndice indice of the desired key + * @param l list containing the results * @retval -1 configuration file not found * @retval 0 OK - * @retval 1 key not found */ -int LTPBundleFindOptionalValueWithKey(const char *fileName, - const char *tokenKey, char *tokenValue, int tokenIndice) +int bundleParse(const char *fileName, list_t *l) { FILE *file = NULL; - int ret = 0; - - desiredIndex = tokenIndice; - pcDesiredKey = tokenKey; - pcFinValue[0] = '\0'; + int r; +#ifndef NDEBUG + int i; +#endif file = fopen(fileName, "r"); - if (!file) + { + Log3(PCSC_LOG_CRITICAL, "Could not open bundle file %s: %s", + fileName, strerror(errno)); return 1; + } + + r = list_init(l); + assert(r >= 0); + (void)r; + ListKeys = l; yyin = file; do { (void)yylex(); } while (!feof(file)); - - if ('\0' == pcFinValue[0]) - ret = -1; - else - (void)strlcpy(tokenValue, pcFinValue, TOKEN_MAX_VALUE_SIZE); + yylex_destroy(); (void)fclose(file); - return ret; -} +#ifndef NDEBUG + printf("size: %d\n", list_size(l)); + for (i=0; i < list_size(l); i++) + { + struct bundleElt *elt; + unsigned int j; + + elt = list_get_at(l, i); + assert(elt); + printf("Key: %s\n", elt->key); + + for (j=0; jvalues); j++) + { + char *v = list_get_at(&elt->values, j); + printf(" value: %s\n", v); + } + } +#endif + + return 0; +} /** - * Find a key in a configuration file + * Free the list created by bundleParse() * - * @param fileName file name - * @param tokenKey key value - * @param[out] tokenValue token value (if key found) - * @param tokenIndice indice of the desired key - * @retval -1 configuration file not found - * @retval 0 OK - * @retval 1 key not found + * @param l list containing the results */ -int LTPBundleFindValueWithKey(const char *fileName, const char *tokenKey, - char *tokenValue, int tokenIndice) +void bundleRelease(list_t *l) { - int ret = 0; + unsigned int i; - ret = LTPBundleFindOptionalValueWithKey(fileName, tokenKey, tokenValue, - tokenIndice); + for (i=0; i < list_size(l); i++) + { + struct bundleElt *elt; + unsigned int j; - if (1 == ret) - Log3(PCSC_LOG_CRITICAL, "Could not open bundle file %s: %s", - fileName, strerror(errno)); + elt = list_get_at(l, i); + assert(elt); - if ((-1 == ret) && (0 == tokenIndice)) - /* Not defined at all */ - Log3(PCSC_LOG_CRITICAL, "Value/Key not defined for: %s in %s", - tokenKey, fileName); + /* free all the values */ + for (j=0; jvalues); j++) + free(list_get_at(&elt->values, j)); + list_destroy(&elt->values); + + /* free the key */ + free(elt->key); + free(elt); + } - return ret; + list_destroy(l); } - diff -Nru acsccid-1.0.8/src/tokenparser.l acsccid-1.1.0/src/tokenparser.l --- acsccid-1.0.8/src/tokenparser.l 2009-07-04 08:10:31.000000000 +0000 +++ acsccid-1.1.0/src/tokenparser.l 2014-12-10 08:32:26.000000000 +0000 @@ -1,18 +1,45 @@ /* * Reads lexical config files and updates database. * - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) + * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) * * Copyright (C) 2001-2003 - * David Corcoran + * David Corcoran + * Copyright (C) 2003-2010 * Ludovic Rousseau * - * $Id: tokenparser.l 4294 2009-07-03 09:55:05Z rousseau $ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +Changes to this license can be made only by the copyright author with +explicit written consent. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: tokenparser.l 6851 2014-02-14 15:43:32Z rousseau $ */ /** * @file - * @brief provides LTPBundleFindValueWithKey() function on non-MacOS X + * @brief provides parsing functions for Info.plist files * platforms */ @@ -22,157 +49,238 @@ #include #include #include +#define NDEBUG +#include -#include "misc.h" -#include "debug.h" +#include "simclist.h" +#include "debuglog.h" #include "parser.h" #include "strlcpycat.h" -void tpevalToken(char *pcToken, int tokType); - -static const char *pcDesiredKey = NULL; -static char pcKey[TOKEN_MAX_KEY_SIZE]; -static char pcValue[TOKEN_MAX_VALUE_SIZE]; -static char pcFinValue[TOKEN_MAX_VALUE_SIZE]; -static int valueIndex = 0; -static int desiredIndex = 0; - +static void eval_key(char *pcToken, list_t *list_key); +static void eval_value(char *pcToken, list_t *list_values); void tperrorCheck (char *pcToken_error); +static list_t *ListKeys; +static list_t *ListValues; + %} %option nounput +%option noinput %option noyywrap %% #.* {} "\n" {} -\([A-Z]|[a-z]|[0-9]|[ \t])+\<\/key\> { valueIndex = 0; tpevalToken(yytext, TOKEN_TYPE_KEY); } +\([A-Z]|[a-z]|[0-9]|[ \t])+\<\/key\> { eval_key(yytext, ListKeys); } [ \t] {} -\([A-Z]|[a-z]|[0-9]|[ \t]|[!@#$%^&*()\-+/_\:?.,=~'"])+\<\/string\> {tpevalToken(yytext, TOKEN_TYPE_STRING); valueIndex += 1;} +\([A-Z]|[a-z]|[0-9]|[ \t]|[!@#$%^&*()\-+/_\:?.,=~'";\[\]])+\<\/string\> { eval_value(yytext, ListValues); } . { tperrorCheck(yytext); } %% -void tpevalToken(char *pcToken, int tokType) +static void eval_key(char *pcToken, list_t *list_key) { - unsigned int len; - len = 0; + struct bundleElt *elt; + int r; + size_t len; + + /* create a new list element */ + elt = malloc(sizeof(*elt)); + assert(elt); + + /* foobar + * 012345 : 5 is the first key character index */ + + /* calculate the argument length */ + for (len=0; pcToken[len+5] != '<'; len++) + ; + len++; /* final NULL byte */ + + elt->key = malloc(len); + (void)strlcpy(elt->key, &pcToken[5], len); + + r = list_init(&elt->values); + assert(r >= 0); + (void)r; - if (tokType == TOKEN_TYPE_KEY) - { - /* foobar - * 012345 : 5 is the first key character index */ - - /* calculate the argument length */ - for (len=0; pcToken[len+5] != '<'; len++) - ; - len++; /* final NULL byte */ + /* add the key/values */ + list_append(list_key, elt); - if (len > sizeof(pcKey)) - (void)strlcpy(pcKey, &pcToken[5], sizeof(pcKey)); - else - (void)strlcpy(pcKey, &pcToken[5], len); - } + /* set the list to store the values */ + ListValues = &elt->values; +} - if (tokType == TOKEN_TYPE_STRING) +static void eval_value(char *pcToken, list_t *list_values) +{ + int r; + size_t len; + char *value; + char *amp; + + /* foobar + * 012345678 : 8 is the first string character index */ + + /* calculate the argument length */ + for (len=0; pcToken[len+8] != '<'; len++) + ; + len++; /* final NULL byte */ + + value = malloc(len); + assert(value); + + (void)strlcpy(value, &pcToken[8], len); + + /* for all & in the string */ + amp = value; + while ((amp = strstr(amp, "&")) != NULL) { - /* foobar - * 012345678 : 8 is the first string character index */ + char *p; - /* calculate the argument length */ - for (len=0; pcToken[len+8] != '<'; len++) - ; - len++; /* final NULL byte */ - - if (len > sizeof(pcValue)) - (void)strlcpy(pcValue, &pcToken[8], sizeof(pcValue)); - else - (void)strlcpy(pcValue, &pcToken[8], len); - - if (strcmp(pcKey, pcDesiredKey) == 0) - if (desiredIndex == valueIndex) - (void)strlcpy(pcFinValue, pcValue, sizeof(pcFinValue)); + /* just skip "amp;" substring (4 letters) */ + for (p = amp+1; *(p+4); p++) + { + *p = *(p+4); + } + /* terminate the now shorter string */ + *p = '\0'; + + /* skip the & and continue */ + amp++; } + + r = list_append(list_values, value); + assert(r >= 0); + (void)r; } void tperrorCheck (char *token_error) { + (void)token_error; } /** * Find an optional key in a configuration file * No error is logged if the key is not found * + * @param l list generated by bundleParse() + * @param key searched key + * @param[out] values list of token value (if key found) + * @retval 0 OK + * @retval 1 key not found + */ +int LTPBundleFindValueWithKey(list_t *l, const char *key, list_t **values) +{ + unsigned int i; + int ret = 1; + + for (i=0; i < list_size(l); i++) + { + struct bundleElt *elt; + + elt = list_get_at(l, i); + assert(elt); + + if (0 == strcmp(elt->key, key)) + { + *values = &elt->values; + ret = 0; + } + } + + return ret; +} + + +/** + * Parse a Info.plist file and file a list + * * @param fileName file name - * @param tokenKey key value - * @param[out] tokenValue token value (if key found) - * @param tokenIndice indice of the desired key + * @param l list containing the results * @retval -1 configuration file not found * @retval 0 OK - * @retval 1 key not found */ -int LTPBundleFindOptionalValueWithKey(const char *fileName, - const char *tokenKey, char *tokenValue, int tokenIndice) +int bundleParse(const char *fileName, list_t *l) { FILE *file = NULL; - int ret = 0; - - desiredIndex = tokenIndice; - pcDesiredKey = tokenKey; - pcFinValue[0] = '\0'; + int r; +#ifndef NDEBUG + int i; +#endif file = fopen(fileName, "r"); - if (!file) + { + Log3(PCSC_LOG_CRITICAL, "Could not open bundle file %s: %s", + fileName, strerror(errno)); return 1; + } + r = list_init(l); + assert(r >= 0); + (void)r; + + ListKeys = l; yyin = file; do { (void)yylex(); } while (!feof(file)); - - if ('\0' == pcFinValue[0]) - ret = -1; - else - (void)strlcpy(tokenValue, pcFinValue, TOKEN_MAX_VALUE_SIZE); + yylex_destroy(); (void)fclose(file); - return ret; -} +#ifndef NDEBUG + printf("size: %d\n", list_size(l)); + for (i=0; i < list_size(l); i++) + { + struct bundleElt *elt; + unsigned int j; + + elt = list_get_at(l, i); + assert(elt); + printf("Key: %s\n", elt->key); + + for (j=0; jvalues); j++) + { + char *v = list_get_at(&elt->values, j); + printf(" value: %s\n", v); + } + } +#endif + + return 0; +} /** - * Find a key in a configuration file + * Free the list created by bundleParse() * - * @param fileName file name - * @param tokenKey key value - * @param[out] tokenValue token value (if key found) - * @param tokenIndice indice of the desired key - * @retval -1 configuration file not found - * @retval 0 OK - * @retval 1 key not found + * @param l list containing the results */ -int LTPBundleFindValueWithKey(const char *fileName, const char *tokenKey, - char *tokenValue, int tokenIndice) +void bundleRelease(list_t *l) { - int ret = 0; + unsigned int i; - ret = LTPBundleFindOptionalValueWithKey(fileName, tokenKey, tokenValue, - tokenIndice); + for (i=0; i < list_size(l); i++) + { + struct bundleElt *elt; + unsigned int j; - if (1 == ret) - Log3(PCSC_LOG_CRITICAL, "Could not open bundle file %s: %s", - fileName, strerror(errno)); + elt = list_get_at(l, i); + assert(elt); - if ((-1 == ret) && (0 == tokenIndice)) - /* Not defined at all */ - Log3(PCSC_LOG_CRITICAL, "Value/Key not defined for: %s in %s", - tokenKey, fileName); + /* free all the values */ + for (j=0; jvalues); j++) + free(list_get_at(&elt->values, j)); + list_destroy(&elt->values); + + /* free the key */ + free(elt->key); + free(elt); + } - return ret; + list_destroy(l); } - diff -Nru acsccid-1.0.8/src/towitoko/atr.c acsccid-1.1.0/src/towitoko/atr.c --- acsccid-1.0.8/src/towitoko/atr.c 2014-04-17 07:42:57.000000000 +0000 +++ acsccid-1.1.0/src/towitoko/atr.c 2014-12-10 08:32:26.000000000 +0000 @@ -20,9 +20,12 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include + #include "atr.h" -#include +#ifdef HAVE_STRING_H #include +#endif #include "debug.h" /* @@ -314,32 +317,47 @@ * It was rewritten by Ludovic Rousseau, 2004 */ #define PROTOCOL_UNSET -1 -int ATR_GetDefaultProtocol(ATR_t * atr, int *protocol) +int ATR_GetDefaultProtocol(ATR_t * atr, int *protocol, int *availableProtocols) { int i; /* default value */ *protocol = PROTOCOL_UNSET; + if (availableProtocols) + *availableProtocols = 0; for (i=0; iib[i][ATR_INTERFACE_BYTE_TD].present && (PROTOCOL_UNSET == *protocol)) + if (atr->ib[i][ATR_INTERFACE_BYTE_TD].present) { - /* set to the first protocol byte found */ - *protocol = atr->ib[i][ATR_INTERFACE_BYTE_TD].value & 0x0F; - DEBUG_COMM2("default protocol: T=%d", *protocol); + int T = atr->ib[i][ATR_INTERFACE_BYTE_TD].value & 0x0F; + + DEBUG_COMM2("T=%d Protocol Found", T); + if (availableProtocols) + *availableProtocols |= 1 << T; + + if (PROTOCOL_UNSET == *protocol) + { + /* set to the first protocol byte found */ + *protocol = T; + DEBUG_COMM2("default protocol: T=%d", *protocol); + } } /* specific mode if TA2 present */ if (atr->ib[1][ATR_INTERFACE_BYTE_TA].present) { *protocol = atr->ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F; + if (availableProtocols) + *availableProtocols = 1 << *protocol; DEBUG_COMM2("specific mode found: T=%d", *protocol); } if (PROTOCOL_UNSET == *protocol) { - DEBUG_INFO("no default protocol found in ATR. Using T=0"); + DEBUG_INFO1("no default protocol found in ATR. Using T=0"); *protocol = ATR_PROTOCOL_TYPE_T0; + if (availableProtocols) + *availableProtocols = 1 << *protocol; } return ATR_OK; diff -Nru acsccid-1.0.8/src/towitoko/atr.h acsccid-1.1.0/src/towitoko/atr.h --- acsccid-1.0.8/src/towitoko/atr.h 2009-01-06 23:14:33.000000000 +0000 +++ acsccid-1.1.0/src/towitoko/atr.h 2014-12-10 08:32:26.000000000 +0000 @@ -101,7 +101,7 @@ /* General smartcard characteristics */ extern int ATR_GetConvention(ATR_t * atr, /*@out@*/ int *convention); -extern int ATR_GetDefaultProtocol(ATR_t * atr, /*@out@*/ int *protocol); +extern int ATR_GetDefaultProtocol(ATR_t * atr, /*@out@*/ int *protocol, int *availableProtocols); /* ATR parameters and integer values */ extern int ATR_GetIntegerValue(ATR_t * atr, int name, BYTE * value); diff -Nru acsccid-1.0.8/src/towitoko/defines.h acsccid-1.1.0/src/towitoko/defines.h --- acsccid-1.0.8/src/towitoko/defines.h 2008-11-18 21:48:42.000000000 +0000 +++ acsccid-1.1.0/src/towitoko/defines.h 2014-12-10 08:32:26.000000000 +0000 @@ -27,7 +27,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif /* diff -Nru acsccid-1.0.8/src/towitoko/pps.c acsccid-1.1.0/src/towitoko/pps.c --- acsccid-1.0.8/src/towitoko/pps.c 2012-01-05 08:15:54.000000000 +0000 +++ acsccid-1.1.0/src/towitoko/pps.c 2014-12-10 08:32:26.000000000 +0000 @@ -23,9 +23,12 @@ #include "pps.h" #include "atr.h" +#ifdef HAVE_STDLIB_H #include -#include +#endif +#ifdef HAVE_STRING_H #include +#endif #include #include "commands.h" diff -Nru acsccid-1.0.8/src/utils.c acsccid-1.1.0/src/utils.c --- acsccid-1.0.8/src/utils.c 2008-11-18 21:48:42.000000000 +0000 +++ acsccid-1.1.0/src/utils.c 2014-12-10 08:32:26.000000000 +0000 @@ -1,6 +1,6 @@ /* utils.c: - Copyright (C) 2003-2004 Ludovic Rousseau + Copyright (C) 2003-2008 Ludovic Rousseau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,11 +18,12 @@ */ /* - * $Id: utils.c 2974 2008-05-28 18:32:52Z rousseau $ + * $Id: utils.c 6975 2014-09-04 11:33:05Z rousseau $ */ #include +#include #include "ccid.h" #include "defs.h" #include "ccid_ifdhandler.h" diff -Nru acsccid-1.0.8/src/utils.h acsccid-1.1.0/src/utils.h --- acsccid-1.0.8/src/utils.h 2009-06-20 14:37:33.000000000 +0000 +++ acsccid-1.1.0/src/utils.h 2014-12-10 08:32:26.000000000 +0000 @@ -1,6 +1,6 @@ /* utils.c: - Copyright (C) 2003-2004 Ludovic Rousseau + Copyright (C) 2003-2009 Ludovic Rousseau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,7 @@ */ /* - * $Id: utils.h 4256 2009-06-14 11:17:00Z rousseau $ + * $Id: utils.h 4973 2010-06-01 09:43:29Z rousseau $ */ #ifndef TRUE