[pcsc-lite] Added support for Polkit and force sanity of parameters received by the client

Nikos Mavrogiannopoulos nmav at fedoraproject.org
Tue Feb 11 13:50:48 UTC 2014


commit db032e045fb4c96489a50de4563299eb63304027
Author: Nikos Mavrogiannopoulos <nmav at redhat.com>
Date:   Tue Feb 11 13:47:51 2014 +0100

    Added support for Polkit and force sanity of parameters received by the client

 org.debian.pcsc-lite.policy   |   30 +
 pcsc-lite.spec                |   24 +-
 pcscd-1.8.10-null-force.patch |   12 +
 pcscd-1.8.10-polkit.patch     | 1382 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1447 insertions(+), 1 deletions(-)
---
diff --git a/org.debian.pcsc-lite.policy b/org.debian.pcsc-lite.policy
new file mode 100644
index 0000000..e089707
--- /dev/null
+++ b/org.debian.pcsc-lite.policy
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+<policyconfig>
+  <vendor>The PCSC-lite Project</vendor>
+  <vendor_url>http://pcsclite.alioth.debian.org/</vendor_url>
+<!--  <icon_name>smart-card</icon_name> -->
+
+  <action id="org.debian.pcsc-lite.access_pcsc">
+    <description>Access to the PC/SC daemon</description>
+    <message>Authentication is required to access the PC/SC daemon</message>
+    <defaults>
+      <allow_any>yes</allow_any>
+      <allow_inactive>yes</allow_inactive>
+      <allow_active>yes</allow_active>
+    </defaults>
+  </action>
+
+  <action id="org.debian.pcsc-lite.access_card">
+    <description>Access to the smart card</description>
+    <message>Authentication is required to access the smart card</message>
+    <defaults>
+      <allow_any>yes</allow_any>
+      <allow_inactive>yes</allow_inactive>
+      <allow_active>yes</allow_active>
+    </defaults>
+  </action>
+
+</policyconfig>
diff --git a/pcsc-lite.spec b/pcsc-lite.spec
index e480b8f..d249b69 100644
--- a/pcsc-lite.spec
+++ b/pcsc-lite.spec
@@ -2,18 +2,26 @@
 
 Name:           pcsc-lite
 Version:        1.8.10
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        PC/SC Lite smart card framework and applications
 
 Group:          System Environment/Daemons
 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
 
 BuildRequires:  doxygen
 BuildRequires:  graphviz
 BuildRequires:  systemd-devel
 BuildRequires:  /usr/bin/pod2man
+BuildRequires:  polkit-devel
+BuildRequires:  autoconf
+BuildRequires:  automake
+BuildRequires:  gettext-devel
+BuildRequires:  libtool
 
 Requires(post): systemd
 Requires(preun): systemd
@@ -58,6 +66,9 @@ Requires:       %{name}-libs = %{version}-%{release}
 %prep
 %setup -q
 
+%patch0 -p1 -b .polkit
+%patch1 -p1 -b .null
+
 # Convert to utf-8
 for file in ChangeLog; do
     iconv -f ISO-8859-1 -t UTF-8 -o $file.new $file && \
@@ -67,8 +78,10 @@ done
 
 
 %build
+autoreconf -if
 %configure \
   --disable-static \
+  --enable-polkit \
   --enable-usbdropdir=%{_libdir}/pcsc/drivers
 make %{?_smp_mflags}
 doxygen doc/doxygen.conf ; rm -f doc/api/*.{map,md5}
@@ -76,6 +89,10 @@ doxygen doc/doxygen.conf ; rm -f doc/api/*.{map,md5}
 
 %install
 make install DESTDIR=$RPM_BUILD_ROOT
+rm -f $RPM_BUILD_ROOT%{_datadir}/polkit-1/actions/org.debian.pcsc-lite.policy
+
+mkdir -p $RPM_BUILD_ROOT%{_datadir}/polkit-1/actions/
+install -p -m 644 %{SOURCE1} $RPM_BUILD_ROOT%{_datadir}/polkit-1/actions/
 
 # Create empty directories
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/reader.conf.d
@@ -112,6 +129,7 @@ rm $RPM_BUILD_ROOT%{_docdir}/pcsc-lite/README.DAEMON
 %dir %{_libdir}/pcsc/drivers/
 %{_mandir}/man5/reader.conf.5*
 %{_mandir}/man8/pcscd.8*
+%{_datadir}/polkit-1/actions/org.debian.pcsc-lite.policy
 %ghost %dir %{_localstatedir}/run/pcscd/
 
 %files libs
@@ -131,6 +149,10 @@ rm $RPM_BUILD_ROOT%{_docdir}/pcsc-lite/README.DAEMON
 
 
 %changelog
+* Tue Feb 11 2014 Nikos Mavrogiannopoulos <nmav at redhat.com> - 1.8.10-2
+- Added upstream patch to support polkit
+- Force sanity of parameters received by the client
+
 * Sun Oct 20 2013 Kalev Lember <kalevlember at gmail.com> - 1.8.10-1
 - Update to 1.8.10
 - Update source URL
diff --git a/pcscd-1.8.10-null-force.patch b/pcscd-1.8.10-null-force.patch
new file mode 100644
index 0000000..98ffb4a
--- /dev/null
+++ b/pcscd-1.8.10-null-force.patch
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 0000000..64e80b2
--- /dev/null
+++ b/pcscd-1.8.10-polkit.patch
@@ -0,0 +1,1382 @@
+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 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE policyconfig PUBLIC
++ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
++ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
++<policyconfig>
++  <vendor>The PCSC-lite Project</vendor>
++  <vendor_url>http://pcsclite.alioth.debian.org/</vendor_url>
++<!--  <icon_name>smart-card</icon_name> -->
++
++  <action id="org.debian.pcsc-lite.access_pcsc">
++    <description>Access to the PC/SC daemon</description>
++    <message>Authentication is required to access the PC/SC daemon</message>
++    <defaults>
++      <allow_any>auth_admin</allow_any>
++      <allow_inactive>auth_admin</allow_inactive>
++      <allow_active>yes</allow_active>
++    </defaults>
++  </action>
++
++  <action id="org.debian.pcsc-lite.access_card">
++    <description>Access to the smart card</description>
++    <message>Authentication is required to access the smart card</message>
++    <defaults>
++      <allow_any>auth_admin</allow_any>
++      <allow_inactive>auth_admin</allow_inactive>
++      <allow_active>yes</allow_active>
++    </defaults>
++  </action>
++
++</policyconfig>
+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 <nmav at redhat.com>
++ */
++
++/**
++ * @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 <sys/types.h>
++#include <sys/socket.h>
++#include <sys/ioctl.h>
++#include <sys/un.h>
++#include <stdio.h>
++#include "debuglog.h"
++
++#include <errno.h>
++
++#if defined(HAVE_POLKIT) && defined(SO_PEERCRED)
++
++#include <polkit/polkit.h>
++
++/* 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 <nmav at redhat.com>
++ *
++ */
++
++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 <corcoran at linuxnet.com>
++ * Copyright (C) 2003-2004
++ *  Damien Sauveron <damien.sauveron at labri.fr>
++ * Copyright (C) 2002-2011
++ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
++ * Copyright (C) 2009
++ *  Jean-Luc Giraud <jlgiraud at googlemail.com>
++ *
++ * $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 <time.h>
++#include <stdio.h>
++#include <string.h>
++#include <stddef.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <pthread.h>
++
++#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;
++}


More information about the scm-commits mailing list