[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