From 94e15f156434a26f6ee10de1fd3b7d21ad53e648 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 3 Jun 2014 10:12:16 +0200 Subject: [PATCH] new upstream release. --- .gitignore | 1 + pcsc-lite.spec | 15 +- pcscd-1.8.10-null-force.patch | 12 - pcscd-1.8.10-polkit.patch | 1382 --------------------------------- sources | 3 +- 5 files changed, 9 insertions(+), 1404 deletions(-) delete mode 100644 pcscd-1.8.10-null-force.patch delete mode 100644 pcscd-1.8.10-polkit.patch diff --git a/.gitignore b/.gitignore index 4371c40..f7a4350 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /pcsc-lite-*.tar.bz2 +/pcsc-lite-1.8.11.tar.bz2.asc diff --git a/pcsc-lite.spec b/pcsc-lite.spec index 319ce43..78ea1d0 100644 --- a/pcsc-lite.spec +++ b/pcsc-lite.spec @@ -1,8 +1,8 @@ %global upstream_build 3963 Name: pcsc-lite -Version: 1.8.10 -Release: 4%{?dist} +Version: 1.8.11 +Release: 1%{?dist} Summary: PC/SC Lite smart card framework and applications Group: System Environment/Daemons @@ -10,9 +10,7 @@ License: BSD URL: http://pcsclite.alioth.debian.org/ Source0: https://alioth.debian.org/frs/download.php/file/%{upstream_build}/%{name}-%{version}.tar.bz2 Source1: org.debian.pcsc-lite.policy -Patch0: pcscd-1.8.10-polkit.patch -Patch1: pcscd-1.8.10-null-force.patch -Patch2: pcscd-1.8.10-safer-udev-usage.patch +Patch0: pcscd-1.8.10-safer-udev-usage.patch BuildRequires: doxygen BuildRequires: graphviz @@ -67,9 +65,7 @@ Requires: %{name}-libs = %{version}-%{release} %prep %setup -q -%patch0 -p1 -b .polkit -%patch1 -p1 -b .null -%patch2 -p1 -b .udev +%patch0 -p1 -b .udev # Convert to utf-8 for file in ChangeLog; do @@ -152,7 +148,8 @@ rm $RPM_BUILD_ROOT%{_docdir}/pcsc-lite/README.DAEMON %changelog -* Tue Jun 03 2014 Nikos Mavrogiannopoulos - 1.8.10-4 +* Tue Jun 03 2014 Nikos Mavrogiannopoulos - 1.8.11-1 +- New upstream release - Safer usage of libudev functions * Tue Mar 11 2014 Nikos Mavrogiannopoulos - 1.8.10-3 diff --git a/pcscd-1.8.10-null-force.patch b/pcscd-1.8.10-null-force.patch deleted file mode 100644 index 98ffb4a..0000000 --- a/pcscd-1.8.10-null-force.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -ur pcsc-lite-1.8.10.orig/src/winscard_svc.c pcsc-lite-1.8.10/src/winscard_svc.c ---- pcsc-lite-1.8.10.orig/src/winscard_svc.c 2013-08-05 21:18:44.000000000 +0200 -+++ pcsc-lite-1.8.10/src/winscard_svc.c 2014-02-11 13:03:03.145500010 +0100 -@@ -436,6 +436,7 @@ - - READ_BODY(coStr) - -+ coStr.szReader[sizeof(coStr.szReader)-1] = 0; - hCard = coStr.hCard; - dwActiveProtocol = coStr.dwActiveProtocol; - -Only in pcsc-lite-1.8.10/src: winscard_svc.c.orig diff --git a/pcscd-1.8.10-polkit.patch b/pcscd-1.8.10-polkit.patch deleted file mode 100644 index 64e80b2..0000000 --- a/pcscd-1.8.10-polkit.patch +++ /dev/null @@ -1,1382 +0,0 @@ -diff -urN pcsc-lite-1.8.10.orig/configure.ac pcsc-lite-1.8.10/configure.ac ---- pcsc-lite-1.8.10.orig/configure.ac 2013-10-19 18:33:04.000000000 +0200 -+++ pcsc-lite-1.8.10/configure.ac 2014-02-11 13:04:10.505009385 +0100 -@@ -280,6 +280,29 @@ - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libusb" - fi - -+# --enable-polkit -+POLKIT_MINIMUM=0.111 -+AC_ARG_ENABLE(polkit, -+ AS_HELP_STRING([--enable-polkit], -+ [Build with polkit support]), -+ use_polkit=$withval, use_polkit=no) -+if test "$use_polkit" != "no"; then -+ PKG_CHECK_MODULES(POLKIT, [polkit-gobject-1 >= $POLKIT_MINIMUM], [use_polkit=yes], [use_polkit=no]) -+ if test "$use_polkit" != "no";then -+ AC_DEFINE([HAVE_POLKIT], 1, [Build polkit access control support]) -+ polkit_policy_dir=$($PKG_CONFIG polkit-gobject-1 --variable=policydir) -+ AC_SUBST(POLICY_DIR, [$polkit_policy_dir]) -+ else -+ use_polkit=no -+ AC_MSG_ERROR([[ -+*** -+*** polkit >= $POLKIT_MINIMUM was not found. Access control will be disabled. -+*** You may get it from http://www.freedesktop.org/software/polkit/ -+*** ]]) -+ fi -+fi -+AM_CONDITIONAL(ENABLE_POLKIT, test "$use_polkit" != "no") -+ - # --with-systemdsystemunitdir=DIR - AC_ARG_WITH([systemdsystemunitdir], - AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), -@@ -389,6 +412,8 @@ - PCSC_ARCH: ${PCSC_ARCH} - - pcscd binary ${PCSCD_BINARY} -+polkit support: ${use_polkit} -+polkit policy dir: ${polkit_policy_dir} - libudev support: ${use_libudev} - libusb support: ${use_libusb} - USB drop directory: ${usbdropdir} -diff -urN pcsc-lite-1.8.10.orig/doc/Makefile.am pcsc-lite-1.8.10/doc/Makefile.am ---- pcsc-lite-1.8.10.orig/doc/Makefile.am 2010-10-27 09:40:50.000000000 +0200 -+++ pcsc-lite-1.8.10/doc/Makefile.am 2014-02-11 13:04:10.506009400 +0100 -@@ -3,13 +3,23 @@ - SUBDIRS = . example - - doc_DATA = \ -- README.DAEMON -+ README.DAEMON README.polkit - - man_MANS = pcscd.8 reader.conf.5 - man_in = pcscd.8.in reader.conf.5.in - --EXTRA_DIST = $(doc_DATA) $(man_in) doxygen.conf.in formaticc.1 -+EXTRA_DIST = $(doc_DATA) $(man_in) doxygen.conf.in formaticc.1 \ -+ org.debian.pcsc-lite.policy - - doxygen: - rm -fr api ; cd .. ; doxygen doc/doxygen.conf - # cp doxygen.css api/ -+ -+if ENABLE_POLKIT -+install-data-hook: -+ $(MKDIR_P) $(DESTDIR)/$(POLICY_DIR) -+ $(INSTALL_DATA) $(srcdir)/org.debian.pcsc-lite.policy $(DESTDIR)/$(POLICY_DIR) -+ -+uninstall-hook: -+ rm $(DESTDIR)/$(POLICY_DIR)/org.debian.pcsc-lite.policy -+endif -diff -urN pcsc-lite-1.8.10.orig/doc/org.debian.pcsc-lite.policy pcsc-lite-1.8.10/doc/org.debian.pcsc-lite.policy ---- pcsc-lite-1.8.10.orig/doc/org.debian.pcsc-lite.policy 1970-01-01 01:00:00.000000000 +0100 -+++ pcsc-lite-1.8.10/doc/org.debian.pcsc-lite.policy 2014-02-11 13:04:10.505009385 +0100 -@@ -0,0 +1,30 @@ -+ -+ -+ -+ The PCSC-lite Project -+ http://pcsclite.alioth.debian.org/ -+ -+ -+ -+ Access to the PC/SC daemon -+ Authentication is required to access the PC/SC daemon -+ -+ auth_admin -+ auth_admin -+ yes -+ -+ -+ -+ -+ Access to the smart card -+ Authentication is required to access the smart card -+ -+ auth_admin -+ auth_admin -+ yes -+ -+ -+ -+ -diff -urN pcsc-lite-1.8.10.orig/doc/README.polkit pcsc-lite-1.8.10/doc/README.polkit ---- pcsc-lite-1.8.10.orig/doc/README.polkit 1970-01-01 01:00:00.000000000 +0100 -+++ pcsc-lite-1.8.10/doc/README.polkit 2014-02-11 13:04:10.506009400 +0100 -@@ -0,0 +1,39 @@ -+When pcsc-lite is compiled using the --enable-polkit option then -+polkit will be used to control access to the pcsc-lite daemon. -+ -+That allows more fine grained access control to smart cards that -+is tied to the system processes rather than solely depending on -+the smart card controls (e.g., only console users can access the -+card and so on). -+ -+Polkit is documented at: -+http://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html -+ -+A default polkit policy is shipped with pcsc-lite in -+org.debian.pcsc-lite.policy. The policy file allows restricting access -+to the daemon as well as access to smart cards. -+ -+Polkit allows for additional rules, e.g., restricting access to -+particular smart cards. The rules are javascript files placed -+in /usr/share/polkit-1/rules.d/. To make specific smart card -+reader accessible by the web server (run as www-data user) you -+may use the following rules: -+ -+polkit.addRule(function(action, subject) { -+ if (action.id == "org.debian.pcsc-lite.access_card" && -+ action.lookup("reader") == 'name of reader' && -+ subject.user == "www-data") { -+ return polkit.Result.YES; -+ } -+}); -+ -+polkit.addRule(function(action, subject) { -+ if (action.id == "org.debian.pcsc-lite.access_pcsc" && -+ subject.user == "www-data") { -+ return polkit.Result.YES; -+ } -+}); -+ -+ -+Note that the name of the reader can be obtained using "opensc-tool -l" -+or "pcsc_scan". -diff -urN pcsc-lite-1.8.10.orig/src/auth.c pcsc-lite-1.8.10/src/auth.c ---- pcsc-lite-1.8.10.orig/src/auth.c 1970-01-01 01:00:00.000000000 +0100 -+++ pcsc-lite-1.8.10/src/auth.c 2014-02-11 13:04:10.506009400 +0100 -@@ -0,0 +1,155 @@ -+/* -+ * MUSCLE SmartCard Development ( http://www.linuxnet.com ) -+ * -+ * Copyright (C) 2013 Red Hat -+ * -+ * All rights reserved. -+ * 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. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "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 -+ * COPYRIGHT HOLDER OR CONTRIBUTORS 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. -+ * -+ * Author: Nikos Mavrogiannopoulos -+ */ -+ -+/** -+ * @file -+ * @brief polkit authorization of clients -+ * -+ * IsClientAuthorized() checks whether the connecting client is authorized -+ * to access the resources using polkit. -+ */ -+ -+#include "config.h" -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include "debuglog.h" -+ -+#include -+ -+#if defined(HAVE_POLKIT) && defined(SO_PEERCRED) -+ -+#include -+ -+/* Returns non zero when the client is authorized */ -+unsigned IsClientAuthorized(int socket, const char* action, const char* reader) -+{ -+ struct ucred cr; -+ socklen_t cr_len; -+ int ret; -+ PolkitSubject *subject; -+ PolkitAuthority *authority; -+ PolkitAuthorizationResult *result; -+ PolkitDetails *details; -+ GError *error = NULL; -+ char action_name[128]; -+ -+ snprintf(action_name, sizeof(action_name), "org.debian.pcsc-lite.%s", action); -+ -+ cr_len = sizeof(cr); -+ ret = getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len); -+ if (ret == -1) -+ { -+ int e = errno; -+ Log2(PCSC_LOG_CRITICAL, -+ "Error obtaining client process credentials: %s", strerror(e)); -+ return 0; -+ } -+ -+ authority = polkit_authority_get_sync(NULL, NULL); -+ if (authority == NULL) -+ { -+ Log1(PCSC_LOG_CRITICAL, "polkit_authority_get_sync failed"); -+ return 0; -+ } -+ -+ subject = polkit_unix_process_new_for_owner(cr.pid, 0, cr.uid); -+ if (subject == NULL) -+ { -+ Log1(PCSC_LOG_CRITICAL, "polkit_unix_process_new_for_owner failed"); -+ ret = 0; -+ goto cleanup1; -+ } -+ -+ details = polkit_details_new(); -+ if (details == NULL) -+ { -+ Log1(PCSC_LOG_CRITICAL, "polkit_details_new failed"); -+ ret = 0; -+ goto cleanup0; -+ } -+ -+ if (reader != NULL) -+ polkit_details_insert(details, "reader", reader); -+ -+ result = polkit_authority_check_authorization_sync(authority, subject, -+ action_name, details, -+ POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE, -+ NULL, -+ &error); -+ -+ if (result == NULL) -+ { -+ Log2(PCSC_LOG_CRITICAL, "Error in authorization: %s", error->message); -+ g_error_free(error); -+ ret = 0; -+ } -+ else -+ { -+ if (polkit_authorization_result_get_is_authorized(result)) -+ { -+ ret = 1; -+ } -+ else -+ { -+ ret = 0; -+ } -+ } -+ -+ if (ret == 0) -+ { -+ Log4(PCSC_LOG_CRITICAL, -+ "Process %u (user: %u) is NOT authorized for action: %s", -+ (unsigned)cr.pid, (unsigned)cr.uid, action); -+ } -+ -+ g_object_unref(subject); -+cleanup0: -+ g_object_unref(details); -+cleanup1: -+ g_object_unref(authority); -+ -+ return ret; -+} -+ -+#else -+ -+int IsClientAuthorized(int socket, const char* action, const char* reader) -+{ -+ return 1; -+} -+ -+#endif -diff -urN pcsc-lite-1.8.10.orig/src/auth.h pcsc-lite-1.8.10/src/auth.h ---- pcsc-lite-1.8.10.orig/src/auth.h 1970-01-01 01:00:00.000000000 +0100 -+++ pcsc-lite-1.8.10/src/auth.h 2014-02-11 13:04:10.506009400 +0100 -@@ -0,0 +1,35 @@ -+/* -+ * MUSCLE SmartCard Development ( http://www.linuxnet.com ) -+ * -+ * Copyright (C) 2013 Red Hat -+ * -+ * All rights reserved. -+ * 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. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "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 -+ * COPYRIGHT HOLDER OR CONTRIBUTORS 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. -+ * -+ * Author: Nikos Mavrogiannopoulos -+ * -+ */ -+ -+unsigned IsClientAuthorized(int socket, const char* action, const char* reader); -diff -urN pcsc-lite-1.8.10.orig/src/Makefile.am pcsc-lite-1.8.10/src/Makefile.am ---- pcsc-lite-1.8.10.orig/src/Makefile.am 2013-03-30 13:15:33.000000000 +0100 -+++ pcsc-lite-1.8.10/src/Makefile.am 2014-02-11 13:04:10.507009422 +0100 -@@ -35,6 +35,8 @@ - libpcsclite_la_LIBADD = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - - pcscd_SOURCES = \ -+ auth.c \ -+ auth.h \ - atrhandler.c \ - atrhandler.h \ - configfile.h \ -@@ -84,12 +86,14 @@ - winscard_svc.c \ - winscard_svc.h - pcscd_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) $(LIBUDEV_CFLAGS) \ -+ $(POLKIT_CFLAGS) \ - -DPCSCD -DSIMCLIST_NO_DUMPRESTORE - pcscd_LDFLAGS = $(LDFLAGS) -export-dynamic - pcscd_LDADD = \ - $(PTHREAD_LIBS) $(COREFOUNDATION) \ - $(LIBUSB_LIBS) $(IOKIT) $(LIBUDEV_LIBS) \ -- $(PTHREAD_LIBS) $(PTHREAD_CFLAGS) -+ $(PTHREAD_LIBS) $(PTHREAD_CFLAGS) \ -+ $(POLKIT_LIBS) - - fix-rights: install-sbinPROGRAMS - chgrp pcscd $(DESTDIR)$(sbindir)/pcscd -diff -urN pcsc-lite-1.8.10.orig/src/winscard_svc.c pcsc-lite-1.8.10/src/winscard_svc.c ---- pcsc-lite-1.8.10.orig/src/winscard_svc.c 2013-08-05 21:18:44.000000000 +0200 -+++ pcsc-lite-1.8.10/src/winscard_svc.c 2014-02-11 13:04:10.507009422 +0100 -@@ -42,6 +42,7 @@ - #include "readerfactory.h" - #include "eventhandler.h" - #include "simclist.h" -+#include "auth.h" - - /** - * @brief Represents an Application Context on the Server side. -@@ -297,6 +298,16 @@ - SCONTEXT * threadContext = (SCONTEXT *) newContext; - int32_t filedes = threadContext->dwClientID; - -+ if (IsClientAuthorized(filedes, "access_pcsc", NULL) == 0) -+ { -+ Log1(PCSC_LOG_CRITICAL, "Rejected unauthorized PC/SC client"); -+ goto exit; -+ } -+ else -+ { -+ Log1(PCSC_LOG_DEBUG, "Authorized PC/SC client"); -+ } -+ - Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%p", - threadContext->dwClientID, threadContext); - -@@ -439,6 +450,16 @@ - hCard = coStr.hCard; - dwActiveProtocol = coStr.dwActiveProtocol; - -+ if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0) -+ { -+ Log2(PCSC_LOG_CRITICAL, "Rejected unauthorized client for '%s'", coStr.szReader); -+ goto exit; -+ } -+ else -+ { -+ Log2(PCSC_LOG_DEBUG, "Authorized client for '%s'", coStr.szReader); -+ } -+ - coStr.rv = SCardConnect(coStr.hContext, coStr.szReader, - coStr.dwShareMode, coStr.dwPreferredProtocols, - &hCard, &dwActiveProtocol); -diff -urN pcsc-lite-1.8.10.orig/src/winscard_svc.c.orig pcsc-lite-1.8.10/src/winscard_svc.c.orig ---- pcsc-lite-1.8.10.orig/src/winscard_svc.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ pcsc-lite-1.8.10/src/winscard_svc.c.orig 2013-08-05 21:18:44.000000000 +0200 -@@ -0,0 +1,959 @@ -+/* -+ * MUSCLE SmartCard Development ( http://www.linuxnet.com ) -+ * -+ * Copyright (C) 2001-2004 -+ * David Corcoran -+ * Copyright (C) 2003-2004 -+ * Damien Sauveron -+ * Copyright (C) 2002-2011 -+ * Ludovic Rousseau -+ * Copyright (C) 2009 -+ * Jean-Luc Giraud -+ * -+ * $Id: winscard_svc.c 6709 2013-08-05 18:49:31Z rousseau $ -+ */ -+ -+/** -+ * @file -+ * @brief This demarshalls functions over the message queue and keeps -+ * track of clients and their handles. -+ * -+ * Each Client message is deald by creating a thread (\c CreateContextThread). -+ * The thread establishes reands and demarshalls the message and calls the -+ * appropriate function to threat it. -+ */ -+ -+#include "config.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pcscd.h" -+#include "winscard.h" -+#include "debuglog.h" -+#include "winscard_msg.h" -+#include "winscard_svc.h" -+#include "sys_generic.h" -+#include "utils.h" -+#include "readerfactory.h" -+#include "eventhandler.h" -+#include "simclist.h" -+ -+/** -+ * @brief Represents an Application Context on the Server side. -+ * -+ * An Application Context contains Channels (\c hCard). -+ */ -+ -+extern char AutoExit; -+static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS; -+static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES; -+ -+static list_t contextsList; /**< Context tracking list */ -+pthread_mutex_t contextsList_lock; /**< lock for the above list */ -+ -+struct _psContext -+{ -+ int32_t hContext; -+ list_t cardsList; -+ pthread_mutex_t cardsList_lock; /**< lock for the above list */ -+ uint32_t dwClientID; /**< Connection ID used to reference the Client. */ -+ pthread_t pthThread; /**< Event polling thread's ID */ -+}; -+typedef struct _psContext SCONTEXT; -+ -+static LONG MSGCheckHandleAssociation(SCARDHANDLE, SCONTEXT *); -+static LONG MSGAddContext(SCARDCONTEXT, SCONTEXT *); -+static LONG MSGRemoveContext(SCARDCONTEXT, SCONTEXT *); -+static LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, SCONTEXT *); -+static LONG MSGRemoveHandle(SCARDHANDLE, SCONTEXT *); -+static LONG MSGCleanupClient(SCONTEXT *); -+ -+static void ContextThread(LPVOID pdwIndex); -+ -+extern READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]; -+ -+static int contextsListhContext_seeker(const void *el, const void *key) -+{ -+ const SCONTEXT * currentContext = (SCONTEXT *)el; -+ -+ if ((el == NULL) || (key == NULL)) -+ { -+ Log3(PCSC_LOG_CRITICAL, "called with NULL pointer: el=%p, key=%p", -+ el, key); -+ return 0; -+ } -+ -+ if (currentContext->hContext == *(int32_t *)key) -+ return 1; -+ return 0; -+} -+ -+LONG ContextsInitialize(int customMaxThreadCounter, -+ int customMaxThreadCardHandles) -+{ -+ int lrv = 0; -+ -+ if (customMaxThreadCounter != 0) -+ contextMaxThreadCounter = customMaxThreadCounter; -+ -+ if (customMaxThreadCardHandles != 0) -+ contextMaxCardHandles = customMaxThreadCardHandles; -+ -+ lrv = list_init(&contextsList); -+ if (lrv < 0) -+ { -+ Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv); -+ return -1; -+ } -+ lrv = list_attributes_seeker(& contextsList, contextsListhContext_seeker); -+ if (lrv < 0) -+ { -+ Log2(PCSC_LOG_CRITICAL, -+ "list_attributes_seeker failed with return value: %d", lrv); -+ return -1; -+ } -+ -+ (void)pthread_mutex_init(&contextsList_lock, NULL); -+ -+ return 1; -+} -+ -+void ContextsDeinitialize(void) -+{ -+ int listSize; -+ listSize = list_size(&contextsList); -+ Log2(PCSC_LOG_DEBUG, "remaining threads: %d", listSize); -+ /* This is currently a no-op. It should terminate the threads properly. */ -+ -+ list_destroy(&contextsList); -+} -+ -+/** -+ * @brief Creates threads to handle messages received from Clients. -+ * -+ * @param[in] pdwClientID Connection ID used to reference the Client. -+ * -+ * @return Error code. -+ * @retval SCARD_S_SUCCESS Success. -+ * @retval SCARD_F_INTERNAL_ERROR Exceded the maximum number of simultaneous Application Contexts. -+ * @retval SCARD_E_NO_MEMORY Error creating the Context Thread. -+ */ -+LONG CreateContextThread(uint32_t *pdwClientID) -+{ -+ int rv; -+ int lrv; -+ int listSize; -+ SCONTEXT * newContext = NULL; -+ LONG retval = SCARD_E_NO_MEMORY; -+ -+ (void)pthread_mutex_lock(&contextsList_lock); -+ -+ listSize = list_size(&contextsList); -+ if (listSize >= contextMaxThreadCounter) -+ { -+ Log2(PCSC_LOG_CRITICAL, "Too many context running: %d", listSize); -+ goto out; -+ } -+ -+ /* Create the context for this thread. */ -+ newContext = malloc(sizeof(*newContext)); -+ if (NULL == newContext) -+ { -+ Log1(PCSC_LOG_CRITICAL, "Could not allocate new context"); -+ goto out; -+ } -+ memset(newContext, 0, sizeof(*newContext)); -+ -+ newContext->dwClientID = *pdwClientID; -+ -+ /* Initialise the list of card contexts */ -+ lrv = list_init(&newContext->cardsList); -+ if (lrv < 0) -+ { -+ Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv); -+ goto out; -+ } -+ -+ /* request to store copies, and provide the metric function */ -+ list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1); -+ -+ /* Adding a comparator -+ * The stored type is SCARDHANDLE (long) but has only 32 bits -+ * usefull even on a 64-bit CPU since the API between pcscd and -+ * libpcscliter uses "int32_t hCard;" -+ */ -+ lrv = list_attributes_comparator(&newContext->cardsList, -+ list_comparator_int32_t); -+ if (lrv != 0) -+ { -+ Log2(PCSC_LOG_CRITICAL, -+ "list_attributes_comparator failed with return value: %d", lrv); -+ list_destroy(&newContext->cardsList); -+ goto out; -+ } -+ -+ (void)pthread_mutex_init(&newContext->cardsList_lock, NULL); -+ -+ lrv = list_append(&contextsList, newContext); -+ if (lrv < 0) -+ { -+ Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d", -+ lrv); -+ list_destroy(&newContext->cardsList); -+ goto out; -+ } -+ -+ rv = ThreadCreate(&newContext->pthThread, THREAD_ATTR_DETACHED, -+ (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext); -+ if (rv) -+ { -+ int lrv2; -+ -+ Log2(PCSC_LOG_CRITICAL, "ThreadCreate failed: %s", strerror(rv)); -+ lrv2 = list_delete(&contextsList, newContext); -+ if (lrv2 < 0) -+ Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv2); -+ list_destroy(&newContext->cardsList); -+ goto out; -+ } -+ -+ /* disable any suicide alarm */ -+ if (AutoExit) -+ alarm(0); -+ -+ retval = SCARD_S_SUCCESS; -+ -+out: -+ (void)pthread_mutex_unlock(&contextsList_lock); -+ -+ if (retval != SCARD_S_SUCCESS) -+ { -+ if (newContext) -+ free(newContext); -+ (void)close(*pdwClientID); -+ } -+ -+ return retval; -+} -+ -+/* -+ * A list of local functions used to keep track of clients and their -+ * connections -+ */ -+ -+/** -+ * @brief Handles messages received from Clients. -+ * -+ * For each Client message a new instance of this thread is created. -+ * -+ * @param[in] dwIndex Index of an avaiable Application Context slot in -+ * \c SCONTEXT *. -+ */ -+#ifndef NO_LOG -+static const char *CommandsText[] = { -+ "NULL", -+ "ESTABLISH_CONTEXT", /* 0x01 */ -+ "RELEASE_CONTEXT", -+ "LIST_READERS", -+ "CONNECT", -+ "RECONNECT", /* 0x05 */ -+ "DISCONNECT", -+ "BEGIN_TRANSACTION", -+ "END_TRANSACTION", -+ "TRANSMIT", -+ "CONTROL", /* 0x0A */ -+ "STATUS", -+ "GET_STATUS_CHANGE", -+ "CANCEL", -+ "CANCEL_TRANSACTION", -+ "GET_ATTRIB", /* 0x0F */ -+ "SET_ATTRIB", -+ "CMD_VERSION", -+ "CMD_GET_READERS_STATE", -+ "CMD_WAIT_READER_STATE_CHANGE", -+ "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */ -+ "NULL" -+}; -+#endif -+ -+#define READ_BODY(v) \ -+ if (header.size != sizeof(v)) { goto wrong_length; } \ -+ ret = MessageReceive(&v, sizeof(v), filedes); \ -+ if (ret != SCARD_S_SUCCESS) { Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); goto exit; } -+ -+#define WRITE_BODY(v) \ -+ WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v) -+#define WRITE_BODY_WITH_COMMAND(command, v) \ -+ Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \ -+ ret = MessageSend(&v, sizeof(v), filedes); -+ -+static void ContextThread(LPVOID newContext) -+{ -+ SCONTEXT * threadContext = (SCONTEXT *) newContext; -+ int32_t filedes = threadContext->dwClientID; -+ -+ Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%p", -+ threadContext->dwClientID, threadContext); -+ -+ while (1) -+ { -+ struct rxHeader header; -+ int32_t ret = MessageReceive(&header, sizeof(header), filedes); -+ -+ if (ret != SCARD_S_SUCCESS) -+ { -+ /* Clean up the dead client */ -+ Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); -+ EHTryToUnregisterClientForEvent(filedes); -+ goto exit; -+ } -+ -+ if ((header.command > CMD_ENUM_FIRST) -+ && (header.command < CMD_ENUM_LAST)) -+ Log3(PCSC_LOG_DEBUG, "Received command: %s from client %d", -+ CommandsText[header.command], filedes); -+ -+ switch (header.command) -+ { -+ /* pcsc-lite client/server protocol version */ -+ case CMD_VERSION: -+ { -+ struct version_struct veStr; -+ -+ READ_BODY(veStr) -+ -+ Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d", -+ veStr.major, veStr.minor); -+ -+ veStr.rv = SCARD_S_SUCCESS; -+ -+ /* client and server use different protocol */ -+ if ((veStr.major != PROTOCOL_VERSION_MAJOR) -+ || (veStr.minor != PROTOCOL_VERSION_MINOR)) -+ { -+ Log3(PCSC_LOG_CRITICAL, "Client protocol is %d:%d", -+ veStr.major, veStr.minor); -+ Log3(PCSC_LOG_CRITICAL, "Server protocol is %d:%d", -+ PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR); -+ veStr.rv = SCARD_E_NO_SERVICE; -+ } -+ -+ /* set the server protocol version */ -+ veStr.major = PROTOCOL_VERSION_MAJOR; -+ veStr.minor = PROTOCOL_VERSION_MINOR; -+ -+ /* send back the response */ -+ WRITE_BODY(veStr) -+ } -+ break; -+ -+ case CMD_GET_READERS_STATE: -+ { -+ /* nothing to read */ -+ -+#ifdef USE_USB -+ /* wait until all readers are ready */ -+ RFWaitForReaderInit(); -+#endif -+ -+ /* dump the readers state */ -+ ret = MessageSend(readerStates, sizeof(readerStates), filedes); -+ } -+ break; -+ -+ case CMD_WAIT_READER_STATE_CHANGE: -+ { -+ struct wait_reader_state_change waStr; -+ -+ READ_BODY(waStr) -+ -+ /* add the client fd to the list */ -+ EHRegisterClientForEvent(filedes); -+ -+ /* We do not send anything here. -+ * Either the client will timeout or the server will -+ * answer if an event occurs */ -+ } -+ break; -+ -+ case CMD_STOP_WAITING_READER_STATE_CHANGE: -+ { -+ struct wait_reader_state_change waStr; -+ -+ READ_BODY(waStr) -+ -+ /* add the client fd to the list */ -+ waStr.rv = EHUnregisterClientForEvent(filedes); -+ -+ WRITE_BODY(waStr) -+ } -+ break; -+ -+ case SCARD_ESTABLISH_CONTEXT: -+ { -+ struct establish_struct esStr; -+ SCARDCONTEXT hContext; -+ -+ READ_BODY(esStr) -+ -+ hContext = esStr.hContext; -+ esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0, -+ &hContext); -+ esStr.hContext = hContext; -+ -+ if (esStr.rv == SCARD_S_SUCCESS) -+ esStr.rv = MSGAddContext(esStr.hContext, threadContext); -+ -+ WRITE_BODY(esStr) -+ } -+ break; -+ -+ case SCARD_RELEASE_CONTEXT: -+ { -+ struct release_struct reStr; -+ -+ READ_BODY(reStr) -+ -+ reStr.rv = SCardReleaseContext(reStr.hContext); -+ -+ if (reStr.rv == SCARD_S_SUCCESS) -+ reStr.rv = MSGRemoveContext(reStr.hContext, threadContext); -+ -+ WRITE_BODY(reStr) -+ } -+ break; -+ -+ case SCARD_CONNECT: -+ { -+ struct connect_struct coStr; -+ SCARDHANDLE hCard; -+ DWORD dwActiveProtocol; -+ -+ READ_BODY(coStr) -+ -+ hCard = coStr.hCard; -+ dwActiveProtocol = coStr.dwActiveProtocol; -+ -+ coStr.rv = SCardConnect(coStr.hContext, coStr.szReader, -+ coStr.dwShareMode, coStr.dwPreferredProtocols, -+ &hCard, &dwActiveProtocol); -+ -+ coStr.hCard = hCard; -+ coStr.dwActiveProtocol = dwActiveProtocol; -+ -+ if (coStr.rv == SCARD_S_SUCCESS) -+ coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard, -+ threadContext); -+ -+ WRITE_BODY(coStr) -+ } -+ break; -+ -+ case SCARD_RECONNECT: -+ { -+ struct reconnect_struct rcStr; -+ DWORD dwActiveProtocol; -+ -+ READ_BODY(rcStr) -+ -+ if (MSGCheckHandleAssociation(rcStr.hCard, threadContext)) -+ goto exit; -+ -+ rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode, -+ rcStr.dwPreferredProtocols, rcStr.dwInitialization, -+ &dwActiveProtocol); -+ rcStr.dwActiveProtocol = dwActiveProtocol; -+ -+ WRITE_BODY(rcStr) -+ } -+ break; -+ -+ case SCARD_DISCONNECT: -+ { -+ struct disconnect_struct diStr; -+ -+ READ_BODY(diStr) -+ -+ if (MSGCheckHandleAssociation(diStr.hCard, threadContext)) -+ goto exit; -+ -+ diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition); -+ -+ if (SCARD_S_SUCCESS == diStr.rv) -+ diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext); -+ -+ WRITE_BODY(diStr) -+ } -+ break; -+ -+ case SCARD_BEGIN_TRANSACTION: -+ { -+ struct begin_struct beStr; -+ -+ READ_BODY(beStr) -+ -+ if (MSGCheckHandleAssociation(beStr.hCard, threadContext)) -+ goto exit; -+ -+ beStr.rv = SCardBeginTransaction(beStr.hCard); -+ -+ WRITE_BODY(beStr) -+ } -+ break; -+ -+ case SCARD_END_TRANSACTION: -+ { -+ struct end_struct enStr; -+ -+ READ_BODY(enStr) -+ -+ if (MSGCheckHandleAssociation(enStr.hCard, threadContext)) -+ goto exit; -+ -+ enStr.rv = SCardEndTransaction(enStr.hCard, -+ enStr.dwDisposition); -+ -+ WRITE_BODY(enStr) -+ } -+ break; -+ -+ case SCARD_CANCEL: -+ { -+ struct cancel_struct caStr; -+ SCONTEXT * psTargetContext = NULL; -+ READ_BODY(caStr) -+ -+ /* find the client */ -+ (void)pthread_mutex_lock(&contextsList_lock); -+ psTargetContext = (SCONTEXT *) list_seek(&contextsList, -+ &caStr.hContext); -+ (void)pthread_mutex_unlock(&contextsList_lock); -+ if (psTargetContext != NULL) -+ { -+ uint32_t fd = psTargetContext->dwClientID; -+ caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED); -+ } -+ else -+ caStr.rv = SCARD_E_INVALID_HANDLE; -+ -+ WRITE_BODY(caStr) -+ } -+ break; -+ -+ case SCARD_STATUS: -+ { -+ struct status_struct stStr; -+ -+ READ_BODY(stStr) -+ -+ if (MSGCheckHandleAssociation(stStr.hCard, threadContext)) -+ goto exit; -+ -+ /* only hCard and return value are used by the client */ -+ stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL, -+ NULL, 0, NULL); -+ -+ WRITE_BODY(stStr) -+ } -+ break; -+ -+ case SCARD_TRANSMIT: -+ { -+ struct transmit_struct trStr; -+ unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED]; -+ unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED]; -+ SCARD_IO_REQUEST ioSendPci; -+ SCARD_IO_REQUEST ioRecvPci; -+ DWORD cbRecvLength; -+ -+ READ_BODY(trStr) -+ -+ if (MSGCheckHandleAssociation(trStr.hCard, threadContext)) -+ goto exit; -+ -+ /* avoids buffer overflow */ -+ if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer)) -+ || (trStr.cbSendLength > sizeof(pbSendBuffer))) -+ goto buffer_overflow; -+ -+ /* read sent buffer */ -+ ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes); -+ if (ret != SCARD_S_SUCCESS) -+ { -+ Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); -+ goto exit; -+ } -+ -+ ioSendPci.dwProtocol = trStr.ioSendPciProtocol; -+ ioSendPci.cbPciLength = trStr.ioSendPciLength; -+ ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol; -+ ioRecvPci.cbPciLength = trStr.ioRecvPciLength; -+ cbRecvLength = trStr.pcbRecvLength; -+ -+ trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci, -+ pbSendBuffer, trStr.cbSendLength, &ioRecvPci, -+ pbRecvBuffer, &cbRecvLength); -+ -+ trStr.ioSendPciProtocol = ioSendPci.dwProtocol; -+ trStr.ioSendPciLength = ioSendPci.cbPciLength; -+ trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol; -+ trStr.ioRecvPciLength = ioRecvPci.cbPciLength; -+ trStr.pcbRecvLength = cbRecvLength; -+ -+ WRITE_BODY(trStr) -+ -+ /* write received buffer */ -+ if (SCARD_S_SUCCESS == trStr.rv) -+ ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes); -+ } -+ break; -+ -+ case SCARD_CONTROL: -+ { -+ struct control_struct ctStr; -+ unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED]; -+ unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED]; -+ DWORD dwBytesReturned; -+ -+ READ_BODY(ctStr) -+ -+ if (MSGCheckHandleAssociation(ctStr.hCard, threadContext)) -+ goto exit; -+ -+ /* avoids buffer overflow */ -+ if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer)) -+ || (ctStr.cbSendLength > sizeof(pbSendBuffer))) -+ { -+ goto buffer_overflow; -+ } -+ -+ /* read sent buffer */ -+ ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes); -+ if (ret != SCARD_S_SUCCESS) -+ { -+ Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); -+ goto exit; -+ } -+ -+ dwBytesReturned = ctStr.dwBytesReturned; -+ -+ ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode, -+ pbSendBuffer, ctStr.cbSendLength, -+ pbRecvBuffer, ctStr.cbRecvLength, -+ &dwBytesReturned); -+ -+ ctStr.dwBytesReturned = dwBytesReturned; -+ -+ WRITE_BODY(ctStr) -+ -+ /* write received buffer */ -+ if (SCARD_S_SUCCESS == ctStr.rv) -+ ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes); -+ } -+ break; -+ -+ case SCARD_GET_ATTRIB: -+ { -+ struct getset_struct gsStr; -+ DWORD cbAttrLen; -+ -+ READ_BODY(gsStr) -+ -+ if (MSGCheckHandleAssociation(gsStr.hCard, threadContext)) -+ goto exit; -+ -+ /* avoids buffer overflow */ -+ if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr)) -+ goto buffer_overflow; -+ -+ cbAttrLen = gsStr.cbAttrLen; -+ -+ gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId, -+ gsStr.pbAttr, &cbAttrLen); -+ -+ gsStr.cbAttrLen = cbAttrLen; -+ -+ WRITE_BODY(gsStr) -+ } -+ break; -+ -+ case SCARD_SET_ATTRIB: -+ { -+ struct getset_struct gsStr; -+ -+ READ_BODY(gsStr) -+ -+ if (MSGCheckHandleAssociation(gsStr.hCard, threadContext)) -+ goto exit; -+ -+ /* avoids buffer overflow */ -+ if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr)) -+ goto buffer_overflow; -+ -+ gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId, -+ gsStr.pbAttr, gsStr.cbAttrLen); -+ -+ WRITE_BODY(gsStr) -+ } -+ break; -+ -+ default: -+ Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command); -+ goto exit; -+ } -+ -+ /* MessageSend() failed */ -+ if (ret != SCARD_S_SUCCESS) -+ { -+ /* Clean up the dead client */ -+ Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); -+ goto exit; -+ } -+ } -+ -+buffer_overflow: -+ Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes); -+ goto exit; -+wrong_length: -+ Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes); -+exit: -+ (void)close(filedes); -+ (void)MSGCleanupClient(threadContext); -+ (void)pthread_exit((LPVOID) NULL); -+} -+ -+LONG MSGSignalClient(uint32_t filedes, LONG rv) -+{ -+ uint32_t ret; -+ struct wait_reader_state_change waStr; -+ -+ Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes); -+ -+ waStr.rv = rv; -+ WRITE_BODY_WITH_COMMAND("SIGNAL", waStr) -+ -+ return ret; -+} /* MSGSignalClient */ -+ -+static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext) -+{ -+ threadContext->hContext = hContext; -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext) -+{ -+ LONG rv; -+ int lrv; -+ -+ if (threadContext->hContext != hContext) -+ return SCARD_E_INVALID_VALUE; -+ -+ (void)pthread_mutex_lock(&threadContext->cardsList_lock); -+ while (list_size(&threadContext->cardsList) != 0) -+ { -+ READER_CONTEXT * rContext = NULL; -+ SCARDHANDLE hCard, hLockId; -+ void *ptr; -+ -+ /* -+ * Disconnect each of these just in case -+ */ -+ ptr = list_get_at(&threadContext->cardsList, 0); -+ if (NULL == ptr) -+ { -+ Log1(PCSC_LOG_CRITICAL, "list_get_at failed"); -+ continue; -+ } -+ hCard = *(int32_t *)ptr; -+ -+ /* -+ * Unlock the sharing -+ */ -+ rv = RFReaderInfoById(hCard, &rContext); -+ if (rv != SCARD_S_SUCCESS) -+ { -+ (void)pthread_mutex_unlock(&threadContext->cardsList_lock); -+ return rv; -+ } -+ -+ hLockId = rContext->hLockId; -+ rContext->hLockId = 0; -+ -+ if (hCard != hLockId) -+ { -+ /* -+ * if the card is locked by someone else we do not reset it -+ * and simulate a card removal -+ */ -+ rv = SCARD_W_REMOVED_CARD; -+ } -+ else -+ { -+ /* -+ * We will use SCardStatus to see if the card has been -+ * reset there is no need to reset each time -+ * Disconnect is called -+ */ -+ rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL); -+ } -+ -+ if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD) -+ (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD); -+ else -+ (void)SCardDisconnect(hCard, SCARD_RESET_CARD); -+ -+ /* Remove entry from the list */ -+ lrv = list_delete_at(&threadContext->cardsList, 0); -+ if (lrv < 0) -+ Log2(PCSC_LOG_CRITICAL, -+ "list_delete_at failed with return value: %d", lrv); -+ -+ UNREF_READER(rContext) -+ } -+ (void)pthread_mutex_unlock(&threadContext->cardsList_lock); -+ list_destroy(&threadContext->cardsList); -+ -+ /* We only mark the context as no longer in use. -+ * The memory is freed in MSGCleanupCLient() */ -+ threadContext->hContext = 0; -+ -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard, -+ SCONTEXT * threadContext) -+{ -+ LONG retval = SCARD_E_INVALID_VALUE; -+ -+ if (threadContext->hContext == hContext) -+ { -+ /* -+ * Find an empty spot to put the hCard value -+ */ -+ int listLength; -+ -+ (void)pthread_mutex_lock(&threadContext->cardsList_lock); -+ -+ listLength = list_size(&threadContext->cardsList); -+ if (listLength >= contextMaxCardHandles) -+ { -+ Log4(PCSC_LOG_DEBUG, -+ "Too many card handles for thread context @%p: %d (max is %d)" -+ "Restart pcscd with --max-card-handle-per-thread value", -+ threadContext, listLength, contextMaxCardHandles); -+ retval = SCARD_E_NO_MEMORY; -+ } -+ else -+ { -+ int lrv; -+ -+ lrv = list_append(&threadContext->cardsList, &hCard); -+ if (lrv < 0) -+ { -+ Log2(PCSC_LOG_CRITICAL, -+ "list_append failed with return value: %d", lrv); -+ retval = SCARD_E_NO_MEMORY; -+ } -+ else -+ retval = SCARD_S_SUCCESS; -+ } -+ -+ (void)pthread_mutex_unlock(&threadContext->cardsList_lock); -+ } -+ -+ return retval; -+} -+ -+static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext) -+{ -+ int lrv; -+ -+ (void)pthread_mutex_lock(&threadContext->cardsList_lock); -+ lrv = list_delete(&threadContext->cardsList, &hCard); -+ (void)pthread_mutex_unlock(&threadContext->cardsList_lock); -+ if (lrv < 0) -+ { -+ Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv); -+ return SCARD_E_INVALID_VALUE; -+ } -+ -+ return SCARD_S_SUCCESS; -+} -+ -+ -+static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, -+ SCONTEXT * threadContext) -+{ -+ int list_index = 0; -+ -+ if (0 == threadContext->hContext) -+ { -+ /* the handle is no more valid. After SCardReleaseContext() for -+ * example */ -+ Log1(PCSC_LOG_CRITICAL, "Invalidated handle"); -+ return -1; -+ } -+ -+ (void)pthread_mutex_lock(&threadContext->cardsList_lock); -+ list_index = list_locate(&threadContext->cardsList, &hCard); -+ (void)pthread_mutex_unlock(&threadContext->cardsList_lock); -+ if (list_index >= 0) -+ return 0; -+ -+ /* Must be a rogue client, debug log and sleep a couple of seconds */ -+ Log1(PCSC_LOG_ERROR, "Client failed to authenticate"); -+ (void)SYS_Sleep(2); -+ -+ return -1; -+} -+ -+ -+/* Should be called just prior to exiting the thread as it de-allocates -+ * the thread memory strucutres -+ */ -+static LONG MSGCleanupClient(SCONTEXT * threadContext) -+{ -+ int lrv; -+ int listSize; -+ -+ if (threadContext->hContext != 0) -+ { -+ (void)SCardReleaseContext(threadContext->hContext); -+ (void)MSGRemoveContext(threadContext->hContext, threadContext); -+ } -+ -+ Log3(PCSC_LOG_DEBUG, -+ "Thread is stopping: dwClientID=%d, threadContext @%p", -+ threadContext->dwClientID, threadContext); -+ -+ /* Clear the struct to ensure that we detect -+ * access to de-allocated memory -+ * Hopefully the compiler won't optimise it out */ -+ memset((void*) threadContext, 0, sizeof(SCONTEXT)); -+ Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext); -+ -+ (void)pthread_mutex_lock(&contextsList_lock); -+ lrv = list_delete(&contextsList, threadContext); -+ listSize = list_size(&contextsList); -+ (void)pthread_mutex_unlock(&contextsList_lock); -+ if (lrv < 0) -+ Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv); -+ -+ free(threadContext); -+ -+ /* start a suicide alarm */ -+ if (AutoExit && (listSize < 1)) -+ { -+ Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds", -+ TIME_BEFORE_SUICIDE); -+ alarm(TIME_BEFORE_SUICIDE); -+ } -+ -+ return 0; -+} diff --git a/sources b/sources index df07743..c10ac12 100644 --- a/sources +++ b/sources @@ -1 +1,2 @@ -7268cc5ef8fc01b785c7cea87adb1ade pcsc-lite-1.8.10.tar.bz2 +73502ca4ba6526727f9f49c63d805408 pcsc-lite-1.8.11.tar.bz2 +57253008899ea97f38fd4df62c1c2844 pcsc-lite-1.8.11.tar.bz2.asc