diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 311920d1..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,35 +0,0 @@ -### Versions - -* smart card reader driver name and version -* pcsc-lite version -* the output of the command `/usr/sbin/pcscd --version` - -### Platform - -* Operating system or GNU/Linux distribution name and version -* Smart card middleware name and version -* Smart card reader manufacturer name and reader model name -* Smart card name - -### Issue - -* What do you do? -* What result do you expect? -* What result do you get instead? - -### Log - -Then you shall generate a complete log (do not truncate it). - -* If you need to enter the smart card PIN to reproduce the problem then - consider changing your PIN before generating the logs as the PIN value - will be included in the logs. -* Kill any running pcscd process -* (re)start pcscd exactly as described bellow: -``` -sudo LIBCCID_ifdLogLevel=0x000F pcscd --foreground --debug --apdu --color | tee log.txt -``` -* Stop pcscd (using Control-C) after the problem occured and send me the - generated log.txt file - -See also https://pcsclite.apdu.fr/#support diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..c2eb7ea6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,51 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: LudovicRousseau + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. +2. +3. +4. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Versions:** +- smart card reader driver name and version +- pcsc-lite version +- the output of the command `/usr/sbin/pcscd --version` + +**Platform:** +- Operating system or GNU/Linux distribution name and version +- Smart card middleware name and version +- Smart card reader manufacturer name and reader model name +- Smart card name + +**Log:** +Then you shall generate a complete log (do not truncate it). + +- If you need to enter the smart card PIN to reproduce the problem then + consider changing your PIN before generating the logs as the PIN value + will be included in the logs. +- Kill any running pcscd process +- (re)start pcscd exactly as described bellow: +``` +sudo LIBCCID_ifdLogLevel=0x000F pcscd --foreground --debug --apdu --color | tee log.txt +``` +- Stop pcscd (using Control-C) after the problem occurred and send me the + generated `log.txt` file + +See also https://pcsclite.apdu.fr/#support + +**Additional context** +Add any other context about the problem here. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 61000681..dfcb35ee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job # can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: setup prerequisites shell: bash @@ -46,11 +46,11 @@ jobs: shell: bash run: | ./bootstrap - export CFLAGS="-Wall -Wextra -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wswitch-enum -Wundef -Wuninitialized -Wunused -Wwrite-strings -Wmissing-noreturn -flto=auto -O2 -Wp,-D_FORTIFY_SOURCE=2" - ./configure ${{ matrix.configure_args }} + export CFLAGS="-Wall -Wextra -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wswitch-enum -Wundef -Wuninitialized -Wunused -Wwrite-strings -Wmissing-noreturn -flto=auto -O2" + ./configure --disable-polkit ${{ matrix.configure_args }} make V=1 - name: distcheck shell: bash run: | - make distcheck + AM_DISTCHECK_CONFIGURE_FLAGS=--disable-polkit make distcheck diff --git a/.github/workflows/build_meson.yml b/.github/workflows/build_meson.yml new file mode 100644 index 00000000..47c4fb44 --- /dev/null +++ b/.github/workflows/build_meson.yml @@ -0,0 +1,59 @@ +name: build_meson + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: [push, pull_request] + +# A workflow run is made up of one or more jobs that can run +# sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job + # can access it + - uses: actions/checkout@v4 + + - name: setup prerequisites + shell: bash + run: | + sudo apt update + sudo apt install \ + autoconf-archive \ + debhelper-compat \ + doxygen \ + dpkg-dev \ + flex \ + libpolkit-gobject-1-dev \ + libsystemd-dev \ + libudev-dev \ + libusb-1.0-0-dev \ + meson \ + pkg-config + + - name: compile + shell: bash + run: | + export CFLAGS="-Wall -Wextra -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wold-style-definition -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes -Wswitch-enum -Wundef -Wuninitialized -Wunused -Wwrite-strings -Wmissing-noreturn -flto=auto -O2" + meson setup builddir --werror + cd builddir + + DESTDIR=/tmp/pcsc meson install + find /tmp/pcsc + + meson dist + + # doxygen + meson compile doc + + meson setup --reconfigure -Dlibsystemd=false -Dlibudev=false -Dpolkit=false + meson compile + + meson setup --reconfigure -Dserial=true + meson compile + + meson setup --reconfigure -Dembedded=true + meson compile diff --git a/ChangeLog b/ChangeLog index a7f4d2ff..4f167421 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,127 @@ +2.4.1: Ludovic Rousseau +1 January 2026 +- Add backward version support on the client side +- Add backward version support on the server side +- hotplug libudev: rescan the USB bus with "pcscd --hotplug" +- fix a value in pcscd.service systemd file +- meson: install systemd files even if libsystemd is not used +- Some other minor improvements + +2.4.0: Ludovic Rousseau +19 October 2025 +- Run pcscd under a pcscd user instead of root when using systemd +- Set PIDFile in systemd service file +- Protect contextMapList modifications using a mutex +- meson: + . Fix libpcsclite.pc file + . respect builtin meson default_library option + . build and install spy lib & tool only when needed +- UnitaryTests/*.py: fix pylint warnings +- Improve Doxygen documentation + +2.3.3: Ludovic Rousseau +2 April 2025 +- Make polkit rules work again (bug introduced in 2.3.2) + +2.3.2: Ludovic Rousseau +26 March 2025 +- Hardening systemd pcscd.service file +- pcscd.service: add missing Requires=polkit.service +- pcsc-spy: add missing PCSCv2_PART10_PROPERTY_* definitions +- Support udev PCSCLITE_IGNORE property to filter readers +- debuglog: force use of colors when --color is used +- Some other minor improvements + +2.3.1: Ludovic Rousseau +24 December 2024 +- Install a default /etc/default/pcscd file +- auth.c: implement polkit support for FreeBSD +- meson: + . also build static version of libpcsclite + . add options to disable polkit and libsystemd + . add "filter_names" in features when needed +- Doxygen: document dwCurrentState use for "\\?PnP?\Notification" +- Some other minor improvements + +2.3.0: Ludovic Rousseau +3 August 2024 +- SCardGetStatusChange(): add the number of reader events +- Add Appstream metainfo announcing HW support +- meson: specify minimum meson version to use +- fix formats under musl libc +- Send libpcsclite.so logs to stderr instead of stdout +- Some other minor improvements + +2.2.3: Ludovic Rousseau +26 May 2024 +- meson: + . Fix build on Slackware 15 + . fail if both libusb and libudev are used +- Fix memory leak on exit +- libpcscspy: dump an output buffer only if the call succeeded +- Some code cleanup + +2.2.2: Ludovic Rousseau +20 May 2024 +- Serial support is ENABLED by default + +2.2.1: Ludovic Rousseau +8 May 2024 +- fix meson related issues +- Some code cleanup + +2.2.0: Ludovic Rousseau +3 May 2024 +- provide files for meson build tool (replaces autoconf/auoomake) +- fix a missing symbol in libpcscspy (bug introduced by the previous version) +- fix shutdown issues with hotplug_libusb +- update pcsc-spy manpage +- update copyright date +- Some other minor improvements + +2.1.0: Ludovic Rousseau +12 April 2024 +- LIBPCSCLITE_DELEGATE is used to redirect to another libpcsclite library +- setup_spy.sh displays the LIBPCSCLITE_DELEGATE value to use for spying +- provides libfake.c as a sample source code +- Some other minor improvements + +2.0.3: Ludovic Rousseau +3 March 2024 +- add SCARD_E_UNKNOWN_RES_MNG back + +2.0.2: Ludovic Rousseau +3 March 2024 +- SCardConnect() & SCardReconnect(): restrict the protocol used +- negotiate PTS also for the backup protocol +- pcscd.8: + . document --disable-polkit + . add "CONFIGURATION FILE" section +- Some other minor improvements + +2.0.1: Ludovic Rousseau +24 November 2023 +- SCardConnect(): return SCARD_W_SECURITY_VIOLATION when needed (polkit) +- SCardCancel(): return SCARD_S_SUCCESS even if the client already finished +- polkit is enabled by default +- libpcscspy: fix a crash with NULL pointers +- Doxygen: fix SCardBeginTransaction() documentation +- fix pcscd internal thread safety issues (clang -fsanitize=thread) +- Some other minor improvements + + +9 June 2023 +2.0.0: Ludovic Rousseau +9 June 2023 +- Adjust USB drivers path at run-time via environment variable PCSCLITE_HP_DROPDIR +- Add '--disable-polkit' option +- Reset eventCounter when a reader is removed +- Add "polkit" in "pcscd -v" output if enabled +- Doxygen: document SCARD_E_INVALID_VALUE for some functions +- use secure_getenv(3) if available +- Some other minor improvements + + 1.9.9: Ludovic Rousseau 11 September 2022 - SCardEstablishContext() may return SCARD_W_SECURITY_VIOLATION if refused by Polkit @@ -153,7 +277,7 @@ 1.8.22: Ludovic Rousseau 17 June 2017 -- SCardCancel() was broken in 1.8.21. The call was bloking. +- SCardCancel() was broken in 1.8.21. The call was blocking. - Enable use of info level logging for pcscd using -i/--info @@ -317,7 +441,7 @@ pcsc-lite-1.8.9: Ludovic Rousseau - correctly manage thread safe multi-slot readers - Do not use pthread_atfork() any more (fix problem on FreeBSD) - fix memory leaks. - This was not really a problem unless you embedd pcscd in another + This was not really a problem unless you embed pcscd in another process and do init/deinit pcscd without exiting the process (as maybe used on Android or iOS). - pcscd.8 manpage: add documentation for --max-thread, @@ -602,7 +726,7 @@ pcsc-lite-1.6.1: Ludovic Rousseau list of readers even if a reader was connected. Thanks to Patrice Angelini for the bug report - SCardConnect() & SCardReconnect(): do not reset the cardProtocol in - SCARD_SHARE_DIRECT case since the card have _not_ been reseted. A new + SCARD_SHARE_DIRECT case since the card has _not_ been reset. A new PPS negotiation would fail. - Do not install files in /etc any more. Serial drivers are rare now. - Avoids a crash if a client sends a unknown command. @@ -890,7 +1014,7 @@ pcsc-lite-1.4.4: Ludovic Rousseau 14 August 2007 - do not call a Log function in a signal handler and do hotplug synchronously. See Debian bug #430492 Thanks to Russell Stuart -- support LSB init scritp format +- support LSB init script format - better support of Solaris and Mac OS X - some other minor improvements and bug corrections @@ -957,7 +1081,7 @@ pcsc-lite-1.4.0: Ludovic Rousseau pcsc-lite-1.3.3: Ludovic Rousseau 19 January 2007 - add -H --hotplug argument to ask the pcscd daemon to rescan the - avaiable readers + available readers - add support for IFD_GENERATE_HOTPLUG bit in driver Info.plist ifdCapabilities - add --force-reader-polling to ignore the IFD_GENERATE_HOTPLUG bit in @@ -990,7 +1114,7 @@ pcsc-lite-1.3.2: Ludovic Rousseau - define MAX_BUFFER_SIZE_EXTENDED as the maximal size allowed for a extended APDU (64KB) - LPCTSTR and LPTSTR types are deprecated. Use LPCSTR and LPSTR instead -- Dual licence src/error.c so it can be used bu OpenSC. It is now +- Dual licence src/error.c so it can be used by OpenSC. It is now BSD-like, see the COPYING file and GNU Lesser General Licence 2.1 or (at your option) any later version - document that the 4 bytes field value in PCSC_TLV_STRUCTURE is always @@ -1039,7 +1163,7 @@ pcsc-lite-1.2.9-beta10: Ludovic Rousseau reader name (between parenthesis) - the library libpcsclite.so.1 only exports the symbols defined by the API (http://pcsclite.alioth.debian.org/pcsc-lite/). This is needed to - be able to use the library in an appliation that also uses flex (like + be able to use the library in an application that also uses flex (like muscleTool). The problem only occurs with GCC >= 4.0 - some other minor improvements and bug corrections @@ -1084,7 +1208,7 @@ pcsc-lite-1.2.9-beta8: Ludovic Rousseau card driver (like SCARD_CTL_CODE, CM_IOCTL_GET_FEATURE_REQUEST, FEATURE_* and HOST_TO_CCID) - pcscd: allow a serial hotplug by sending a SIGUSR1 signal. The - /etc/reader.conf file is re-read and reader presence/abscence is updated + /etc/reader.conf file is re-read and reader presence/absence is updated - musclecard library: small bug fixes - pcsc-lite SCF: small bug fixes - some other minor improvements and bug corrections @@ -1103,10 +1227,10 @@ pcsc-lite-1.2.9-beta7: Ludovic Rousseau file from /etc/reader.conf.d/* files This script is called by /etc/init.d/pcscd before starting the daemon - add support of SCardGetAttrib() with a NULL pbAttr parameter to only - get the needed lenth in pcbAttrLen + get the needed length in pcbAttrLen - SCardReconnect() now works after a card movement. Previously SCardReconnect() returned "Card was removed" even if the new card is - reseted. + reset. - SCardGetStatusChange(): greatly improve performances. Thanks to Oivind H. Danielsen - SCardControl(): check if the pbSendBuffer is NULL or no bytes are sent @@ -1141,7 +1265,7 @@ pcsc-lite-1.2.9-beta6: Ludovic Rousseau You should use 'DEVICENAME /dev/null' if your driver does not use this field - src/winscard.c: . Avoid generating a PPS request that would not be just after a power - up. The previous code worked only when the card was _reseted_ at + up. The previous code worked only when the card was _reset_ at SCardDisconnect() but not when SCARD_LEAVE_CARD was used. - correctly manage multi-slots readers - etc/pcscd.init: @@ -1167,7 +1291,7 @@ pcsc-lite-1.2.9-beta5: Ludovic Rousseau compile but mark the type deprecated. See http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Type-Attributes.html - src/tokenfactory.c: - . TPSearchBundlesForAtr(): use "%s/%s" insead of "%s%s" when + . TPSearchBundlesForAtr(): use "%s/%s" instead of "%s%s" when generating the MuscleCard bundle name on MacOSX - src/winscard.c: . SCardControl() (new API) can now be used with a IFDHandler v2.0 or v3.0. @@ -1231,7 +1355,7 @@ pcsc-lite-1.2.9-beta3: Ludovic Rousseau wants to use even if the card only support only one protocol. - src/atrhandler.c: . add support of specific mode by the presence of TA2 (protocol not - negociable) + negotiable) - src/utils/Makefile.am: . install bundleTool and installifd in [...]/sbin/ instead of [...]/bin/ - doc/example/Makefile.am: @@ -1354,7 +1478,7 @@ pcsc-lite-1.2.0: Ludovic Rousseau pcsc-lite-1.2.0-rc3: Ludovic Rousseau 15 october, 2003 -- src/winscard_msg.c: perform a round-robbin among clients to avoid starvation +- src/winscard_msg.c: perform a round-robin among clients to avoid starvation under heavy load. Patch from Bettina Martelli. - src/winscard_clnt.c: send debug to stdout only if the environment variable MUSCLECARD_DEBUG is defined @@ -1373,7 +1497,7 @@ pcsc-lite-1.2.0-rc2: Ludovic Rousseau link with libmusclecard. - src/winscard_clnt.c: add a new function SCardUnload() to free allocated resources. It is mandatory only if you use dlopen/dlclose to often - load/unload the library. Otherwi se you will exhaust the resources + load/unload the library. Otherwise you will exhaust the resources available and get a crash. Thanks to Guy Moreillon for the patch. - src/muscletest.c: code cleaning @@ -1493,7 +1617,7 @@ pcsc-lite-1.1.2beta3: Ludovic Rousseau, David Corcoran - Support for Sun Microsystems' SCF - Patches from Dmitry Djachenko to: . init g_rgSCard??Pci variable at compile time - . return more meaningfull error codes in SCardReconnect() + . return more meaningful error codes in SCardReconnect() . return more information in SCardStatus() . accept pioRecvPci == NULL in SCardTransmit() according to MSDN (July 2002) : SCardTransmit description diff --git a/GPL-3.0.txt b/GPL-3.0.txt deleted file mode 100644 index 94a9ed02..00000000 --- a/GPL-3.0.txt +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/Makefile.am b/Makefile.am index 534def2d..f5f950ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,6 @@ DISTCHECK_CONFIGURE_FLAGS = \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) EXTRA_DIST = \ - GPL-3.0.txt \ bootstrap \ ChangeLog.git \ SECURITY \ @@ -19,4 +18,3 @@ DISTCLEANFILES = ChangeLog.git ChangeLog.git: git log --stat --decorate=short > $@ - diff --git a/README b/README index 2f202481..8d69f078 100644 --- a/README +++ b/README @@ -26,7 +26,7 @@ allocate/deallocate reader drivers at runtime (default). PCSC Lite uses the same winscard API as used under Windows(R). For security aware persons please read the SECURITY file on possible -vulnerabilites to pcsclite, how you can fix some, and how some will +vulnerabilities to pcsclite, how you can fix some, and how some will be fixed. For information on how to install driver please read the DRIVERS file. @@ -57,9 +57,9 @@ Options: (default /var/run) -By running pcscd under a priveledged account you can link to +By running pcscd under a privileged account you can link to libpcsclite.so and it will act as a client to the pcscd allowing multiple -applications to be run under non-priveledged accounts. +applications to be run under non-privileged accounts. Then type "make install" to copy the libraries to /usr/local/lib. If you choose not to have your reader configuration file in /etc/reader.conf.d/ @@ -80,7 +80,7 @@ There is a test program with this package: testpcsc: Linked to libpcsclite. Must run /usr/local/pcsc/bin/pcscd and then ./testpcsc. pcscd must be run as root or a hardware - priveledged user. ./testpcsc can be run under any account. + privileged user. ./testpcsc can be run under any account. LIBUSB SUPPORT: Versions after 1.2.0 support libusb. Available on GNU/Linux and *BSD. @@ -94,7 +94,7 @@ called "XXXX.bundle" in the usb dropdir directory (--enable-usbdropdir=PATH). Here, the string "XXXX" stands for an arbitrary driver name, like in "ifd-GemPC430.bundle". An example .bundle-directory can be found in the source distribution of the ifd-gempc driver -(http://ludovic.rousseau.free.fr/softwares/ifd-GemPC/) +(https://ifd-gempc.apdu.fr/) SOLARIS: Solaris PC/SC applications must link with -lsocket since @@ -107,5 +107,5 @@ directory. For questions, please email me at: corcoran@musclecard.com On some plateforms (GNU/Linux on mips and mipsel, FreeBSD and possibly -other *BSD suystems) you must use: +other *BSD systems) you must use: $ ./configure LDFLAGS="-lpthread" diff --git a/README.md b/README.md index e4384237..7f60334a 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,11 @@ Middleware to access a smart card using SCard API (PC/SC) The project Web site is: https://pcsclite.apdu.fr/ + +Contributors +============ + + + + + diff --git a/SECURITY b/SECURITY index ae817150..421456b7 100644 --- a/SECURITY +++ b/SECURITY @@ -3,12 +3,6 @@ SECURITY This file discusses security related issues with pcsc-lite and how to handle them. -Sometimes it is dangerous to run daemons under a root account. If there is -a chance to exploit a buffer overflow you can protect sensitive information -by running it under a different account. It might be useful to create another -user with hardware priveledges and run pcscd as that user. Be sure this user -can manipulate the server sockets. - Application suggestions: diff --git a/TODO b/TODO deleted file mode 100644 index 05d97657..00000000 --- a/TODO +++ /dev/null @@ -1,11 +0,0 @@ -- include Apple patches and improvements (if possible/needed) - -- allow to have pcscd and libpcsclite on two different machines. - That would be needed to support remote PAM login. - Maybe use unix2tcp (http://dizzy.roedu.net/unix2tcp/) - -- manage power suspend/resume (in a laptop for example) and coordinate - with the driver (when/if possible) - - -April 2011 diff --git a/c.sh b/c.sh index 60c857eb..7b80bc3b 100755 --- a/c.sh +++ b/c.sh @@ -1,16 +1,21 @@ #!/bin/sh set -x +set -e -./configure \ - --enable-strict \ - --prefix=/usr \ - --sysconfdir=/etc \ - --enable-maintainer-mode \ - --enable-twinserial \ - --with-systemdsystemunitdir=/usr/lib/systemd/system \ - --enable-usbdropdir=/usr/lib/pcsc/drivers \ - --enable-ipcdir=/run/pcscd \ - --libdir=/usr/lib/x86_64-linux-gnu \ - CFLAGS="$CFLAGS" \ - "$@" +BUILD_DIR=builddir +TMP_DIR=/tmp/pcsc + +rm -rf "$BUILD_DIR" + +meson setup "$BUILD_DIR" \ + --prefix /usr \ + -Dsystemdunit=system \ + "$@" + +cd "$BUILD_DIR" +meson compile + +rm -rf "$TMP_DIR" +DESTDIR="$TMP_DIR" meson install +find "$TMP_DIR" diff --git a/clang-analyze.sh b/clang-analyze.sh index b8007b3c..e59d03c8 100755 --- a/clang-analyze.sh +++ b/clang-analyze.sh @@ -3,13 +3,11 @@ set -e # do not use configfile.c since it is a lex file from configfile.l -if [ $# -lt 1 ] -then - files=$(ls -1 src/*.c | grep -v configfile | grep -v tokenparser) -else - files="$@" -fi -inc="-I. -Isrc -Isrc/PCSC -I/usr/include/hal -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include " -opt="--analyze " - -clang $inc $opt $files +pcscd_files="src/atrhandler.c src/auth.c src/debuglog.c src/dyn_unix.c src/eventhandler.c src/hotplug_generic.c src/hotplug_libudev.c src/hotplug_libusb.c src/ifdwrapper.c src/pcscdaemon.c src/prothandler.c src/readerfactory.c src/simclist.c src/sys_unix.c src/utils.c src/winscard.c src/winscard_msg.c src/winscard_msg_srv.c src/winscard_svc.c" +lib_files="src/debug.c src/winscard_clnt.c src/sys_unix.c src/utils.c src/winscard_msg.c" + +inc="-Ibuilddir -Isrc -Isrc/PCSC -I/usr/include/hal -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -I/usr/include/polkit-1 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include" +opt="--analyze" + +clang $inc -DPCSCD $opt $pcscd_files +clang $inc $opt $lib_files diff --git a/configure.ac b/configure.ac index 53ca9415..f6e3fdff 100644 --- a/configure.ac +++ b/configure.ac @@ -3,9 +3,9 @@ AC_PREREQ([2.69]) -AC_INIT([pcsc-lite],[1.9.9]) +AC_INIT([pcsc-lite], [2.2.0]) AC_CONFIG_SRCDIR(src/pcscdaemon.c) -AM_INIT_AUTOMAKE(1.8 dist-bzip2 no-dist-gzip) +AM_INIT_AUTOMAKE(1.8 dist-bzip2 no-dist-gzip foreign subdir-objects) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR(m4) @@ -17,40 +17,28 @@ AC_PROG_CC AC_C_BIGENDIAN # Check for some target-specific stuff -case "$host" in -*-*-hpux*) - CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE_EXTENDED" - ;; -*-*-solaris*) - CPPFLAGS="$CPPFLAGS -I/usr/local/include" - LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib" - need_dash_r=1 - ;; -*-*-sunos4*) - CPPFLAGS="$CPPFLAGS -DSUNOS4" - ;; -*-*-aix*) - CPPFLAGS="$CPPFLAGS -I/usr/local/include" - LDFLAGS="$LDFLAGS -L/usr/local/lib" - if (test "$LD" != "gcc" && test -z "$blibpath"); then - blibpath="/usr/lib:/lib:/usr/local/lib" - fi - ;; -*-*-osf*) - CPPFLAGS="$CPPFLAGS -D_POSIX_PII_SOCKET" - ;; -*-*-darwin*) - AC_SUBST(COREFOUNDATION) - COREFOUNDATION="-Wl,-framework,CoreFoundation" - AC_SUBST(IOKIT) - IOKIT="-Wl,-framework,IOKit" - if test "$GCC" = "yes"; then - CFLAGS="$CFLAGS -no-cpp-precomp" - fi - use_libusb=no - AC_MSG_WARN([libusb disabled on Darwin for pcsc-lite]) - ;; -esac +AS_CASE(["$host"], + [*-*-hpux*], [CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE_EXTENDED"], + [*-*-solaris*], [ + CPPFLAGS="$CPPFLAGS -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib" + need_dash_r=1 ], + [*-*-sunos4*], [CPPFLAGS="$CPPFLAGS -DSUNOS4"], + [*-*-aix*], [ + CPPFLAGS="$CPPFLAGS -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib" + AS_IF([test "$LD" != "gcc" && test -z "$blibpath"], + [blibpath="/usr/lib:/lib:/usr/local/lib"])], + [*-*-osf*], [CPPFLAGS="$CPPFLAGS -D_POSIX_PII_SOCKET"], + [*-*-darwin*], [ + AC_SUBST(COREFOUNDATION) + COREFOUNDATION="-Wl,-framework,CoreFoundation" + AC_SUBST(IOKIT) + IOKIT="-Wl,-framework,IOKit" + AS_IF([test "$GCC" = "yes"], [CFLAGS="$CFLAGS -no-cpp-precomp"]) + use_libusb=no + AC_MSG_WARN([libusb disabled on Darwin for pcsc-lite])] +) # Options AM_MAINTAINER_MODE @@ -61,10 +49,10 @@ AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_LEX([noyywrap]) -if test $LEX = ":" -then - AC_MSG_ERROR([no lex or flex found]) -fi +AS_IF([test $LEX = ":"], [ + AM_MISSING_PROG(MISSINGLEX, [flex]) + LEX=$MISSINGLEX] +) PKG_PROG_PKG_CONFIG AM_PROG_CC_C_O AM_PROG_AR @@ -73,7 +61,7 @@ AM_PROG_AR AX_PTHREAD([ AC_DEFINE(HAVE_PTHREAD, 1, [Define if you have POSIX threads libraries and header files.]) -],[ +], [ AC_MSG_ERROR([POSIX thread support required]) ]) @@ -110,13 +98,12 @@ AC_FUNC_ERROR_AT_LINE AC_FUNC_STAT AC_FUNC_VPRINTF AC_CHECK_FUNCS(getopt_long nanosleep strerror vsnprintf getrandom) +AC_CHECK_FUNCS(secure_getenv issetugid) AC_FUNC_ALLOCA # C Compiler features AC_C_INLINE -if test "$GCC" = "yes"; then - CFLAGS="-Wall -fno-common $CFLAGS" -fi +AS_IF([test "$GCC" = "yes"], [CFLAGS="-Wall -fno-common $CFLAGS"]) # check if the compiler support -fvisibility=hidden (GCC >= 4) saved_CFLAGS="$CFLAGS" @@ -135,20 +122,15 @@ AC_SEARCH_LIBS([dlopen], [dl dld], [], [ # Use 'uname' output as an architecture define PCSC_ARCH=`uname | sed -e s,/,_,` -case "$PCSC_ARCH" in -Darwin) - PCSC_ARCH=MacOS - ;; -SunOS) - PCSC_ARCH=Solaris - ;; -esac +AS_CASE(["$PCSC_ARCH"], + [Darwin], [PCSC_ARCH=MacOS], + [SunOS], [PCSC_ARCH=Solaris]) AC_DEFINE_UNQUOTED(PCSC_ARCH, "$PCSC_ARCH", [PC/SC target architecture]) PCSCLITE_FEATURES="${PCSCLITE_FEATURES} $PCSC_ARCH $host" # --disable-documentation AC_ARG_ENABLE(documentation, - AS_HELP_STRING([--disable-documentation],[do not build documentation]), + AS_HELP_STRING([--disable-documentation], [do not build documentation]), [ enable_doc="${enableval}" ], [ enable_doc="yes" ] ) AM_CONDITIONAL(ENABLE_DOC, test "$enable_doc" != "no") @@ -160,53 +142,47 @@ AC_CHECK_LIB(rt, mq_getattr, [LIBS="$LIBS -lrt"]) # check for libsystemd AC_ARG_ENABLE(libsystemd, - AS_HELP_STRING([--disable-libsystemd],[do not use libsystemd]), + AS_HELP_STRING([--disable-libsystemd], [do not use libsystemd]), [ use_libsystemd="${enableval}" ], [ use_libsystemd="yes" ] ) -if test "$use_libsystemd" != "no"; then - PKG_CHECK_MODULES(LIBSYSTEMD, libsystemd,, +AS_IF([test "$use_libsystemd" != "no"], + [PKG_CHECK_MODULES(LIBSYSTEMD, libsystemd,, [ AC_MSG_ERROR([install libsystemd-dev or use --disable-libsystemd]) ]) AC_DEFINE(USE_LIBSYSTEMD, 1, [Use libsystemd]) - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libsystemd" -fi + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libsystemd"]) # --disable-serial AC_ARG_ENABLE(serial, - AS_HELP_STRING([--disable-serial],[do not use serial reader.conf files]), + AS_HELP_STRING([--disable-serial], [do not use serial reader.conf files]), [ use_serial="${enableval}" ], [ use_serial="yes" ] ) AM_CONDITIONAL(ENABLE_SERIAL, test "$use_serial" != "no") -if test "$use_serial" != "no"; then - AC_DEFINE(USE_SERIAL, 1, [Use serial conf file mechanism]) - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} serial" -fi +AS_IF([test "$use_serial" != "no"], + [AC_DEFINE(USE_SERIAL, 1, [Use serial conf file mechanism]) + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} serial"]) # --disable-usb AC_ARG_ENABLE(usb, - AS_HELP_STRING([--disable-usb],[do not use usb hotplug]), + AS_HELP_STRING([--disable-usb], [do not use usb hotplug]), [ use_usb="${enableval}" ], [ use_usb="yes" ] ) AM_CONDITIONAL(ENABLE_USB, test "$use_usb" != "no") -if test "$use_usb" != "no"; then - AC_DEFINE(USE_USB, 1, [Use USB hotplug mechanism]) - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} usb" -fi +AS_IF([test "$use_usb" != "no"], + [AC_DEFINE(USE_USB, 1, [Use USB hotplug mechanism]) + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} usb"]) # --enable-libudev AC_ARG_ENABLE(libudev, - AS_HELP_STRING([--disable-libudev],[do not use libudev]), + AS_HELP_STRING([--disable-libudev], [do not use libudev]), [ use_libudev="${enableval}" ], - [ if test "$PCSC_ARCH" != "Linux" ; then - use_libudev="no" - else - use_libudev="${use_libudev-yes}" - fi ]) + [ AS_IF([test "$PCSC_ARCH" != "Linux"], + [use_libudev="no"], + [use_libudev="${use_libudev-yes}"]) + ]) # disable libudev check is USB is not used -if test "$use_usb" = "no"; then - use_libudev="no" -fi +AS_IF([test "$use_usb" = "no"], [use_libudev="no"]) # check if libudev is used -if test "x$use_libudev" != xno ; then - PKG_CHECK_MODULES(LIBUDEV, libudev, [], +AS_IF([test "x$use_libudev" != xno], + [PKG_CHECK_MODULES(LIBUDEV, libudev, [], [ AC_MSG_ERROR([install libudev-dev or use --disable-libudev]) ]) saved_CPPFLAGS="$CPPFLAGS" @@ -229,44 +205,40 @@ if test "x$use_libudev" != xno ; then CPPFLAGS="$saved_CPPFLAGS" LIBS="$saved_LIBS" -fi + ]) AC_SUBST(LIBUDEV_CFLAGS) AC_SUBST(LIBUDEV_LIBS) -if test x$use_libudev = xyes; then - AC_DEFINE(HAVE_LIBUDEV, 1, [Libudev is available]) - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libudev" -fi +AS_IF([test x$use_libudev = xyes], + [AC_DEFINE(HAVE_LIBUDEV, 1, [Libudev is available]) + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libudev"]) # --enable-libusb AC_ARG_ENABLE(libusb, - AS_HELP_STRING([--enable-libusb],[use libusb]), + AS_HELP_STRING([--enable-libusb], [use libusb]), [ use_libusb="${enableval}" ], - [ if test "x$use_libudev" = xyes ; then use_libusb="${use_libusb-no}" ; - else use_libusb="${use_libusb-yes}" ; fi ] ) + [ AS_IF([test "x$use_libudev" = xyes], + [use_libusb="${use_libusb-no}"], + [use_libusb="${use_libusb-yes}"])] ) # disable libusb check is USB is not used -if test "$use_usb" = "no"; then - use_libusb="no" -fi +AS_IF([test "$use_usb" = "no"], [use_libusb="no"]) # check if libusb is used -if test "x$use_libusb" != xno ; then - if test "x$use_libudev" != xno ; then - AC_MSG_ERROR([You can't use libudev _and_ libusb. Select only one.]) - fi +AS_IF([test "x$use_libusb" != xno], + [ + AS_IF([test "x$use_libudev" != xno], + [AC_MSG_ERROR([You can't use libudev _and_ libusb. Select only one.])]) PKG_CHECK_MODULES(LIBUSB, libusb-1.0, [], [ AC_MSG_RESULT([no]) AC_CHECK_PROG([LIBUSBCONFIG], [libusb-config], [yes]) - if test "$LIBUSBCONFIG" = "yes" ; then - LIBUSB_CFLAGS="$LIBUSB_CFLAGS `libusb-config --cflags`" - LIBUSB_LIBS="$LIBUSB_LIBS `libusb-config --libs`" - else - AC_MSG_WARN([libusb-config not found.]) - fi + AS_IF([test "$LIBUSBCONFIG" = "yes"], + [LIBUSB_CFLAGS="$LIBUSB_CFLAGS `libusb-config --cflags`" + LIBUSB_LIBS="$LIBUSB_LIBS `libusb-config --libs`" ], + [AC_MSG_WARN([libusb-config not found.])]) ]) saved_CPPFLAGS="$CPPFLAGS" @@ -289,69 +261,64 @@ if test "x$use_libusb" != xno ; then CPPFLAGS="$saved_CPPFLAGS" LIBS="$saved_LIBS" -fi +]) AC_SUBST(LIBUSB_CFLAGS) AC_SUBST(LIBUSB_LIBS) -if test x$use_libusb = xyes; then - AC_DEFINE(HAVE_LIBUSB, 1, [Libusb is available]) - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libusb" -fi +AS_IF([test x$use_libusb = xyes], + [AC_DEFINE(HAVE_LIBUSB, 1, [Libusb is available]) + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libusb"]) -# --enable-polkit +# --disable-polkit POLKIT_MINIMUM=0.111 AC_ARG_ENABLE(polkit, - AS_HELP_STRING([--enable-polkit], - [Build with polkit support]), - use_polkit=$enableval, 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([[ -*** + AS_HELP_STRING([--disable-polkit], + [do not build with polkit support]), + use_polkit=$enableval, use_polkit=yes) +AS_IF([test "$use_polkit" != "no"], + [PKG_CHECK_MODULES(POLKIT, [polkit-gobject-1 >= $POLKIT_MINIMUM], [use_polkit=yes], [use_polkit=no]) + AS_IF([test "$use_polkit" != "no"], + [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]) + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} polkit"], + [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]), [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) -if test "x$with_systemdsystemunitdir" != xno; then - AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) -fi +AS_IF([test "x$with_systemdsystemunitdir" != xno], + [AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])]) AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ]) # --enable-embedded AC_ARG_ENABLE(embedded, - AS_HELP_STRING([--enable-embedded],[limit RAM and CPU ressources by disabling features (log)]), + AS_HELP_STRING([--enable-embedded], [limit RAM and CPU resources by disabling features (log)]), [ use_embedded="${enableval}" ]) -if test x$use_embedded = xyes; then - AC_DEFINE(NO_LOG, 1, [Disable logging support]) - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} nolog" -fi +AS_IF([test x$use_embedded = xyes], + [AC_DEFINE(NO_LOG, 1, [Disable logging support]) + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} nolog"]) # --enable-usbdropdir=DIR AC_ARG_ENABLE(usbdropdir, - AS_HELP_STRING([--enable-usbdropdir=DIR],[directory containing USB + AS_HELP_STRING([--enable-usbdropdir=DIR], [directory containing USB drivers (default /usr/local/lib/pcsc/drivers)]), [usbdropdir="${enableval}"], [usbdropdir=false]) -if test x${usbdropdir} = xfalse ; then - if test "x$libdir" != xNONE; then - usbdropdir="$libdir/pcsc/drivers" - else - usbdropdir="$ac_default_libdir/pcsc/drivers" - fi -fi +AS_IF([test x${usbdropdir} = xfalse], + [AS_IF([test "x$libdir" != xNONE], + [usbdropdir="$libdir/pcsc/drivers"], + [usbdropdir="$ac_default_libdir/pcsc/drivers"]) +]) AX_RECURSIVE_EVAL($usbdropdir,usbdropdir_exp) usbdropdir=$usbdropdir_exp AC_DEFINE_UNQUOTED(PCSCLITE_HP_DROPDIR, "$usbdropdir", [directory containing USB drivers]) @@ -359,59 +326,52 @@ PCSCLITE_FEATURES="${PCSCLITE_FEATURES} usbdropdir=${usbdropdir}" # --enable-debugatr AC_ARG_ENABLE(debugatr, - AS_HELP_STRING([--enable-debugatr],[enable ATR debug messages from pcscd]), -[ case "${enableval}" in - yes) debugatr=true ;; - no) debugatr=false ;; - *) AC_MSG_ERROR([bad value ${enableval} for --enable-debugatr]) ;; -esac], [debugatr=false]) - -if test x${debugatr} = xtrue ; then - AC_DEFINE(ATR_DEBUG, 1, [display ATR parsing debug messages.]) - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} debugatr" -fi + AS_HELP_STRING([--enable-debugatr], [enable ATR debug messages from pcscd]), +[ AS_CASE(["${enableval}"], + [yes], [debugatr=true], + [no], [debugatr=false], + [*], [AC_MSG_ERROR([bad value ${enableval} for --enable-debugatr])]) +], [debugatr=false]) + +AS_IF([test x${debugatr} = xtrue], + [AC_DEFINE(ATR_DEBUG, 1, [display ATR parsing debug messages.]) + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} debugatr"]) # --enable-ipcdir=DIR AC_ARG_ENABLE(ipcdir, - AS_HELP_STRING([--enable-ipcdir=DIR],[directory containing IPC files + AS_HELP_STRING([--enable-ipcdir=DIR], [directory containing IPC files (default /run/pcscd)]), [ipcdir="${enableval}"], [ipcdir=false]) -if test x${ipcdir} = xfalse ; then - ipcdir="/run/pcscd" -fi -AC_DEFINE_UNQUOTED(USE_IPCDIR, "$ipcdir", [directory containing IPC files]) +AS_IF([test x${ipcdir} = xfalse], [ipcdir="/run/pcscd"]) PCSCLITE_FEATURES="${PCSCLITE_FEATURES} ipcdir=${ipcdir}" CPPFLAGS="-I\${top_srcdir}/src $CPPFLAGS" # --enable-confdir=DIR AC_ARG_ENABLE(confdir, -AS_HELP_STRING([--enable-confdir=DIR],[directory containing reader configurations (default ${sysconfdir}/reader.conf.d)]), +AS_HELP_STRING([--enable-confdir=DIR], [directory containing reader configurations (default ${sysconfdir}/reader.conf.d)]), [confdir="${enableval}"], [confdir="${sysconfdir}/reader.conf.d"]) # --disable-filter AC_ARG_ENABLE(filter, - AS_HELP_STRING([--disable-filter],[disable reader filtering using + AS_HELP_STRING([--disable-filter], [disable reader filtering using PCSCLITE_FILTER_IGNORE_READER_NAMES and PCSCLITE_FILTER_EXTEND_READER_NAMES]), [ use_filter="${enableval}" ], [ use_filter="yes" ]) -if test x$use_filter = xyes; then - AC_DEFINE(FILTER_NAMES, 1, [Filter reader names]) - PCSCLITE_FEATURES="${PCSCLITE_FEATURES} filter" -fi +AS_IF([test x$use_filter = xyes], + [AC_DEFINE(FILTER_NAMES, 1, [Filter reader names]) + PCSCLITE_FEATURES="${PCSCLITE_FEATURES} filter"]) # --enable-strict AC_ARG_ENABLE( [strict], - [AS_HELP_STRING([--enable-strict],[enable strict compile mode @<:@enabled@:>@])], + [AS_HELP_STRING([--enable-strict], [enable strict compile mode @<:@enabled@:>@])], , [enable_strict="no"] ) -if test "${enable_strict}" = "yes"; then - CFLAGS="-Wall -Wextra -Werror ${CFLAGS}" -fi +AS_IF([test "${enable_strict}" = "yes"], [CFLAGS="-Wall -Wextra -Werror ${CFLAGS}"]) # Setup dist stuff AC_SUBST(usbdropdir) @@ -481,4 +441,3 @@ src/pcscd.h src/PCSC/pcsclite.h ]) AC_OUTPUT - diff --git a/doc/Makefile.am b/doc/Makefile.am index ecfdcdfa..49a0770b 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -6,7 +6,7 @@ doc_DATA = \ 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 \ org.debian.pcsc-lite.policy doxygen: diff --git a/doc/README.polkit b/doc/README.polkit index dbf7c565..099dcdac 100644 --- a/doc/README.polkit +++ b/doc/README.polkit @@ -1,5 +1,10 @@ -When pcsc-lite is compiled using the --enable-polkit option then -polkit will be used to control access to the pcsc-lite daemon. +By default pcsc-lite will use polkit to control access to the pcsc-lite +daemon. + +For now, only GNU/Linux and FreeBSD are supported. Patches are welcome +for other platforms. +Configure pcsc-lite with -Dpolkit=false if polkit is not available for +your platform. That allows more fine grained access control to smart cards that is tied to the system processes rather than solely depending on diff --git a/doc/doxygen.conf.in b/doc/doxygen.conf.in index 9dfc8805..681fbc43 100644 --- a/doc/doxygen.conf.in +++ b/doc/doxygen.conf.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.16 +# Doxyfile 1.10.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -53,6 +63,12 @@ PROJECT_BRIEF = PROJECT_LOGO = +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If @@ -60,16 +76,28 @@ PROJECT_LOGO = OUTPUT_DIRECTORY = doc -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,26 +109,18 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -217,6 +237,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -240,25 +268,19 @@ TAB_SIZE = 4 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -299,19 +321,22 @@ OPTIMIZE_OUTPUT_SLICE = NO # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is -# Fortran), use: inc=Fortran f=C. +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = @@ -334,6 +359,17 @@ MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 5 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -445,6 +481,27 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = YES + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -508,6 +565,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -519,14 +583,15 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -545,12 +610,20 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# (including Cygwin) ands Mac users are advised to set this option to NO. -# The default value is: system dependent. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = YES @@ -568,6 +641,12 @@ HIDE_SCOPE_NAMES = YES HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -725,7 +804,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -771,24 +851,50 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = NO # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = YES +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -799,13 +905,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -819,17 +939,29 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = src +INPUT = ../src \ + pcsclite.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: https://www.gnu.org/software/libiconv/) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -838,11 +970,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, -# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.h @@ -860,7 +996,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = src/winscard_scf.c +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -882,10 +1018,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test EXCLUDE_SYMBOLS = @@ -930,6 +1063,11 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -971,6 +1109,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -985,7 +1132,8 @@ USE_MDFILE_AS_MAINPAGE = SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO @@ -1068,17 +1216,11 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = NO -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1157,10 +1299,15 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = /usr/share/doxygen-awesome-css/doxygen-awesome.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1172,9 +1319,22 @@ HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1184,7 +1344,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1202,20 +1362,11 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that -# are dynamically created via Javascript. If disabled, the navigation index will +# are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML -# page. Disable this option to support browsers that do not have Javascript, +# page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1230,6 +1381,33 @@ HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1245,10 +1423,11 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: https://developer.apple.com/xcode/), introduced with OSX -# 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. @@ -1265,6 +1444,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1290,8 +1476,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1321,7 +1511,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1348,6 +1538,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1366,7 +1566,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1374,8 +1575,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1383,16 +1584,16 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = @@ -1404,9 +1605,9 @@ QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1449,15 +1650,27 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +FULL_SIDEBAR = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. @@ -1483,6 +1696,24 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1492,19 +1723,14 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. -FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# https://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1514,11 +1740,29 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1531,22 +1775,29 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1574,7 +1825,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1593,7 +1844,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1606,8 +1858,9 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1702,7 +1955,7 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4wide +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just @@ -1716,29 +1969,31 @@ PAPER_TYPE = a4wide EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1771,18 +2026,26 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = NO -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. USE_PDFLATEX = NO -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1795,16 +2058,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -1813,14 +2066,6 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -1885,16 +2130,6 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_RTF is set to YES. - -RTF_SOURCE_CODE = NO - #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- @@ -1991,27 +2226,44 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2086,7 +2338,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2153,15 +2406,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2175,25 +2428,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2202,7 +2439,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2219,49 +2456,77 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" + +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2284,10 +2549,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2299,7 +2586,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2308,7 +2597,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2348,16 +2640,26 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2394,11 +2696,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2407,10 +2710,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2448,18 +2751,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2472,14 +2763,34 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/doc/example/pcsc_demo.c b/doc/example/pcsc_demo.c new file mode 100644 index 00000000..ec991764 --- /dev/null +++ b/doc/example/pcsc_demo.c @@ -0,0 +1,308 @@ +/* + * Sample program to use PC/SC API. + * + * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) + * + * Copyright (C) 2003-2021 + * Ludovic Rousseau + * +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include + +/* PCSC error message pretty print */ +#define PCSC_ERROR(rv, text) \ +if (rv != SCARD_S_SUCCESS) \ +{ \ + printf(text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \ + goto end; \ +} \ +else \ +{ \ + printf(text ": OK\n\n"); \ +} + +int main(int argc, char *argv[]) +{ + LONG rv; + SCARDCONTEXT hContext = 0; + DWORD dwReaders; + LPSTR mszReaders = NULL; + char *ptr, **readers = NULL; + int nbReaders; + SCARDHANDLE hCard; + DWORD dwActiveProtocol, dwReaderLen, dwState, dwProt, dwAtrLen; + BYTE pbAtr[MAX_ATR_SIZE] = ""; + char pbReader[MAX_READERNAME] = ""; + int reader_nb; + unsigned int i; + const SCARD_IO_REQUEST *pioSendPci; + SCARD_IO_REQUEST pioRecvPci; + BYTE pbRecvBuffer[10]; + BYTE pbSendBuffer[] = { 0x00, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 }; + DWORD dwSendLength, dwRecvLength; + + printf("PC/SC sample code\n"); + printf("V 1.4 2003-2009, Ludovic Rousseau \n"); + + printf("\nTHIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL FOR END USERS!\n"); + printf("Do NOT use it unless you really know what you do.\n\n"); + + rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); + if (rv != SCARD_S_SUCCESS) + { + printf("SCardEstablishContext: Cannot Connect to Resource Manager %lX\n", rv); + return EXIT_FAILURE; + } + + /* Retrieve the available readers list. */ + dwReaders = SCARD_AUTOALLOCATE; + rv = SCardListReaders(hContext, NULL, (LPSTR)&mszReaders, &dwReaders); + PCSC_ERROR(rv, "SCardListReaders") + + /* Extract readers from the null separated string and get the total + * number of readers */ + nbReaders = 0; + ptr = mszReaders; + while (*ptr != '\0') + { + ptr += strlen(ptr)+1; + nbReaders++; + } + + if (nbReaders == 0) + { + printf("No reader found\n"); + goto end; + } + + /* allocate the readers table */ + readers = calloc(nbReaders, sizeof(char *)); + if (NULL == readers) + { + printf("Not enough memory for readers[]\n"); + goto end; + } + + /* fill the readers table */ + nbReaders = 0; + ptr = mszReaders; + while (*ptr != '\0') + { + printf("%d: %s\n", nbReaders, ptr); + readers[nbReaders] = ptr; + ptr += strlen(ptr)+1; + nbReaders++; + } + + if (argc > 1) + { + reader_nb = atoi(argv[1]); + if (reader_nb < 0 || reader_nb >= nbReaders) + { + printf("Wrong reader index: %d\n", reader_nb); + goto end; + } + } + else + reader_nb = 0; + + /* connect to a card */ + dwActiveProtocol = -1; + rv = SCardConnect(hContext, readers[reader_nb], SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); + printf(" Protocol: %ld\n", dwActiveProtocol); + PCSC_ERROR(rv, "SCardConnect") + + /* get card status */ + dwAtrLen = sizeof(pbAtr); + dwReaderLen = sizeof(pbReader); + rv = SCardStatus(hCard, /*NULL*/ pbReader, &dwReaderLen, &dwState, &dwProt, + pbAtr, &dwAtrLen); + printf(" Reader: %s (length %ld bytes)\n", pbReader, dwReaderLen); + printf(" State: 0x%lX\n", dwState); + printf(" Prot: %ld\n", dwProt); + printf(" ATR (length %ld bytes):", dwAtrLen); + for (i=0; i, -for the Debian GNU/Linux system (but may be used by others). -. -.SH "SEE ALSO" -.BR pcscd (8) diff --git a/doc/org.debian.pcsc-lite.policy b/doc/org.debian.pcsc-lite.policy index 1d49bbc7..b8b574d9 100644 --- a/doc/org.debian.pcsc-lite.policy +++ b/doc/org.debian.pcsc-lite.policy @@ -10,6 +10,7 @@ Access to the PC/SC daemon Authentication is required to access the PC/SC daemon + unix-user:pcscd no no @@ -20,6 +21,7 @@ Access to the smart card Authentication is required to access the smart card + unix-user:pcscd no no diff --git a/doc/pcscd.8.in b/doc/pcscd.8.in index f9c4cfde..229931ed 100644 --- a/doc/pcscd.8.in +++ b/doc/pcscd.8.in @@ -3,12 +3,39 @@ pcscd \- PC/SC Smart Card Daemon . .SH SYNOPSIS -.B pcscd -.RI [ options ] +.SY pcscd +.OP \-acfTdeCvHSI +.OP \-\-apdu +.OP \-\-config dir +.OP \-\-foreground +.OP \-\-color +.OP \-\-debug +.OP \-\-info +.OP \-\-error +.OP \-\-critical +.OP \-\-force\-reader\-polling +.OP \-t number +.OP \-\-max\-thread number +.OP \-s number +.OP \-\-max\-card\-handle\-per\-thread number +.OP \-r number +.OP \-\-max\-card\-handle\-per\-reader number +.OP \-\-version +.OP \-\-hotplug +.OP \-\-reader\-name\-no\-serial +.OP \-\-reader\-name\-no\-interface +.OP \-\-disable-polkit +.YS +. +.SY pcscd +.B \-h +.SY pcscd +.B \-\-help +.YS . .SH OPTIONS .TP -.BR -a ", " \-\-apdu +.BR \-a ", " \-\-apdu log APDUs and SW using the debug method (see .BR \-\-debug ). .TP @@ -40,24 +67,24 @@ use error log level. use critical log level. .PP The log levels are ordered as: debug < info < error < critical. Use a -log level l will log this level and all the levels above it. +log level \fIl\fP will log this level and all the levels above it. .TP .B \-\-force\-reader\-polling ignore the IFD_GENERATE_HOTPLUG reader capability .TP -.BR \-t ", " \-\-max\-thread +.BR \-t ", " \-\-max\-thread " " \fInumber maximum number of threads (default 200). This is the maximum number of clients (SCardEstablishContext) that pcscd can handle. .TP -.BR \-s ", " \-\-max\-card\-handle\-per\-thread +.BR \-s ", " \-\-max\-card\-handle\-per\-thread " " \fInumber maximum number of card handle per thread (default: 200). This is the maximum number of card handle (SCardConnect) per client (SCardEstablishContext). .TP -.BR \-r ", " \-\-max\-card\-handle\-per\-reader +.BR \-r ", " \-\-max\-card\-handle\-per\-reader " " \fInumber maximum number of card handle per reader (default: 200) This is the maximum number of card handle (SCardConnect) per reader. @@ -84,6 +111,9 @@ Do not include the USB serial number in the reader name. .TP .BR \-I ", " \-\-reader\-name\-no\-interface Do not include the USB interface name in the reader name. +.TP +.BR \-\-disable-polkit +Ignore polkit rules. All accesses are allowed. .SH DESCRIPTION pcscd is the daemon program for pcsc-lite. It is a resource manager that coordinates communications with smart card readers and smart cards and @@ -114,7 +144,49 @@ directory as a bundle. You shall NOT add a USB driver in a .I @PCSCLITE_CONFIG_DIR@/my_reader.conf file. . +.SH "CONFIGURATION FILE" +It is possible to set arguments that will be used by pcscd with the +configuration file +.I /etc/default/pcscd +For example you can increase the debug level using: +.RS +.EX +PCSCD_ARGS=--debug +.EE +.RE +.PP +Or set environment variables like: +.RS +.EX +PCSCLITE_FILTER_IGNORE_READER_NAMES="Twin" +PCSCLITE_FILTER_EXTEND_READER_NAMES=" $HOSTNAME" +.EE +.RE +.PP +See +.UR +https://blog.apdu.fr/posts/2021/08/pcsc-lite-configuration-using/ +.UE +for more details. +.SH "UDEV USB READER FILTERING (LINUX ONLY)" +If udev support is enabled, setting the udev property +.I PCSCLITE_IGNORE=1 +on a USB device will cause that reader to be ignored. For example +to ignore any reader attached to USB port 3 of bus 1, add +the following to a +.I foobar.rules +file in the +.I /etc/udev/rules.d/ +directory: +.RS +.EX +ACTION!="remove|unbind", SUBSYSTEM=="usb", KERNEL=="1-3", ENV{PCSCLITE_IGNORE}="1" +.EE +.RE .SH FILES +.I /etc/default/pcscd +: daemon configuration file +.PP .I @PCSCLITE_CONFIG_DIR@/* : Serial reader configuration files .PP @@ -126,7 +198,8 @@ file. . .SH "SEE ALSO" .BR reader.conf (5), -.BR syslog (3) +.BR syslog (3), +.BR udev (7) . .SH AUTHORS David Corcoran and Ludovic Rousseau diff --git a/doc/update.sh b/doc/update.sh index 2bbe5aae..f64ca0f6 100755 --- a/doc/update.sh +++ b/doc/update.sh @@ -3,6 +3,9 @@ set -e set -x -rm -rf api -make doxygen -rsync --recursive --verbose --update --rsh=ssh api pcsclite.apdu.fr:Serveurs_web/pcsclite.apdu.fr/ +cd ../builddir +rm -rf doc + +meson compile doc + +rsync --recursive --verbose --update --rsh=ssh doc/api pcsclite.apdu.fr:Serveurs_web/pcsclite.apdu.fr/ diff --git a/etc/fr.apdu.pcsclite.metainfo.xml b/etc/fr.apdu.pcsclite.metainfo.xml new file mode 100644 index 00000000..06833f48 --- /dev/null +++ b/etc/fr.apdu.pcsclite.metainfo.xml @@ -0,0 +1,23 @@ + + + fr.apdu.pcsclite + MIT + pcscd + Middleware to access a smart card using PC/SC + +

The purpose of PC/SC Lite is to provide a Windows(R) SCard + interface in a very small form factor for communicating to smart + cards and smart cards readers.

+ +

The PC/SC daemon is used to dynamically allocate/deallocate + reader drivers at runtime and manage connections to the + readers.

+
+ + PCSC-lite project + + https://pcsclite.apdu.fr/ + + usb:*ic0Bisc00ip* + +
diff --git a/etc/pcscd b/etc/pcscd new file mode 100644 index 00000000..b8fc660f --- /dev/null +++ b/etc/pcscd @@ -0,0 +1,14 @@ +# Defaults for pcscd (/etc/default/pcscd) +# https://blog.apdu.fr/posts/2021/08/pcsc-lite-configuration-using/ + +# PCSCD_ARGS is used in the systemd service unit to pass cli arguments +# to pcscd executable. +PCSCD_ARGS="" + +# Adjust USB drivers path at run-time +#PCSCLITE_HP_DROPDIR="/usr/lib/pcsc/drivers/" + +# Remove and/or customize PC/SC reader names +# https://blog.apdu.fr/posts/2015/12/remove-andor-customize-pcsc-reader-names/ +#PCSCLITE_FILTER_IGNORE_READER_NAMES="Contactless" +#PCSCLITE_FILTER_EXTEND_READER_NAMES=" $HOSTNAME" diff --git a/etc/pcscd-sysusers.conf b/etc/pcscd-sysusers.conf new file mode 100644 index 00000000..ae23a74f --- /dev/null +++ b/etc/pcscd-sysusers.conf @@ -0,0 +1,3 @@ +# Add a locked pcscd system user and group. +# See man sysusers.d(5). +u! pcscd - "PC/SC Smart Card Daemon" diff --git a/etc/pcscd.service.in b/etc/pcscd.service.in index 65ad6a69..874a03dc 100644 --- a/etc/pcscd.service.in +++ b/etc/pcscd.service.in @@ -1,12 +1,51 @@ [Unit] Description=PC/SC Smart Card Daemon Requires=pcscd.socket +@requires_polkit@ Documentation=man:pcscd(8) [Service] ExecStart=@sbindir_exp@/pcscd --foreground --auto-exit $PCSCD_ARGS ExecReload=@sbindir_exp@/pcscd --hotplug EnvironmentFile=-@sysconfdir@/default/pcscd +User=pcscd +RuntimeDirectory=pcscd +RuntimeDirectoryPreserve=yes +PIDFile=@ipcdir@/pcscd.pid + +# Paths +ProtectProc=invisible + +# Capabilities +CapabilityBoundingSet= + +# Security +NoNewPrivileges=yes + +# Process Properties +UMask=0077 + +# Sandboxing +ProtectSystem=strict +ProtectHome=yes +PrivateTmp=yes +PrivateUsers=identity +ProtectHostname=yes +ProtectClock=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectKernelLogs=yes +ProtectControlGroups=yes +RestrictNamespaces=yes +LockPersonality=yes +MemoryDenyWriteExecute=yes +RestrictRealtime=yes +RestrictSUIDSGID=yes + +# System Call Filtering +SystemCallFilter=@system-service +SystemCallFilter=~@resources @privileged +SystemCallArchitectures=native [Install] Also=pcscd.socket diff --git a/etc/pcscd.socket.in b/etc/pcscd.socket.in index 0a5654b9..81c855ce 100644 --- a/etc/pcscd.socket.in +++ b/etc/pcscd.socket.in @@ -4,6 +4,8 @@ Description=PC/SC Smart Card Daemon Activation Socket [Socket] ListenStream=@ipcdir@/pcscd.comm SocketMode=0666 +SocketUser=pcscd +SocketGroup=pcscd [Install] WantedBy=sockets.target diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..22f569c0 --- /dev/null +++ b/meson.build @@ -0,0 +1,328 @@ +# for ninja: +# meson setup builddir +# cd builddir ; meson compile + +# fox Xcode: +# meson setup --backend=xcode xcode +# cd xcode ; meson compile + +# regenerate configuration (run from builddir/) +# meson setup --reconfigure --wipe + +project('pcsc-lite', 'c', + meson_version : '>=0.58.0', + version : '2.4.1') + +# for config.h +conf_data = configuration_data({ + 'VERSION' : '"' + meson.project_version() + '"', + 'PCSCLITE_HP_DROPDIR' : '"' + get_option('usbdropdir') + '"', + 'HAVE_NANOSLEEP' : true, + 'NO_LOG' : get_option('embedded'), + }) +# for generated files from .in templates +sbindir = join_paths(get_option('prefix') , get_option('sbindir')) +confgen_data = configuration_data({ + 'VERSION' : meson.project_version(), + 'ipcdir' : get_option('ipcdir'), + 'sysconfdir' : get_option('sysconfdir'), + 'sbindir_exp' : sbindir, + 'PCSCLITE_CONFIG_DIR' : get_option('serialconfdir'), + 'usbdropdir' : get_option('usbdropdir'), + }) + +# tests for functions +compiler = meson.get_compiler('c') +if compiler.has_function('getrandom', prefix : '#include ') + conf_data.set('HAVE_GETRANDOM', true) +endif +if compiler.has_function('secure_getenv') + conf_data.set('HAVE_SECURE_GETENV', true) +endif +if compiler.has_function('getopt_long') + conf_data.set('HAVE_GETOPT_LONG', true) +endif + +# tests for options +features = [] +if get_option('usb') + conf_data.set('USE_USB', true) + features += 'USB' +endif + +if get_option('serial') + conf_data.set('USE_SERIAL', true) + features += 'serial' +endif + +if get_option('filter_names') + conf_data.set('FILTER_NAMES', true) + features += 'filter_names' +endif + +# flex generator +gen_flex = generator(find_program('flex'), + output : '@BASENAME@.c', + arguments : ['-o', '@OUTPUT@', '--prefix=@BASENAME@', '@INPUT@']) + +# global arguments +add_global_arguments('-fvisibility=hidden', language : 'c') + +# pcscd daemon +pcscd_src = [ + 'src/atrhandler.c', + 'src/auth.c', + 'src/debuglog.c', + 'src/dyn_unix.c', + 'src/eventhandler.c', + 'src/hotplug_generic.c', + 'src/hotplug_libudev.c', + 'src/hotplug_libusb.c', + 'src/ifdwrapper.c', + 'src/pcscdaemon.c', + 'src/prothandler.c', + 'src/readerfactory.c', + 'src/simclist.c', + 'src/sys_unix.c', + 'src/utils.c', + 'src/winscard.c', + 'src/winscard_msg.c', + 'src/winscard_msg_srv.c', + 'src/winscard_svc.c' + ] +gen_src = gen_flex.process('src/configfile.l', 'src/tokenparser.l') +pcscd_src += gen_src +incdir = include_directories(['src', 'src/PCSC']) + +# dependencies +threads_dep = dependency('threads') +pcscd_dep = [threads_dep] +if get_option('libudev') + udev_dep = dependency('libudev') + pcscd_dep += udev_dep + conf_data.set('HAVE_LIBUDEV', true) + features += 'libudev' +endif + +if get_option('libusb') + if get_option('libudev') + error('You can\'t use both libudev and libusb') + endif + libusb_dep = dependency('libusb-1.0') + pcscd_dep += libusb_dep + conf_data.set('HAVE_LIBUSB', true) + features += 'libusb' +endif + +cc = meson.get_compiler('c') +dl_deps = cc.find_library('dl', required: false) + +pcscd_dep += dl_deps + +if get_option('polkit') + polkit_dep = dependency('polkit-gobject-1') + pcscd_dep += polkit_dep + conf_data.set('HAVE_POLKIT', true) + confgen_data.set('requires_polkit', 'Requires=polkit.service') + features += 'polkit' +endif + +systemdunit = get_option('systemdunit') +if get_option('libsystemd') + systemd_dep = dependency('libsystemd') + pcscd_dep += systemd_dep + conf_data.set('USE_LIBSYSTEMD', true) + features += 'systemd' + + systemd = dependency('systemd') + systemdsystemunitdir = systemd.get_variable(pkgconfig : 'systemd' + systemdunit + 'unitdir') + sysusersdir = systemd.get_variable(pkgconfig : 'sysusersdir') +else + systemdsystemunitdir = get_option('prefix') / 'lib' / 'systemd' / systemdunit + sysusersdir = get_option('prefix') / 'sysusers.d' +endif + +# architecture +r = run_command('uname', check: true) +pcsc_arch = r.stdout().strip() +if pcsc_arch == 'Darwin' + pcsc_arch = 'MacOS' + pcscd_dep += dependency('appleframeworks', modules : ['foundation', 'IOKit']) + pcscd_src += files(['src/hotplug_macosx.c', 'src/dyn_macosx.c']) +endif +conf_data.set_quoted('PCSC_ARCH', pcsc_arch) + +features += pcsc_arch +features += target_machine.cpu() +features += 'ipcdir=' + get_option('ipcdir') +features += 'usbdropdir=' + get_option('usbdropdir') +features += 'serialconfdir=' + get_option('serialconfdir') + +# generate PCSCLITE_FEATURES +conf_data.set('PCSCLITE_FEATURES', '"' + ' '.join(features) + '"') + +executable('pcscd', + sources : pcscd_src, + include_directories : incdir, + dependencies : pcscd_dep, + c_args: '-DPCSCD', + export_dynamic : true, + install_dir : sbindir, + install : true) + +# libpcsclite_real library +libpcsclite_real_src = [ + 'src/debug.c', + 'src/winscard_clnt.c', + 'src/simclist.c', + 'src/sys_unix.c', + 'src/utils.c', + 'src/winscard_msg.c' + ] + +# libpcsclite library +libpcsclite_src = [ + 'src/error.c', + 'src/g_defines.c', + 'src/libredirect.c', + 'src/sys_unix.c' + ] +if get_option('default_library') != 'static' + libpcsclite = shared_library('pcsclite', + libpcsclite_src, + dependencies : [dl_deps, threads_dep], + include_directories : incdir, + soversion : 1, + install : true) + + shared_library('pcsclite_real', + libpcsclite_real_src, + include_directories : incdir, + dependencies : threads_dep, + c_args: '-DLIBPCSCLITE -DSIMCLIST_NO_DUMPRESTORE', + soversion : 1, + install : true) +endif + +# static library +libpcsclite_static_src = libpcsclite_real_src + [ + 'src/error.c', + 'src/g_defines.c', + ] +if get_option('default_library') != 'shared' + libpcsclite_static = static_library('pcsclite', + libpcsclite_static_src, + include_directories : incdir, + dependencies : threads_dep, + c_args: '-DLIBPCSCLITE -DSIMCLIST_NO_DUMPRESTORE', + install : true) + if get_option('default_library') == 'static' + libpcsclite = libpcsclite_static + endif +endif + +# libpcsclite_fake library +library('pcsclite_fake', + sources : 'src/libfake.c', + include_directories : incdir) + +# testpcsc program +executable('testpcsc', + sources : 'src/testpcsc.c', + include_directories : incdir, + link_with : libpcsclite) + +executable('pcsc_demo', + sources : 'doc/example/pcsc_demo.c', + include_directories : incdir, + link_with : libpcsclite) + +if get_option('default_library') == 'both' + executable('pcsc_demo_static', + sources : 'doc/example/pcsc_demo.c', + include_directories : incdir, + link_with : libpcsclite_static) +endif + +# PC/SC headers +install_headers( + ['src/PCSC/debuglog.h', + 'src/PCSC/ifdhandler.h', + 'src/PCSC/reader.h', + 'src/PCSC/winscard.h', + 'src/PCSC/wintypes.h'], + install_dir : get_option('includedir') / 'PCSC') + +# data +if get_option('polkit') +install_data('doc/org.debian.pcsc-lite.policy', + install_dir : polkit_dep.get_variable('policydir')) +endif + +install_data('etc/fr.apdu.pcsclite.metainfo.xml', + install_dir : 'share/metainfo' + ) + +install_data('etc/pcscd', + install_dir : get_option('sysconfdir') / 'default' + ) + +# generate config.h +configure_file(output : 'config.h', + configuration : conf_data) + +# generate from .in files +configure_file(output : 'pcsclite.h', + input : 'src/PCSC/pcsclite.h.in', + install_dir : get_option('prefix') / get_option('includedir') / 'PCSC', + configuration : confgen_data) +configure_file(output : 'pcscd.h', + input : 'src/pcscd.h.in', + configuration : confgen_data) +configure_file(output : 'pcscd.socket', + input : 'etc/pcscd.socket.in', + install_dir : systemdsystemunitdir, + configuration : confgen_data) +configure_file(output : 'pcscd.service', + input : 'etc/pcscd.service.in', + install_dir : systemdsystemunitdir, + configuration : confgen_data) +install_data('etc/pcscd-sysusers.conf', + install_dir : sysusersdir) +configure_file(output : 'pcscd.8', + input : 'doc/pcscd.8.in', + install_dir : join_paths(get_option('mandir'), 'man8'), + configuration : confgen_data) +if get_option('serial') +configure_file(output : 'reader.conf.5', + input : 'doc/reader.conf.5.in', + install_dir : join_paths(get_option('mandir'), 'man5'), + configuration : confgen_data) +endif + +# pkg-config libpcsclite.pc +pkg = import('pkgconfig') +pkg.generate( + extra_cflags : '-pthread', + libraries : '-L${libdir} -lpcsclite', + libraries_private : '-pthread', + subdirs : 'PCSC', + version : meson.project_version(), + name : 'PCSC Lite', + filebase : 'libpcsclite', + variables : [ + 'usbdropdir=' + conf_data.get_unquoted('PCSCLITE_HP_DROPDIR'), + 'serialconfdir=' + get_option('serialconfdir')], + description : 'PC/SC smart card interface') + +# generate documentation +configure_file(output : 'doxygen.conf', + input : 'doc/doxygen.conf.in', + configuration : confgen_data) +doxygen = find_program('doxygen', required : false) +if doxygen.found() + message('Doxygen found') + run_target('doc', command : [doxygen, 'doxygen.conf']) +else + warning('Documentation disabled without doxygen') +endif diff --git a/meson.options b/meson.options new file mode 100644 index 00000000..f0b58cac --- /dev/null +++ b/meson.options @@ -0,0 +1,55 @@ +option('libsystemd', + type : 'boolean', + description : 'Use systemd for daemon auto start') + +option('libudev', + type : 'boolean', + description : 'Use libudev (preferred) for USB hotplug') + +option('libusb', + type : 'boolean', + value : false, + description : 'Use libusb for USB hotplug') + +option('polkit', + type : 'boolean', + description : 'Use polkit to enforce access control') + +option('usb', + type : 'boolean', + description : 'Support USB readers') + +option('serial', + type : 'boolean', + description : 'Support serial readers') + +option('serialconfdir', + type : 'string', + value : '/etc/reader.conf.d', + description : 'Path for serial configuration files') + +option('usbdropdir', + type : 'string', + value : '/usr/lib/pcsc/drivers', + description : 'Path for USB drivers') + +option('ipcdir', + type : 'string', + value : '/run/pcscd', + description : 'Direcrory for pcsc-lite internal communication socket') + +option('systemdunit', + type : 'combo', + choices : ['user', 'system'], + value : 'user', + description : 'Systemd unit directory to use') + +option('embedded', + type : 'boolean', + value : false, + description : 'for embedded systems [limit RAM and CPU resources by disabling features (log)]') + +option('filter_names', + type : 'boolean', + value : true, + description : 'reader filtering using PCSCLITE_FILTER_IGNORE_READER_NAMES and PCSCLITE_FILTER_EXTEND_READER_NAMES') diff --git a/meson_options.txt b/meson_options.txt new file mode 120000 index 00000000..7b28df27 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +meson.options \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 6c7eddb5..70ad31c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/PCSC -I$(top_builddir)/src/PCSC \ $(SYMBOL_VISIBILITY) -lib_LTLIBRARIES = libpcsclite.la +lib_LTLIBRARIES = libpcsclite.la libpcsclite_real.la +check_LTLIBRARIES = libpcsclite_fake.la sbin_PROGRAMS = pcscd noinst_PROGRAMS = testpcsc pcsc-wirecheck pcsc-wirecheck-gen @@ -18,16 +19,25 @@ USB_CONFIG = tokenparser.l \ endif libpcsclite_la_SOURCES = \ - debug.c \ error.c \ + g_defines.c \ + libredirect.c \ + sys_unix.c +libpcsclite_la_LDFLAGS = -version-info 1:0:0 + +libpcsclite_real_la_SOURCES = \ + debug.c \ winscard_clnt.c \ simclist.c \ sys_unix.c \ utils.c \ winscard_msg.c -libpcsclite_la_LDFLAGS = -version-info 1:0:0 -libpcsclite_la_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) -DLIBPCSCLITE -DSIMCLIST_NO_DUMPRESTORE -libpcsclite_la_LIBADD = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +libpcsclite_real_la_LDFLAGS = -version-info 1:0:0 +libpcsclite_real_la_CFLAGS = $(PTHREAD_CFLAGS) -DLIBPCSCLITE -DSIMCLIST_NO_DUMPRESTORE +libpcsclite_real_la_LIBADD = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +libpcsclite_fake_la_SOURCES = \ + libfake.c pcscd_SOURCES = \ auth.c \ @@ -38,7 +48,6 @@ pcscd_SOURCES = \ $(SERIAL_CONFIG) \ debuglog.c \ dyn_generic.h \ - dyn_hpux.c \ dyn_macosx.c \ dyn_unix.c \ eventhandler.c \ @@ -73,7 +82,7 @@ pcscd_SOURCES = \ winscard_msg_srv.c \ winscard_svc.c \ winscard_svc.h -pcscd_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) $(LIBUDEV_CFLAGS) \ +pcscd_CFLAGS = $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) $(LIBUDEV_CFLAGS) \ $(POLKIT_CFLAGS) $(LIBSYSTEMD_CFLAGS) \ -DPCSCD -DSIMCLIST_NO_DUMPRESTORE pcscd_LDFLAGS = $(LDFLAGS) $(LIBSYSTEMD_LIBS) -export-dynamic diff --git a/src/PCSC/debuglog.h b/src/PCSC/debuglog.h index 64883e21..e5dcbb29 100644 --- a/src/PCSC/debuglog.h +++ b/src/PCSC/debuglog.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2004 * David Corcoran - * Copyright (C) 1999-2011 + * Copyright (C) 1999-2022 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -90,7 +90,7 @@ enum { #define Log0(priority) do { } while(0) #define Log1(priority, fmt) do { } while(0) #define Log2(priority, fmt, data) do {(void)priority; } while(0) -#define Log3(priority, fmt, data1, data2) do {int p = priority; (void)p; } while(0) +#define Log3(priority, fmt, data1, data2) do {int _p = priority; (void)_p; } while(0) #define Log4(priority, fmt, data1, data2, data3) do { } while(0) #define LogRv4(priority, rv, fmt, data1, data2) do { } while(0) #define Log5(priority, fmt, data1, data2, data3, data4) do { } while(0) diff --git a/src/PCSC/ifdhandler.h b/src/PCSC/ifdhandler.h index a60ca8fc..d47a22ac 100644 --- a/src/PCSC/ifdhandler.h +++ b/src/PCSC/ifdhandler.h @@ -5,7 +5,7 @@ * David Corcoran * Copyright (C) 2003-2004 * Damien Sauveron - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -213,7 +213,7 @@ The pound sign # denotes a comment. @subsection FRIENDLYNAME The FRIENDLYNAME field is an arbitrary text used to identify the reader. This text is displayed by commands like @c pcsc_scan -http://ludovic.rousseau.free.fr/softwares/pcsc-tools/ that prints the +https://pcsc-tools.apdu.fr/ that prints the names of all the connected and detected readers. @subsection DEVICENAME @@ -315,7 +315,7 @@ whichever location your reader resides. SCARD_IO_HEADER, *PSCARD_IO_HEADER; /* - * The list of tags should be alot more but this is all I use in the + * The list of tags should be a lot more but this is all I use in the * meantime */ #define TAG_IFD_ATR 0x0303 /**< ATR */ @@ -411,7 +411,7 @@ possible to query IFDHICCPresence() for card status. PC/SC supports the loading of multiple readers through one instance of the driver in which XXXX is important. XXXX identifies the unique reader in which the driver communicates to. The driver should set up - an array of structures that asociate this XXXX with the underlying + an array of structures that associate this XXXX with the underlying details of the particular reader. @param[in] DeviceName Filename to use by the driver.\n @@ -459,7 +459,7 @@ port used by each reader. @endcode bInterfaceNumber is the number of the interface on the device. It is - only usefull for devices with more than one CCID interface. + only useful for devices with more than one CCID interface. devpath is the filename of the device on the file system. diff --git a/src/PCSC/pcsclite.h.in b/src/PCSC/pcsclite.h.in index 968514d4..b687bb50 100644 --- a/src/PCSC/pcsclite.h.in +++ b/src/PCSC/pcsclite.h.in @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2004 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Copyright (C) 2005 * Martin Paljak @@ -58,7 +58,7 @@ typedef SCARDHANDLE *LPSCARDHANDLE; #define MAX_ATR_SIZE 33 /**< Maximum ATR size */ -/* Set structure elements aligment on bytes +/* Set structure elements alignment on bytes * http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */ #ifdef __APPLE__ #pragma pack(1) @@ -192,7 +192,8 @@ extern const SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci; /** @ingroup ErrorCodes */ #define SCARD_E_INVALID_CHV ((LONG)0x8010002A) /**< The supplied PIN is incorrect. */ /** @ingroup ErrorCodes */ -#define SCARD_E_UNKNOWN_RES_MNG ((LONG)0x8010002B) /**< An unrecognized error code was returned from a layered component. */ +#define SCARD_E_UNKNOWN_RES_MSG ((LONG)0x8010002B) /**< An unrecognized error code was returned from a layered component. */ +#define SCARD_E_UNKNOWN_RES_MNG SCARD_E_UNKNOWN_RES_MSG /** @ingroup ErrorCodes */ #define SCARD_E_NO_SUCH_CERTIFICATE ((LONG)0x8010002C) /**< The requested certificate does not exist. */ /** @ingroup ErrorCodes */ @@ -292,7 +293,7 @@ extern const SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci; /* * The message and buffer sizes must be multiples of 16. * The max message size must be at least large enough - * to accomodate the transmit_struct + * to accommodate the transmit_struct */ #define MAX_BUFFER_SIZE 264 /**< Maximum Tx/Rx Buffer for short APDU */ #define MAX_BUFFER_SIZE_EXTENDED (4 + 3 + (1<<16) + 3 + 2) /**< enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer */ diff --git a/src/PCSC/reader.h b/src/PCSC/reader.h index f00eed7b..8e9fcd6c 100644 --- a/src/PCSC/reader.h +++ b/src/PCSC/reader.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2005 * David Corcoran - * Copyright (C) 2005-2009 + * Copyright (C) 2005-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -148,7 +148,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -/* Set structure elements aligment on bytes +/* Set structure elements alignment on bytes * http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */ #if defined(__APPLE__) || defined(sun) || defined(__NetBSD__) #pragma pack(1) diff --git a/src/PCSC/winscard.h b/src/PCSC/winscard.h index a4ea5782..cfc729fa 100644 --- a/src/PCSC/winscard.h +++ b/src/PCSC/winscard.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2003 * David Corcoran - * Copyright (C) 2002-2009 + * Copyright (C) 2002-2018 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/PCSC/wintypes.h b/src/PCSC/wintypes.h index 474b5a5f..10734e6b 100644 --- a/src/PCSC/wintypes.h +++ b/src/PCSC/wintypes.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2018 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/README_INTERNALS.txt b/src/README_INTERNALS.txt index 33e429ae..ccc13bb3 100644 --- a/src/README_INTERNALS.txt +++ b/src/README_INTERNALS.txt @@ -20,18 +20,18 @@ pcscd (daemon) atrhandler.c configfile.l debuglog.c - dyn_hpux.c (this file is OS dependant) - dyn_macosx.c (this file is OS dependant) - dyn_unix.c (this file is OS dependant) + dyn_hpux.c (this file is OS dependent) + dyn_macosx.c (this file is OS dependent) + dyn_unix.c (this file is OS dependent) eventhandler.c hotplug_generic.c hotplug_libusb.c - hotplug_macosx.c (this file is OS dependant) + hotplug_macosx.c (this file is OS dependent) ifdwrapper.c pcscdaemon.c prothandler.c readerfactory.c - sys_unix.c (this file is OS dependant) + sys_unix.c (this file is OS dependent) tokenparser.l winscard.c winscard_msg.c @@ -60,7 +60,7 @@ Maximum applications Maximum contexts by application PCSCLITE_MAX_APPLICATION_CONTEXTS -Maximum of applications contexts that PC/SC Ressources Manager can accept +Maximum of applications contexts that PC/SC Resources Manager can accept PCSCLITE_MAX_APPLICATIONS_CONTEXTS = PCSCLITE_MAX_APPLICATIONS * PCSCLITE_MAX_APPLICATION_CONTEXTS @@ -91,7 +91,7 @@ PC/SC D1 handles 5 APPLICATIONS_CONTEXTS. PC/SC D1 also handles 3 READERS_CONTEXTS. These contexts are created for example by the plug of the readers. -The maximum of applications contexts that PC/SC Ressources Manager can +The maximum of applications contexts that PC/SC Resources Manager can accept is thus PCSCLITE_MAX_APPLICATIONS * PCSCLITE_MAX_APPLICATION_CONTEXTS. @@ -118,7 +118,7 @@ PC/SC D3 | | | (7) | App D ---------------/ -For simplify, there are 3 differents roles: Application, PC/SC Daemon +For simplify, there are 3 different roles: Application, PC/SC Daemon and IFDhandler/reader. Between these role there are some contexts and on the top of them there diff --git a/src/atrhandler.c b/src/atrhandler.c index dad30d6f..5840430b 100644 --- a/src/atrhandler.c +++ b/src/atrhandler.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -82,16 +82,16 @@ short ATRDecodeAtr(int *availableProtocols, int *currentProtocol, *currentProtocol = SCARD_PROTOCOL_UNDEFINED; if (dwLength < 2) - return 0; /** @retval 0 Atr must have TS and T0 */ + return -1; /** @retval -1 Atr must have TS and T0 */ /* * Decode the TS byte */ if ((pucAtr[0] != 0x3F) && (pucAtr[0] != 0x3B)) - return 0; /** @retval 0 Unable to decode TS byte */ + return -2; /** @retval -2 Unable to decode TS byte */ /* - * Here comes the platform dependant stuff + * Here comes the platform dependent stuff */ /* @@ -146,7 +146,7 @@ short ATRDecodeAtr(int *availableProtocols, int *currentProtocol, *currentProtocol = SCARD_PROTOCOL_T1; break; default: - return 0; /** @retval 0 Unable to decode LNS */ + return -3; /** @retval -3 Unable to decode LNS */ } } @@ -196,12 +196,12 @@ short ATRDecodeAtr(int *availableProtocols, int *currentProtocol, break; default: - return 0; /** @retval 0 Unable do decode T protocol */ + return -4; /** @retval -4 Unable do decode T protocol */ } } if (p > MAX_ATR_SIZE) - return 0; /** @retval 0 Maximum attribute size */ + return -5; /** @retval -5 Maximum attribute size */ /* next interface characters index */ i++; @@ -222,5 +222,5 @@ short ATRDecodeAtr(int *availableProtocols, int *currentProtocol, *currentProtocol - SCARD_PROTOCOL_T0, *availableProtocols); #endif - return 1; /** @retval 1 Success */ + return 0; /** @retval 0 Success */ } diff --git a/src/atrhandler.h b/src/atrhandler.h index d42894bb..1d4e039e 100644 --- a/src/atrhandler.h +++ b/src/atrhandler.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2002-2009 + * Copyright (C) 2002-2021 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/auth.c b/src/auth.c index e0318ed6..a09a6e0a 100644 --- a/src/auth.c +++ b/src/auth.c @@ -51,14 +51,34 @@ #include -#if defined(HAVE_POLKIT) && defined(SO_PEERCRED) +#ifdef HAVE_POLKIT + +#if defined(SO_PEERCRED) || defined(LOCAL_PEERCRED) #include +#include + +#ifdef __FreeBSD__ + +#include +typedef struct xucred platform_cred; +#define CRED_PID(uc) (uc).cr_pid +#define CRED_UID(uc) (uc).cr_uid + +#else + +typedef struct ucred platform_cred; +#define CRED_PID(uc) (uc).pid +#define CRED_UID(uc) (uc).uid + +#endif + +extern bool disable_polkit; /* Returns non zero when the client is authorized */ unsigned IsClientAuthorized(int socket, const char* action, const char* reader) { - struct ucred cr; + platform_cred cr; socklen_t cr_len; int ret; PolkitSubject *subject; @@ -68,15 +88,24 @@ unsigned IsClientAuthorized(int socket, const char* action, const char* reader) GError *error = NULL; char action_name[128]; + if (disable_polkit) + return 1; + snprintf(action_name, sizeof(action_name), "org.debian.pcsc-lite.%s", action); cr_len = sizeof(cr); +#ifdef LOCAL_PEERCRED + ret = getsockopt(socket, SOL_LOCAL, LOCAL_PEERCRED, &cr, &cr_len); +#else ret = getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len); +#endif if (ret == -1) { +#ifndef NO_LOG int e = errno; Log2(PCSC_LOG_CRITICAL, "Error obtaining client process credentials: %s", strerror(e)); +#endif return 0; } @@ -89,7 +118,7 @@ unsigned IsClientAuthorized(int socket, const char* action, const char* reader) return 0; } - subject = polkit_unix_process_new_for_owner(cr.pid, 0, cr.uid); + subject = polkit_unix_process_new_for_owner(CRED_PID(cr), 0, CRED_UID(cr)); if (subject == NULL) { Log1(PCSC_LOG_CRITICAL, "polkit_unix_process_new_for_owner failed"); @@ -136,7 +165,7 @@ unsigned IsClientAuthorized(int socket, const char* action, const char* reader) { Log4(PCSC_LOG_CRITICAL, "Process %u (user: %u) is NOT authorized for action: %s", - (unsigned)cr.pid, (unsigned)cr.uid, action); + (unsigned)CRED_PID(cr), (unsigned)CRED_UID(cr), action); } if (result) @@ -153,6 +182,14 @@ unsigned IsClientAuthorized(int socket, const char* action, const char* reader) #else +/* Do not enable polkit if it not yet supported on your system. + * Patches are welcome. */ +#error polkit is enabled, but no socket cred implementation for this platform + +#endif + +#else + unsigned IsClientAuthorized(int socket, const char* action, const char* reader) { (void)socket; diff --git a/src/configfile.h b/src/configfile.h index accb454f..c287a97b 100644 --- a/src/configfile.h +++ b/src/configfile.h @@ -5,7 +5,7 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2021 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/configfile.l b/src/configfile.l index 3bbf8263..fd441658 100644 --- a/src/configfile.l +++ b/src/configfile.l @@ -7,7 +7,7 @@ * David Corcoran * Copyright (C) 2004 * Damien Sauveron - * Copyright (C) 2004-2010 + * Copyright (C) 2004-2021 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -302,9 +302,7 @@ int DBGetReaderListDir(const char *readerconf_dir, readerconf_dir, direntry->d_name); /* skip non regular files */ -#ifdef HAVE_STRUCT_DIRENT_D_TYPE if (direntry->d_type == DT_UNKNOWN) -#endif { struct stat st; @@ -322,7 +320,6 @@ int DBGetReaderListDir(const char *readerconf_dir, continue; } } -#ifdef HAVE_STRUCT_DIRENT_D_TYPE else if (direntry->d_type != DT_REG) { @@ -330,7 +327,6 @@ int DBGetReaderListDir(const char *readerconf_dir, direntry->d_name); continue; } -#endif /* skip files starting with . like ., .., .svn, etc */ if ('.' == direntry->d_name[0]) diff --git a/src/debug.c b/src/debug.c index 9ad419bf..803d3164 100644 --- a/src/debug.c +++ b/src/debug.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -42,10 +42,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include -/* We shall not export the log_msg() sumbol */ +/* We shall not export the log_msg() symbol */ #undef PCSC_API #include "debuglog.h" +#include "sys_generic.h" #define DEBUG_BUF_SIZE 2048 @@ -66,18 +68,18 @@ static signed char LogDoColor = 0; /**< no color by default */ static void log_init(void) { - char *e; + const char *e; - e = getenv("PCSCLITE_DEBUG"); + e = SYS_GetEnv("PCSCLITE_DEBUG"); if (e) LogLevel = atoi(e); /* log to stderr and stderr is a tty? */ if (isatty(fileno(stderr))) { - char *term; + const char *term; - term = getenv("TERM"); + term = SYS_GetEnv("TERM"); if (term) { const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode" }; @@ -101,12 +103,12 @@ void log_msg(const int priority, const char *fmt, ...) { char DebugBuffer[DEBUG_BUF_SIZE]; va_list argptr; - static int is_initialized = 0; + static bool is_initialized = false; if (!is_initialized) { log_init(); - is_initialized = 1; + is_initialized = true; } if (priority < LogLevel) /* log priority lower than threshold? */ diff --git a/src/debuglog.c b/src/debuglog.c index ac876769..cc470538 100644 --- a/src/debuglog.c +++ b/src/debuglog.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2025 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -36,9 +36,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#ifdef HAVE_SYSLOG_H #include -#endif #include #include #include @@ -49,6 +47,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "pcsclite.h" #include "misc.h" @@ -98,7 +97,7 @@ INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer, #else /** - * Max string size dumping a maxmium of 2 lines of 80 characters + * Max string size dumping a maximum of 2 lines of 80 characters */ #define DEBUG_BUF_SIZE 2048 @@ -108,7 +107,9 @@ static char LogCategory = DEBUG_CATEGORY_NOTHING; /** default level */ static char LogLevel = PCSC_LOG_ERROR; -static signed char LogDoColor = 0; /**< no color by default */ +static bool LogDoColor = false; /**< no color by default */ + +static pthread_mutex_t LastTimeMutex = PTHREAD_MUTEX_INITIALIZER; static void log_line(const int priority, const char *DebugBuffer, unsigned int rv); @@ -172,11 +173,13 @@ const char * rv2text(unsigned int rv) CASE(SCARD_E_INVALID_PARAMETER); CASE(SCARD_E_INVALID_VALUE); CASE(SCARD_E_NO_MEMORY); + CASE(SCARD_E_NO_READERS_AVAILABLE); CASE(SCARD_E_NO_SERVICE); CASE(SCARD_E_NO_SMARTCARD); CASE(SCARD_E_NOT_TRANSACTED); CASE(SCARD_E_PROTO_MISMATCH); CASE(SCARD_E_READER_UNAVAILABLE); + CASE(SCARD_E_SERVICE_STOPPED); CASE(SCARD_E_SHARING_VIOLATION); CASE(SCARD_E_TIMEOUT); CASE(SCARD_E_UNKNOWN_READER); @@ -187,7 +190,6 @@ const char * rv2text(unsigned int rv) CASE(SCARD_W_RESET_CARD); CASE(SCARD_W_UNPOWERED_CARD); CASE(SCARD_W_UNRESPONSIVE_CARD); - CASE(SCARD_E_NO_READERS_AVAILABLE); default: (void)snprintf(strError, sizeof(strError)-1, @@ -213,6 +215,7 @@ static void log_line(const int priority, const char *DebugBuffer, pthread_t thread_id; const char *rv_text = NULL; + (void)pthread_mutex_lock(&LastTimeMutex); gettimeofday(&new_time, NULL); if (0 == last_time.tv_sec) last_time = new_time; @@ -230,6 +233,7 @@ static void log_line(const int priority, const char *DebugBuffer, delta = 99999999; last_time = new_time; + (void)pthread_mutex_unlock(&LastTimeMutex); thread_id = pthread_self(); @@ -260,10 +264,10 @@ static void log_line(const int priority, const char *DebugBuffer, break; } -#ifdef __APPLE__ -#define THREAD_FORMAT "%p" -#else +#ifdef __GLIBC__ #define THREAD_FORMAT "%lu" +#else +#define THREAD_FORMAT "%p" #endif if (rv_text) { @@ -337,8 +341,11 @@ void DebugLogSetLogType(const int dbgtype) case DEBUGLOG_NO_DEBUG: case DEBUGLOG_SYSLOG_DEBUG: case DEBUGLOG_STDOUT_DEBUG: + LogMsgType = dbgtype; + break; case DEBUGLOG_STDOUT_COLOR_DEBUG: LogMsgType = dbgtype; + LogDoColor = true; break; default: Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stdout", @@ -347,12 +354,11 @@ void DebugLogSetLogType(const int dbgtype) } /* log to stdout and stdout is a tty? */ - if ((DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout))) - || (DEBUGLOG_STDOUT_COLOR_DEBUG == LogMsgType)) + if (DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout))) { - char *term; + const char *term; - term = getenv("TERM"); + term = SYS_GetEnv("TERM"); if (term) { const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" }; @@ -364,7 +370,7 @@ void DebugLogSetLogType(const int dbgtype) /* we found a supported term? */ if (0 == strcmp(terms[i], term)) { - LogDoColor = 1; + LogDoColor = true; break; } } diff --git a/src/dyn_generic.h b/src/dyn_generic.h index 08eea707..85b1cddd 100644 --- a/src/dyn_generic.h +++ b/src/dyn_generic.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2002-2009 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -38,10 +38,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef __dyn_generic_h__ #define __dyn_generic_h__ +#include #include "wintypes.h" - LONG DYN_LoadLibrary(void **, char *); - LONG DYN_CloseLibrary(void **); - LONG DYN_GetAddress(void *, /*@out@*/ void **, const char *, int); + void * DYN_LoadLibrary(const char *); + LONG DYN_CloseLibrary(void *); + LONG DYN_GetAddress(void *, /*@out@*/ void **, const char *, bool); #endif diff --git a/src/dyn_hpux.c b/src/dyn_hpux.c deleted file mode 100644 index baa55e39..00000000 --- a/src/dyn_hpux.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) - * - * Copyright (C) 2001 - * David Corcoran - * Copyright (C) 2002-2010 - * Ludovic Rousseau - * -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * @file - * @brief This abstracts dynamic library loading functions and timing. - */ - -#include "config.h" -#include -#ifdef HAVE_DL_H -#include -#include - -#include "pcsclite.h" -#include "debuglog.h" -#include "dyn_generic.h" - -LONG DYN_LoadLibrary(void **pvLHandle, char *pcLibrary) -{ - - shl_t myHandle; - - *pvLHandle = 0; - myHandle = - shl_load(pcLibrary, BIND_IMMEDIATE | BIND_VERBOSE | BIND_NOSTART, - 0L); - - if (myHandle == 0) - { - Log3(PCSC_LOG_ERROR, "%s: %s", pcLibrary, strerror(errno)); - return SCARD_F_UNKNOWN_ERROR; - } - - *pvLHandle = (void *) myHandle; - return SCARD_S_SUCCESS; -} - -LONG DYN_CloseLibrary(void **pvLHandle) -{ - - int rv; - - rv = shl_unload((shl_t) * pvLHandle); - *pvLHandle = 0; - - if (rv == -1) - { - Log2(PCSC_LOG_ERROR, "%s", strerror(errno)); - return SCARD_F_UNKNOWN_ERROR; - } - - return SCARD_S_SUCCESS; -} - -LONG DYN_GetAddress(void *pvLHandle, void **pvFHandle, const char *pcFunction, - int mayfail) -{ - - int rv; - - *pvFHandle = 0; - rv = shl_findsym((shl_t *) & pvLHandle, pcFunction, TYPE_PROCEDURE, - pvFHandle); - - if (rv == -1) - { - Log3(mayfail ? PCSC_LOG_INFO : PCSC_LOG_ERROR, "%s: %s", - pcFunction, strerror(errno)); - rv = SCARD_F_UNKNOWN_ERROR; - } - else - rv = SCARD_S_SUCCESS; - - return rv; -} - -#endif /* HAVE_DL_H */ - diff --git a/src/dyn_macosx.c b/src/dyn_macosx.c index 0a7821c4..ba669874 100644 --- a/src/dyn_macosx.c +++ b/src/dyn_macosx.c @@ -3,7 +3,7 @@ * * Copyright (C) 2000 * David Corcoran - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -50,14 +50,14 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* * / Load a module (if needed) */ -int DYN_LoadLibrary(void **pvLHandle, char *pcLibrary) +void * DYN_LoadLibrary(const char *pcLibrary) { CFStringRef bundlePath; CFURLRef bundleURL; CFBundleRef bundle; - *pvLHandle = 0; + void *pvLHandle = 0; /* * @@@ kCFStringEncodingMacRoman might be wrong on non US systems. @@ -66,38 +66,38 @@ int DYN_LoadLibrary(void **pvLHandle, char *pcLibrary) bundlePath = CFStringCreateWithCString(NULL, pcLibrary, kCFStringEncodingMacRoman); if (bundlePath == NULL) - return SCARD_E_NO_MEMORY; + return NULL; bundleURL = CFURLCreateWithFileSystemPath(NULL, bundlePath, kCFURLPOSIXPathStyle, TRUE); CFRelease(bundlePath); if (bundleURL == NULL) - return SCARD_E_NO_MEMORY; + return NULL; bundle = CFBundleCreate(NULL, bundleURL); CFRelease(bundleURL); if (bundle == NULL) { Log1(PCSC_LOG_ERROR, "CFBundleCreate"); - return SCARD_F_UNKNOWN_ERROR; + return NULL; } if (!CFBundleLoadExecutable(bundle)) { Log1(PCSC_LOG_ERROR, "CFBundleLoadExecutable"); CFRelease(bundle); - return SCARD_F_UNKNOWN_ERROR; + return NULL; } - *pvLHandle = (void *) bundle; + pvLHandle = (void *) bundle; - return SCARD_S_SUCCESS; + return pvLHandle; } -int DYN_CloseLibrary(void **pvLHandle) +int DYN_CloseLibrary(void *pvLHandle) { - CFBundleRef bundle = (CFBundleRef) * pvLHandle; + CFBundleRef bundle = (CFBundleRef) pvLHandle; if (CFBundleIsExecutableLoaded(bundle) == TRUE) { @@ -107,12 +107,11 @@ int DYN_CloseLibrary(void **pvLHandle) else Log1(PCSC_LOG_ERROR, "Cannot unload library."); - *pvLHandle = 0; return SCARD_S_SUCCESS; } int DYN_GetAddress(void *pvLHandle, void **pvFHandle, const char *pcFunction, - int mayfail) + bool mayfail) { (void)mayfail; diff --git a/src/dyn_unix.c b/src/dyn_unix.c index e931e476..41f80f03 100644 --- a/src/dyn_unix.c +++ b/src/dyn_unix.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -38,51 +38,54 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "config.h" #include #include -#if defined(HAVE_DLFCN_H) && !defined(HAVE_DL_H) && !defined(__APPLE__) +#ifndef __APPLE__ #include #include +#include #include "misc.h" #include "pcsclite.h" #include "debuglog.h" #include "dyn_generic.h" -INTERNAL LONG DYN_LoadLibrary(void **pvLHandle, char *pcLibrary) +INTERNAL void * DYN_LoadLibrary(const char *pcLibrary) { - *pvLHandle = NULL; + void *pvLHandle = NULL; #ifndef PCSCLITE_STATIC_DRIVER - *pvLHandle = dlopen(pcLibrary, RTLD_LAZY); + pvLHandle = dlopen(pcLibrary, RTLD_LAZY); - if (*pvLHandle == NULL) + if (pvLHandle == NULL) { Log3(PCSC_LOG_CRITICAL, "%s: %s", pcLibrary, dlerror()); - return SCARD_F_UNKNOWN_ERROR; } +#else + (void)pcLibrary; #endif - return SCARD_S_SUCCESS; + return pvLHandle; } -INTERNAL LONG DYN_CloseLibrary(void **pvLHandle) +INTERNAL LONG DYN_CloseLibrary(void *pvLHandle) { #ifndef PCSCLITE_STATIC_DRIVER int ret; - ret = dlclose(*pvLHandle); - *pvLHandle = NULL; + ret = dlclose(pvLHandle); if (ret) { Log2(PCSC_LOG_CRITICAL, "%s", dlerror()); return SCARD_F_UNKNOWN_ERROR; } +#else + (void)pvLHandle; #endif return SCARD_S_SUCCESS; } INTERNAL LONG DYN_GetAddress(void *pvLHandle, void **pvFHandle, - const char *pcFunction, int mayfail) + const char *pcFunction, bool mayfail) { char pcFunctionName[256]; LONG rv = SCARD_S_SUCCESS; @@ -107,9 +110,13 @@ INTERNAL LONG DYN_GetAddress(void *pvLHandle, void **pvFHandle, pcFunction, dlerror()); rv = SCARD_F_UNKNOWN_ERROR; } +#else + (void)pvLHandle; + (void)pvFHandle; + (void)mayfail; #endif return rv; } -#endif /* HAVE_DLFCN_H && !HAVE_DL_H && !__APPLE__ */ +#endif /* !__APPLE__ */ diff --git a/src/error.c b/src/error.c index 498445bf..155bbee7 100644 --- a/src/error.c +++ b/src/error.c @@ -3,10 +3,10 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2006-2009 + * Copyright (C) 2006-2024 * Ludovic Rousseau * - * This file is dual licenced: + * This file is dual licensed: * - BSD-like, see the COPYING file * - GNU Lesser General Licence 2.1 or (at your option) any later version. * @@ -189,7 +189,7 @@ PCSC_API const char* pcsc_stringify_error(const LONG pcscError) /* case SCARD_E_WRITE_TOO_MANY: */ /* case SCARD_E_BAD_SEEK: */ /* case SCARD_E_INVALID_CHV: */ - /* case SCARD_E_UNKNOWN_RES_MNG: */ + /* case SCARD_E_UNKNOWN_RES_MSG: */ /* case SCARD_E_NO_SUCH_CERTIFICATE: */ /* case SCARD_E_CERTIFICATE_UNAVAILABLE: */ case SCARD_E_NO_READERS_AVAILABLE: diff --git a/src/eventhandler.c b/src/eventhandler.c index e64b1d52..c3fdabf8 100644 --- a/src/eventhandler.c +++ b/src/eventhandler.c @@ -3,7 +3,7 @@ * * Copyright (C) 2000-2002 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -77,7 +77,7 @@ LONG EHRegisterClientForEvent(int32_t filedes) } /* EHRegisterClientForEvent */ /** - * Try to unregisted a client + * Try to unregister a client * If no client is found then do not log an error */ LONG EHTryToUnregisterClientForEvent(int32_t filedes) @@ -179,14 +179,12 @@ void EHDestroyEventHandler(READER_CONTEXT * rContext) rv = IFDGetCapabilities(rContext, TAG_IFD_POLLING_THREAD_KILLABLE, &dwGetSize, ucGetData); -#ifdef HAVE_PTHREAD_CANCEL if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0]) { Log1(PCSC_LOG_INFO, "Killing polling thread"); (void)pthread_cancel(rContext->pthThread); } else -#endif { /* ask to stop the "polling" thread */ RESPONSECODE (*fct)(DWORD) = NULL; diff --git a/src/eventhandler.h b/src/eventhandler.h index 6a3ab041..48720c3f 100644 --- a/src/eventhandler.h +++ b/src/eventhandler.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -54,10 +54,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. char readerName[MAX_READERNAME]; /**< reader name */ uint32_t eventCounter; /**< number of card events */ uint32_t readerState; /**< SCARD_* bit field */ - int32_t readerSharing; /**< PCSCLITE_SHARING_* sharing status */ + _Atomic int32_t readerSharing; /**< PCSCLITE_SHARING_* sharing status */ UCHAR cardAtr[MAX_ATR_SIZE]; /**< ATR */ - uint32_t cardAtrLength; /**< ATR length */ + _Atomic uint32_t cardAtrLength; /**< ATR length */ uint32_t cardProtocol; /**< SCARD_PROTOCOL_* value */ } READER_STATE; diff --git a/src/strlcpycat.h b/src/g_defines.c similarity index 74% rename from src/strlcpycat.h rename to src/g_defines.c index 70407fdd..82de8007 100644 --- a/src/strlcpycat.h +++ b/src/g_defines.c @@ -1,7 +1,7 @@ /* * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) * - * Copyright (C) 2004-2010 + * Copyright (C) 2024 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -28,18 +28,12 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** - * @file - * @brief prototypes of strlcpy()/strlcat() imported from OpenBSD - */ - -#ifdef HAVE_STRLCPY -#include -#else -size_t strlcpy(char *dst, const char *src, size_t siz); -#endif - -#ifndef HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t siz); -#endif +#include "misc.h" +#include +/** Protocol Control Information for T=0 */ +PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) }; +/** Protocol Control Information for T=1 */ +PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) }; +/** Protocol Control Information for raw access */ +PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, sizeof(SCARD_IO_REQUEST) }; diff --git a/src/hotplug.h b/src/hotplug.h index 2d850f82..cff722a0 100644 --- a/src/hotplug.h +++ b/src/hotplug.h @@ -3,7 +3,7 @@ * * Copyright (C) 2000-2003 * David Corcoran - * Copyright (C) 2002-2009 + * Copyright (C) 2002-2022 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -53,8 +53,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define PCSCLITE_HP_BASE_PORT 0x200000 - LONG HPSearchHotPluggables(void); - ULONG HPRegisterForHotplugEvents(void); + LONG HPSearchHotPluggables(const char * hpDirPath); + ULONG HPRegisterForHotplugEvents(const char * hpDirPath); LONG HPStopHotPluggables(void); void HPReCheckSerialReaders(void); diff --git a/src/hotplug_generic.c b/src/hotplug_generic.c index 12a96ed1..d585080b 100644 --- a/src/hotplug_generic.c +++ b/src/hotplug_generic.c @@ -3,7 +3,7 @@ * * Copyright (C) 2000-2003 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2025 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -42,16 +42,23 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "config.h" #include "hotplug.h" +#include "debuglog.h" #if !defined(__APPLE__) && !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUDEV) -LONG HPSearchHotPluggables(void) +LONG HPSearchHotPluggables(const char * hpDirPath) { + (void)hpDirPath; + return 0; } -ULONG HPRegisterForHotplugEvents(void) +ULONG HPRegisterForHotplugEvents(const char * hpDirPath) { + (void)hpDirPath; + + Log1(PCSC_LOG_INFO, "Using fake hotplug"); + return 0; } diff --git a/src/hotplug_libudev.c b/src/hotplug_libudev.c index ec83b8f4..04bf5d23 100644 --- a/src/hotplug_libudev.c +++ b/src/hotplug_libudev.c @@ -1,7 +1,7 @@ /* * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) * - * Copyright (C) 2011 + * Copyright (C) 2011-2026 * Ludovic Rousseau * Copyright (C) 2014 * Stefani Seibold @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** * @file - * @brief This provides a search API for hot plugable devices using libudev + * @brief This provides a search API for hot pluggable devices using libudev */ #include "config.h" @@ -47,6 +47,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "debuglog.h" #include "parser.h" @@ -66,15 +67,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #undef DEBUG_HOTPLUG -#define FALSE 0 -#define TRUE 1 - -extern char Add_Interface_In_Name; -extern char Add_Serial_In_Name; +extern bool Add_Interface_In_Name; +extern bool Add_Serial_In_Name; static pthread_t usbNotifyThread; static int driverSize = -1; static struct udev *Udev; +static struct udev_monitor *Udev_monitor; /** @@ -107,7 +106,7 @@ static struct _readerTracker } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS]; -static LONG HPReadBundleValues(void) +static LONG HPReadBundleValues(const char * hpDirPath) { LONG rv; DIR *hpDir; @@ -116,13 +115,13 @@ static LONG HPReadBundleValues(void) char fullLibPath[FILENAME_MAX]; int listCount = 0; - hpDir = opendir(PCSCLITE_HP_DROPDIR); + hpDir = opendir(hpDirPath); if (NULL == hpDir) { - Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR); + Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s", hpDirPath); Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd."); - return -1; + return 0; } /* allocate a first array */ @@ -159,7 +158,7 @@ static LONG HPReadBundleValues(void) * vendor and product ID's for this particular bundle */ (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist", - PCSCLITE_HP_DROPDIR, currFP->d_name); + hpDirPath, currFP->d_name); fullPath[sizeof(fullPath) - 1] = '\0'; rv = bundleParse(fullPath, &plist); @@ -171,7 +170,7 @@ static LONG HPReadBundleValues(void) libraryPath = list_get_at(values, 0); (void)snprintf(fullLibPath, sizeof(fullLibPath), "%s/%s/Contents/%s/%s", - PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, + hpDirPath, currFP->d_name, PCSC_ARCH, libraryPath); fullLibPath[sizeof(fullLibPath) - 1] = '\0'; @@ -193,7 +192,7 @@ static LONG HPReadBundleValues(void) if (rv) CFBundleName = NULL; else - CFBundleName = strdup(list_get_at(values, 0)); + CFBundleName = list_get_at(values, 0); /* while we find a nth ifdVendorID in Info.plist */ for (alias=0; aliasd_name); driverTracker[listCount].libraryPath = strdup(fullLibPath); - driverTracker[listCount].CFBundleName = CFBundleName; + driverTracker[listCount].CFBundleName = CFBundleName ? strdup(CFBundleName) : NULL; #ifdef DEBUG_HOTPLUG Log2(PCSC_LOG_INFO, "Found driver for: %s", @@ -374,6 +373,7 @@ static void HPAddDevice(struct udev_device *dev) const char *devpath; struct udev_device *parent; const char *sysname; + const char *ignoreprop; /* The device pointed to by dev contains information about the interface. In order to get information about the USB @@ -388,7 +388,7 @@ static void HPAddDevice(struct udev_device *dev) devpath = udev_device_get_devnode(parent); if (!devpath) { - /* the device disapeared? */ + /* the device disappeared? */ Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed"); return; } @@ -411,6 +411,15 @@ static void HPAddDevice(struct udev_device *dev) return; } + ignoreprop = udev_device_get_property_value(parent, "PCSCLITE_IGNORE"); + if (ignoreprop && !strcmp(ignoreprop, "1")) + { + Log4(PCSC_LOG_ERROR, + "Device %s at %s (%s) has PCSCLITE_IGNORE set: ignored", + driver->readerName, devpath, sysname); + return; + } + /* check for duplicated add */ for (index=0; index - * Copyright (C) 2003-2011 + * Copyright (C) 2003-2026 * Ludovic Rousseau * Copyright (C) 2003 * Toni Andjelkovic @@ -55,6 +55,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "misc.h" #include "wintypes.h" @@ -76,11 +77,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define READER_PRESENT 1 #define READER_FAILED 2 -#define FALSE 0 -#define TRUE 1 - -extern char Add_Interface_In_Name; -extern char Add_Serial_In_Name; +extern bool Add_Interface_In_Name; +extern bool Add_Serial_In_Name; /* we use the default libusb context */ #define ctx NULL @@ -89,7 +87,7 @@ pthread_mutex_t usbNotifierMutex; static pthread_t usbNotifyThread; static int driverSize = -1; -static char AraKiriHotPlug = FALSE; +static bool AraKiriHotPlug = false; static int rescan_pipe[] = { -1, -1 }; extern int HPForceReaderPolling; @@ -131,7 +129,7 @@ static LONG HPAddHotPluggable(struct libusb_device *dev, static LONG HPRemoveHotPluggable(int reader_index); static void HPCleanupHotPluggable(int reader_index); -static LONG HPReadBundleValues(void) +static LONG HPReadBundleValues(const char * hpDirPath) { LONG rv; DIR *hpDir; @@ -140,13 +138,14 @@ static LONG HPReadBundleValues(void) char fullLibPath[FILENAME_MAX]; int listCount = 0; - hpDir = opendir(PCSCLITE_HP_DROPDIR); + hpDir = opendir(hpDirPath); if (hpDir == NULL) { - Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR); + Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s", + hpDirPath); Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd."); - return -1; + return 0; } /* allocate a first array */ @@ -183,7 +182,7 @@ static LONG HPReadBundleValues(void) * vendor and product ID's for this particular bundle */ snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist", - PCSCLITE_HP_DROPDIR, currFP->d_name); + hpDirPath, currFP->d_name); fullPath[sizeof(fullPath) - 1] = '\0'; rv = bundleParse(fullPath, &plist); @@ -195,7 +194,7 @@ static LONG HPReadBundleValues(void) libraryPath = list_get_at(values, 0); (void)snprintf(fullLibPath, sizeof(fullLibPath), "%s/%s/Contents/%s/%s", - PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH, + hpDirPath, currFP->d_name, PCSC_ARCH, libraryPath); fullLibPath[sizeof(fullLibPath) - 1] = '\0'; @@ -285,7 +284,8 @@ static LONG HPReadBundleValues(void) if (driverSize == 0) { - Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR); + Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s", + hpDirPath); Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd"); } #ifdef DEBUG_HOTPLUG @@ -342,7 +342,7 @@ static void HPRescanUsbBus(void) ssize_t cnt; for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) - /* clear rollcall */ + /* clear roll call */ readerTracker[i].status = READER_ABSENT; cnt = libusb_get_device_list(ctx, &devs); @@ -401,13 +401,13 @@ static void HPRescanUsbBus(void) for (interface = 0; interface < config_desc->bNumInterfaces; interface++) { - int newreader; + bool newreader; /* A known device has been found */ snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d:%d", bus_number, device_address, interface); bus_device[BUS_DEVICE_STRSIZE - 1] = '\0'; - newreader = TRUE; + newreader = true; /* Check if the reader is a new one */ for (j=0; j 0) { + if (AraKiriHotPlug) + break; Log1(PCSC_LOG_INFO, "Reload serial configuration"); HPRescanUsbBus(); #ifdef USE_SERIAL @@ -546,18 +517,39 @@ static void * HPEstablishUSBNotifications(int pipefd[2]) #endif Log1(PCSC_LOG_INFO, "End reload serial configuration"); } - close(rescan_pipe[0]); - rescan_pipe[0] = -1; } + libusb_exit(ctx); + + for (int i=0; i 0) + if (HPReadBundleValues(hpDirPath) > 0) { + /* used for waiting for the initialization completion */ int pipefd[2]; char c; @@ -576,7 +569,14 @@ LONG HPSearchHotPluggables(void) return -1; } - ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED, + /* used for rescan events */ + if (pipe(rescan_pipe) == -1) + { + Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno)); + return -1; + } + + ThreadCreate(&usbNotifyThread, 0, (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd); /* Wait for initial readers to setup */ @@ -584,7 +584,7 @@ LONG HPSearchHotPluggables(void) { Log2(PCSC_LOG_ERROR, "read: %s", strerror(errno)); return -1; - }; + } /* cleanup pipe fd */ close(pipefd[0]); @@ -596,12 +596,18 @@ LONG HPSearchHotPluggables(void) LONG HPStopHotPluggables(void) { - AraKiriHotPlug = TRUE; + /* tell the rescan thread to shut down; it checks the ara kiri flag, but it + * might also need to be awaken from reading the rescan pipe */ + AraKiriHotPlug = true; + HPReCheckSerialReaders(); + if (rescan_pipe[1] >= 0) { close(rescan_pipe[1]); rescan_pipe[1] = -1; } + /* wait for the rescan thread to complete its cleanup */ + pthread_join(usbNotifyThread, NULL); return 0; } @@ -796,8 +802,10 @@ static void HPCleanupHotPluggable(int reader_index) /** * Sets up callbacks for device hotplug events. */ -ULONG HPRegisterForHotplugEvents(void) +ULONG HPRegisterForHotplugEvents(const char * hpDirPath) { + (void)hpDirPath; + (void)pthread_mutex_init(&usbNotifierMutex, NULL); return 0; } diff --git a/src/hotplug_macosx.c b/src/hotplug_macosx.c index 38155515..16253c66 100644 --- a/src/hotplug_macosx.c +++ b/src/hotplug_macosx.c @@ -3,7 +3,7 @@ * * Copyright (C) 2002-2004 * Stephen M. Webb - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2023 * Ludovic Rousseau * Copyright (C) 2002 * David Corcoran @@ -97,13 +97,12 @@ static HPDriver *Drivers = NULL; */ static void HPDeviceAppeared(void *refCon, io_iterator_t iterator) { - kern_return_t kret; io_service_t obj; (void)refCon; while ((obj = IOIteratorNext(iterator))) - kret = IOObjectRelease(obj); + IOObjectRelease(obj); HPScan(); } @@ -114,13 +113,12 @@ static void HPDeviceAppeared(void *refCon, io_iterator_t iterator) */ static void HPDeviceDisappeared(void *refCon, io_iterator_t iterator) { - kern_return_t kret; io_service_t obj; (void)refCon; while ((obj = IOIteratorNext(iterator))) - kret = IOObjectRelease(obj); + IOObjectRelease(obj); HPScan(); } @@ -160,12 +158,12 @@ static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath) } bundleArray = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault, pluginUrl, NULL); + CFRelease(pluginUrl); if (!bundleArray) { Log1(PCSC_LOG_ERROR, "error getting plugin directory bundles"); return NULL; } - CFRelease(pluginUrl); size_t bundleArraySize = CFArrayGetCount(bundleArray); size_t i; @@ -183,6 +181,7 @@ static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath) if (!blobValue) { Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle"); + CFRelease(bundleArray); return NULL; } @@ -209,6 +208,7 @@ static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath) if (!bundleVector) { Log1(PCSC_LOG_ERROR, "memory allocation failure"); + CFRelease(bundleArray); return NULL; } @@ -221,9 +221,11 @@ static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath) CFURLRef bundleUrl = CFBundleCopyBundleURL(currBundle); CFStringRef bundlePath = CFURLCopyPath(bundleUrl); + CFRelease(bundleUrl); driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath, CFStringGetSystemEncoding())); + CFRelease(bundlePath); const void * blobValue = CFDictionaryGetValue(dict, CFSTR(PCSCLITE_HP_MANUKEY_NAME)); @@ -231,6 +233,7 @@ static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath) if (!blobValue) { Log1(PCSC_LOG_ERROR, "error getting vendor ID from bundle"); + CFRelease(bundleArray); return bundleVector; } @@ -250,6 +253,7 @@ static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath) if (!productArray) { Log1(PCSC_LOG_ERROR, "error getting product ID from bundle"); + CFRelease(bundleArray); return bundleVector; } @@ -259,53 +263,49 @@ static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath) if (!friendlyNameArray) { Log1(PCSC_LOG_ERROR, "error getting product ID from bundle"); + CFRelease(bundleArray); return bundleVector; } - int reader_nb = CFArrayGetCount(vendorArray); + long reader_nb = CFArrayGetCount(vendorArray); if (reader_nb != CFArrayGetCount(productArray)) { Log3(PCSC_LOG_ERROR, - "Malformed Info.plist: %d vendors and %ld products", + "Malformed Info.plist: %ld vendors and %ld products", reader_nb, CFArrayGetCount(productArray)); + CFRelease(bundleArray); return bundleVector; } if (reader_nb != CFArrayGetCount(friendlyNameArray)) { Log3(PCSC_LOG_ERROR, - "Malformed Info.plist: %d vendors and %ld friendlynames", + "Malformed Info.plist: %ld vendors and %ld friendlynames", reader_nb, CFArrayGetCount(friendlyNameArray)); + CFRelease(bundleArray); return bundleVector; } int j; for (j=0; jm_vendorId = strtoul(CFStringGetCStringPtr(strValue, - CFStringGetSystemEncoding()), NULL, 16); + CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer, + kCFStringEncodingUTF8); + driverBundle->m_vendorId = (unsigned int)strtoul(stringBuffer, NULL, 16); strValue = CFArrayGetValueAtIndex(productArray, j); - driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue, - CFStringGetSystemEncoding()), NULL, 16); + CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer, + kCFStringEncodingUTF8); + driverBundle->m_productId = (unsigned int)strtoul(stringBuffer, NULL, 16); strValue = CFArrayGetValueAtIndex(friendlyNameArray, j); - const char *cstr = CFStringGetCStringPtr(strValue, - CFStringGetSystemEncoding()); - if (NULL == cstr) - { - char utf8_str[200]; - if (CFStringGetCString(strValue, utf8_str, sizeof utf8_str, - kCFStringEncodingUTF8)) - driverBundle->m_friendlyName = strdup(utf8_str); - else - continue; - } - else - driverBundle->m_friendlyName = strdup(cstr); + CFStringGetCString(strValue, stringBuffer, sizeof stringBuffer, + kCFStringEncodingUTF8); + driverBundle->m_friendlyName = strdup(stringBuffer); if (!driverBundle->m_libPath) driverBundle->m_libPath = strdup(libPath); @@ -326,49 +326,7 @@ static HPDriverVector HPDriversGetFromDirectory(const char *driverBundlePath) } else { - CFStringRef strValue = blobValue; - -#ifdef DEBUG_HOTPLUG - Log3(PCSC_LOG_DEBUG, "Driver without alias: %s %s", - driverBundle->m_friendlyName, driverBundle->m_libPath); -#endif - - driverBundle->m_vendorId = strtoul(CFStringGetCStringPtr(strValue, - CFStringGetSystemEncoding()), NULL, 16); - - strValue = (CFStringRef) CFDictionaryGetValue(dict, - CFSTR(PCSCLITE_HP_PRODKEY_NAME)); - if (!strValue) - { - Log1(PCSC_LOG_ERROR, "error getting product ID from bundle"); - return bundleVector; - } - driverBundle->m_productId = strtoul(CFStringGetCStringPtr(strValue, - CFStringGetSystemEncoding()), NULL, 16); - - strValue = (CFStringRef) CFDictionaryGetValue(dict, - CFSTR(PCSCLITE_HP_NAMEKEY_NAME)); - if (!strValue) - { - Log1(PCSC_LOG_ERROR, "error getting product friendly name from bundle"); - driverBundle->m_friendlyName = strdup("unnamed device"); - } - else - { - const char *cstr = CFStringGetCStringPtr(strValue, - CFStringGetSystemEncoding()); - - driverBundle->m_friendlyName = strdup(cstr); - } -#ifdef DEBUG_HOTPLUG - Log2(PCSC_LOG_DEBUG, "VendorID: 0x%04X", driverBundle->m_vendorId); - Log2(PCSC_LOG_DEBUG, "ProductID: 0x%04X", driverBundle->m_productId); - Log2(PCSC_LOG_DEBUG, "Friendly name: %s", driverBundle->m_friendlyName); - Log2(PCSC_LOG_DEBUG, "Driver: %s", driverBundle->m_libPath); -#endif - - /* go to next bundle in the vector */ - driverBundle++; + Log1(PCSC_LOG_ERROR, "Non array not supported"); } } CFRelease(bundleArray); @@ -468,7 +426,7 @@ HPDriversMatchUSBDevices(HPDriverVector driverBundle, } io_iterator_t usbIter; - kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault, + kern_return_t kret = IOServiceGetMatchingServices(kIOMainPortDefault, usbMatch, &usbIter); if (kret != 0) @@ -571,7 +529,7 @@ HPDriversMatchPCCardDevices(HPDriver * driverBundle, io_iterator_t pccIter; kern_return_t kret = - IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch, + IOServiceGetMatchingServices(kIOMainPortDefault, pccMatch, &pccIter); if (kret != 0) { @@ -608,6 +566,7 @@ HPDriversMatchPCCardDevices(HPDriver * driverBundle, { CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type, &vendorId); + CFRelease(valueRef); } valueRef = IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"), @@ -620,6 +579,7 @@ HPDriversMatchPCCardDevices(HPDriver * driverBundle, { CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type, &productId); + CFRelease(valueRef); } valueRef = IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"), @@ -632,6 +592,7 @@ HPDriversMatchPCCardDevices(HPDriver * driverBundle, { CFNumberGetValue((CFNumberRef) valueRef, kCFNumberSInt32Type, &pccAddress); + CFRelease(valueRef); } HPDriver *driver = driverBundle; @@ -658,7 +619,7 @@ static void HPEstablishUSBNotification(void) IONotificationPortRef notificationPort; IOReturn kret; - notificationPort = IONotificationPortCreate(kIOMasterPortDefault); + notificationPort = IONotificationPortCreate(kIOMainPortDefault); CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notificationPort), kCFRunLoopDefaultMode); @@ -667,6 +628,7 @@ static void HPEstablishUSBNotification(void) if (!matchingDictionary) { Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed"); + return; } matchingDictionary = (CFMutableDictionaryRef) CFRetain(matchingDictionary); @@ -701,7 +663,7 @@ static void HPEstablishPCCardNotification(void) IONotificationPortRef notificationPort; IOReturn kret; - notificationPort = IONotificationPortCreate(kIOMasterPortDefault); + notificationPort = IONotificationPortCreate(kIOMainPortDefault); CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notificationPort), kCFRunLoopDefaultMode); @@ -710,6 +672,7 @@ static void HPEstablishPCCardNotification(void) if (!matchingDictionary) { Log1(PCSC_LOG_ERROR, "IOServiceMatching() failed"); + return; } matchingDictionary = (CFMutableDictionaryRef) CFRetain(matchingDictionary); @@ -751,9 +714,9 @@ static void HPDeviceNotificationThread(void) * matching devices. * Adds or removes matching readers as necessary. */ -LONG HPSearchHotPluggables(void) +LONG HPSearchHotPluggables(const char * hpDirPath) { - Drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR); + Drivers = HPDriversGetFromDirectory(hpDirPath); if (!Drivers) return 1; @@ -766,23 +729,33 @@ static int HPScan(void) HPDeviceList devices = NULL; if (HPDriversMatchUSBDevices(Drivers, &devices)) + { + if (devices) + free(devices); + return -1; + } if (HPDriversMatchPCCardDevices(Drivers, &devices)) + { + if (devices) + free(devices); + return -1; + } HPDevice *a; for (a = devices; a; a = a->m_next) { - int found = FALSE; + bool found = false; HPDevice *b; for (b = sDeviceList; b; b = b->m_next) { if (HPDeviceEquals(a, b)) { - found = TRUE; + found = true; break; } } @@ -803,14 +776,14 @@ static int HPScan(void) for (a = sDeviceList; a; a = a->m_next) { - int found = FALSE; + bool found = false; HPDevice *b; for (b = devices; b; b = b->m_next) { if (HPDeviceEquals(a, b)) { - found = TRUE; + found = true; break; } } @@ -834,8 +807,10 @@ pthread_t sHotplugWatcherThread; /* * Sets up callbacks for device hotplug events. */ -ULONG HPRegisterForHotplugEvents(void) +ULONG HPRegisterForHotplugEvents(const char * hpDirPath) { + (void)hpDirPath; + ThreadCreate(&sHotplugWatcherThread, THREAD_ATTR_DEFAULT, (PCSCLITE_THREAD_FUNCTION( )) HPDeviceNotificationThread, NULL); diff --git a/src/ifdwrapper.c b/src/ifdwrapper.c index 8cecc466..31a6f440 100644 --- a/src/ifdwrapper.c +++ b/src/ifdwrapper.c @@ -5,7 +5,7 @@ * David Corcoran * Copyright (C) 2003-2004 * Damien Sauveron - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -164,6 +164,7 @@ RESPONSECODE IFDCloseIFD(READER_CONTEXT * rContext) { RESPONSECODE rv; int repeat; + bool do_unlock = true; #ifndef PCSCLITE_STATIC_DRIVER RESPONSECODE(*IFDH_close_channel) (DWORD) = NULL; @@ -184,6 +185,9 @@ RESPONSECODE IFDCloseIFD(READER_CONTEXT * rContext) (void)SYS_USleep(100*1000); /* 100 ms */ goto again; } + else + /* locking failed but we need to close the IFD */ + do_unlock = false; } #ifndef PCSCLITE_STATIC_DRIVER @@ -193,7 +197,8 @@ RESPONSECODE IFDCloseIFD(READER_CONTEXT * rContext) #endif /* END OF LOCKED REGION */ - (void)pthread_mutex_unlock(rContext->mMutex); + if (do_unlock) + (void)pthread_mutex_unlock(rContext->mMutex); return rv; } @@ -228,7 +233,7 @@ RESPONSECODE IFDSetCapabilities(READER_CONTEXT * rContext, DWORD dwTag, } /** - * Get's capabilities in the reader. + * Gets capabilities in the reader. * Other functions int this file will call * the driver directly to not cause a deadlock. */ diff --git a/src/ifdwrapper.h b/src/ifdwrapper.h index e7b1fe49..e1421a7c 100644 --- a/src/ifdwrapper.h +++ b/src/ifdwrapper.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2004 * David Corcoran - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2021 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/lassert.h b/src/lassert.h index c4e85c37..5fbdbcb6 100644 --- a/src/lassert.h +++ b/src/lassert.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2007 * Jacob Berkman - * Copyright (C) 2008 + * Copyright (C) 2008-2014 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/libfake.c b/src/libfake.c new file mode 100644 index 00000000..b35a835b --- /dev/null +++ b/src/libfake.c @@ -0,0 +1,241 @@ +/* + * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) + * + * Copyright (C) 2024 + * Ludovic Rousseau + * +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief Fake PC/SC library (example code) + */ + +/* define PCSC_API used in winscard.h */ +#include "misc.h" +#include "winscard.h" + +LONG SCardEstablishContext(DWORD dwScope, + LPCVOID pvReserved1, LPCVOID pvReserved2, + LPSCARDCONTEXT phContext) +{ + (void)dwScope; + (void)pvReserved1; + (void)pvReserved2; + (void)phContext; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardReleaseContext(SCARDCONTEXT hContext) +{ + (void)hContext; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardIsValidContext(SCARDCONTEXT hContext) +{ + (void)hContext; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardConnect(SCARDCONTEXT hContext, + LPCSTR szReader, + DWORD dwShareMode, + DWORD dwPreferredProtocols, + LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol) +{ + (void)hContext; + (void)szReader; + (void)dwShareMode; + (void)dwPreferredProtocols; + (void)phCard; + (void)pdwActiveProtocol; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardReconnect(SCARDHANDLE hCard, + DWORD dwShareMode, + DWORD dwPreferredProtocols, + DWORD dwInitialization, LPDWORD pdwActiveProtocol) +{ + (void)hCard; + (void)dwShareMode; + (void)dwPreferredProtocols; + (void)dwInitialization; + (void)pdwActiveProtocol; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) +{ + (void)hCard; + (void)dwDisposition; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardBeginTransaction(SCARDHANDLE hCard) +{ + (void)hCard; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition) +{ + (void)hCard; + (void)dwDisposition; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardStatus(SCARDHANDLE hCard, + LPSTR mszReaderName, + LPDWORD pcchReaderLen, + LPDWORD pdwState, + LPDWORD pdwProtocol, + LPBYTE pbAtr, + LPDWORD pcbAtrLen) +{ + (void)hCard; + (void)mszReaderName; + (void)pcchReaderLen; + (void)pdwState; + (void)pdwProtocol; + (void)pbAtr; + (void)pcbAtrLen; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardGetStatusChange(SCARDCONTEXT hContext, + DWORD dwTimeout, + SCARD_READERSTATE *rgReaderStates, DWORD cReaders) +{ + (void)hContext; + (void)dwTimeout; + (void)rgReaderStates; + (void)cReaders; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, + LPCVOID pbSendBuffer, DWORD cbSendLength, + LPVOID pbRecvBuffer, DWORD cbRecvLength, + LPDWORD lpBytesReturned) +{ + (void)hCard; + (void)dwControlCode; + (void)pbSendBuffer; + (void)cbSendLength; + (void)pbRecvBuffer; + (void)cbRecvLength; + (void)lpBytesReturned; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardTransmit(SCARDHANDLE hCard, + const SCARD_IO_REQUEST *pioSendPci, + LPCBYTE pbSendBuffer, DWORD cbSendLength, + SCARD_IO_REQUEST *pioRecvPci, + LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength) +{ + (void)hCard; + (void)pioSendPci; + (void)pbSendBuffer; + (void)cbSendLength; + (void)pioRecvPci; + (void)pbRecvBuffer; + (void)pcbRecvLength; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardListReaderGroups(SCARDCONTEXT hContext, + LPSTR mszGroups, LPDWORD pcchGroups) +{ + (void)hContext; + (void)mszGroups; + (void)pcchGroups; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardListReaders(SCARDCONTEXT hContext, + LPCSTR mszGroups, + LPSTR mszReaders, + LPDWORD pcchReaders) +{ + (void)hContext; + (void)mszGroups; + (void)mszReaders; + (void)pcchReaders; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem) +{ + (void)hContext; + (void)pvMem; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardCancel(SCARDCONTEXT hContext) +{ + (void)hContext; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, +LPBYTE pbAttr, LPDWORD pcbAttrLen) +{ + (void)hCard; + (void)dwAttrId; + (void)pbAttr; + (void)pcbAttrLen; + + return SCARD_F_INTERNAL_ERROR; +} + +LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, + LPCBYTE pbAttr, DWORD cbAttrLen) +{ + (void)hCard; + (void)dwAttrId; + (void)pbAttr; + (void)cbAttrLen; + + return SCARD_F_INTERNAL_ERROR; +} diff --git a/src/libredirect.c b/src/libredirect.c new file mode 100644 index 00000000..d6d19f06 --- /dev/null +++ b/src/libredirect.c @@ -0,0 +1,322 @@ +/* + * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) + * + * Copyright (C) 2024 + * Ludovic Rousseau + * +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief Redirect PC/SC calls to the delegate library + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "misc.h" +#include +#include "sys_generic.h" + +#define DEBUG + +#define DLSYM_DECLARE(symbol) \ + typeof(symbol)* symbol +#define DLSYM_SET_VALUE(symbol) \ + .symbol = (typeof(symbol)(*))internal_error + +/* fake function to just return en error code */ +static LONG internal_error(void) +{ + return SCARD_F_INTERNAL_ERROR; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +/* contains pointers to real functions */ +static struct +{ + DLSYM_DECLARE(SCardEstablishContext); + DLSYM_DECLARE(SCardReleaseContext); + DLSYM_DECLARE(SCardIsValidContext); + DLSYM_DECLARE(SCardConnect); + DLSYM_DECLARE(SCardReconnect); + DLSYM_DECLARE(SCardDisconnect); + DLSYM_DECLARE(SCardBeginTransaction); + DLSYM_DECLARE(SCardEndTransaction); + DLSYM_DECLARE(SCardStatus); + DLSYM_DECLARE(SCardGetStatusChange); + DLSYM_DECLARE(SCardControl); + DLSYM_DECLARE(SCardTransmit); + DLSYM_DECLARE(SCardListReaderGroups); + DLSYM_DECLARE(SCardListReaders); + DLSYM_DECLARE(SCardFreeMemory); + DLSYM_DECLARE(SCardCancel); + DLSYM_DECLARE(SCardGetAttrib); + DLSYM_DECLARE(SCardSetAttrib); +} redirect = { + /* initialized with the fake internal_error() function */ + DLSYM_SET_VALUE(SCardEstablishContext), + DLSYM_SET_VALUE(SCardReleaseContext), + DLSYM_SET_VALUE(SCardIsValidContext), + DLSYM_SET_VALUE(SCardConnect), + DLSYM_SET_VALUE(SCardReconnect), + DLSYM_SET_VALUE(SCardDisconnect), + DLSYM_SET_VALUE(SCardBeginTransaction), + DLSYM_SET_VALUE(SCardEndTransaction), + DLSYM_SET_VALUE(SCardStatus), + DLSYM_SET_VALUE(SCardGetStatusChange), + DLSYM_SET_VALUE(SCardControl), + DLSYM_SET_VALUE(SCardTransmit), + DLSYM_SET_VALUE(SCardListReaderGroups), + DLSYM_SET_VALUE(SCardListReaders), + DLSYM_SET_VALUE(SCardFreeMemory), + DLSYM_SET_VALUE(SCardCancel), + DLSYM_SET_VALUE(SCardGetAttrib), + DLSYM_SET_VALUE(SCardSetAttrib) +}; +#pragma GCC diagnostic pop + +static void *Lib_handle = NULL; + +#ifdef DEBUG +static void log_line(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); +} +#else +static void log_line(const char *fmt, ...) +{ +} +#endif + +static void load_lib(void) +{ +#define LIBPCSC "libpcsclite_real.so.1" + + const char *lib; + + lib = SYS_GetEnv("LIBPCSCLITE_DELEGATE"); + if (NULL == lib) + lib = LIBPCSC; + + /* load the real library */ + Lib_handle = dlopen(lib, RTLD_LAZY); + if (NULL == Lib_handle) + { + log_line("loading \"%s\" failed: %s", lib, dlerror()); + return; + } + +#define get_symbol(s) do { redirect.s = dlsym(Lib_handle, #s); if (NULL == redirect.s) { log_line("%s", dlerror()); return; } } while (0) + + if (SCardEstablishContext == dlsym(Lib_handle, "SCardEstablishContext")) + { + log_line("Symbols dlsym error"); + return; + } + + get_symbol(SCardEstablishContext); + get_symbol(SCardReleaseContext); + get_symbol(SCardIsValidContext); + get_symbol(SCardConnect); + get_symbol(SCardReconnect); + get_symbol(SCardDisconnect); + get_symbol(SCardBeginTransaction); + get_symbol(SCardEndTransaction); + get_symbol(SCardStatus); + get_symbol(SCardGetStatusChange); + get_symbol(SCardControl); + get_symbol(SCardTransmit); + get_symbol(SCardListReaderGroups); + get_symbol(SCardListReaders); + get_symbol(SCardFreeMemory); + get_symbol(SCardCancel); + get_symbol(SCardGetAttrib); + get_symbol(SCardSetAttrib); +} + +/* exported functions */ +PCSC_API LONG SCardEstablishContext(DWORD dwScope, + LPCVOID pvReserved1, + LPCVOID pvReserved2, + LPSCARDCONTEXT phContext) +{ + static pthread_once_t once_control = PTHREAD_ONCE_INIT; + + pthread_once(&once_control, load_lib); + + return redirect.SCardEstablishContext(dwScope, pvReserved1, pvReserved2, + phContext); +} + +PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext) +{ + return redirect.SCardReleaseContext(hContext); +} + +PCSC_API LONG SCardIsValidContext(SCARDCONTEXT hContext) +{ + return redirect.SCardIsValidContext(hContext); +} + +PCSC_API LONG SCardConnect(SCARDCONTEXT hContext, + LPCSTR szReader, + DWORD dwShareMode, + DWORD dwPreferredProtocols, + LPSCARDHANDLE phCard, + LPDWORD pdwActiveProtocol) +{ + return redirect.SCardConnect(hContext, szReader, dwShareMode, + dwPreferredProtocols, phCard, pdwActiveProtocol); +} + +PCSC_API LONG SCardReconnect(SCARDHANDLE hCard, + DWORD dwShareMode, + DWORD dwPreferredProtocols, + DWORD dwInitialization, + LPDWORD pdwActiveProtocol) +{ + return redirect.SCardReconnect(hCard, dwShareMode, dwPreferredProtocols, + dwInitialization, pdwActiveProtocol); +} + +PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard, + DWORD dwDisposition) +{ + return redirect.SCardDisconnect(hCard, dwDisposition); +} + +PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard) +{ + return redirect.SCardBeginTransaction(hCard); +} + +PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, + DWORD dwDisposition) +{ + return redirect.SCardEndTransaction(hCard, dwDisposition); +} + +PCSC_API LONG SCardStatus(SCARDHANDLE hCard, + LPSTR mszReaderName, + LPDWORD pcchReaderLen, + LPDWORD pdwState, + LPDWORD pdwProtocol, + LPBYTE pbAtr, + LPDWORD pcbAtrLen) +{ + return redirect.SCardStatus(hCard, mszReaderName, pcchReaderLen, pdwState, + pdwProtocol, pbAtr, pcbAtrLen); +} + +PCSC_API LONG SCardGetStatusChange(SCARDCONTEXT hContext, + DWORD dwTimeout, + SCARD_READERSTATE *rgReaderStates, + DWORD cReaders) +{ + return redirect.SCardGetStatusChange(hContext, dwTimeout, rgReaderStates, + cReaders); +} + +PCSC_API LONG SCardControl(SCARDHANDLE hCard, + DWORD dwControlCode, + LPCVOID pbSendBuffer, + DWORD cbSendLength, + LPVOID pbRecvBuffer, + DWORD cbRecvLength, + LPDWORD lpBytesReturned) +{ + return redirect.SCardControl(hCard, dwControlCode, pbSendBuffer, cbSendLength, + pbRecvBuffer, cbRecvLength, lpBytesReturned); +} + +PCSC_API LONG SCardTransmit(SCARDHANDLE hCard, + const SCARD_IO_REQUEST *pioSendPci, + LPCBYTE pbSendBuffer, + DWORD cbSendLength, + SCARD_IO_REQUEST *pioRecvPci, + LPBYTE pbRecvBuffer, + LPDWORD pcbRecvLength) +{ + return redirect.SCardTransmit(hCard, pioSendPci, pbSendBuffer, cbSendLength, + pioRecvPci, pbRecvBuffer, pcbRecvLength); +} + +PCSC_API LONG SCardListReaderGroups(SCARDCONTEXT hContext, + LPSTR mszGroups, + LPDWORD pcchGroups) +{ + return redirect.SCardListReaderGroups(hContext, mszGroups, pcchGroups); +} + +PCSC_API LONG SCardListReaders(SCARDCONTEXT hContext, + LPCSTR mszGroups, + LPSTR mszReaders, + LPDWORD pcchReaders) +{ + return redirect.SCardListReaders(hContext, mszGroups, mszReaders, pcchReaders); +} + +PCSC_API LONG SCardFreeMemory(SCARDCONTEXT hContext, + LPCVOID pvMem) +{ + return redirect.SCardFreeMemory(hContext, pvMem); +} + +PCSC_API LONG SCardCancel(SCARDCONTEXT hContext) +{ + return redirect.SCardCancel(hContext); +} + +PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard, + DWORD dwAttrId, + LPBYTE pbAttr, + LPDWORD pcbAttrLen) +{ + return redirect.SCardGetAttrib(hCard, dwAttrId, pbAttr, pcbAttrLen); +} + +PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, + DWORD dwAttrId, + LPCBYTE pbAttr, + DWORD cbAttrLen) +{ + return redirect.SCardSetAttrib(hCard, dwAttrId, pbAttr, cbAttrLen); +} + diff --git a/src/misc.h b/src/misc.h index ac35723c..22d46453 100644 --- a/src/misc.h +++ b/src/misc.h @@ -3,7 +3,7 @@ * * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) * - * Copyright (C) 2005-2010 + * Copyright (C) 2005-2019 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/parser.h b/src/parser.h index 1374b220..316e335a 100644 --- a/src/parser.h +++ b/src/parser.h @@ -3,7 +3,7 @@ * * Copyright (C) 2003 * Toni Andjelkovic - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2018 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/pcscd.h.in b/src/pcscd.h.in index 81c2988c..0c5ed3f1 100644 --- a/src/pcscd.h.in +++ b/src/pcscd.h.in @@ -44,7 +44,7 @@ #define PCSCLITE_CONFIG_DIR "@PCSCLITE_CONFIG_DIR@" -#define PCSCLITE_IPC_DIR USE_IPCDIR +#define PCSCLITE_IPC_DIR "@ipcdir@" #define PCSCLITE_RUN_PID PCSCLITE_IPC_DIR "/pcscd.pid" #define PCSCLITE_CSOCK_NAME PCSCLITE_IPC_DIR "/pcscd.comm" diff --git a/src/pcscdaemon.c b/src/pcscdaemon.c index 35649c31..990a5279 100644 --- a/src/pcscdaemon.c +++ b/src/pcscdaemon.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2002 * David Corcoran - * Copyright (C) 2002-2022 + * Copyright (C) 2002-2026 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -35,7 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief This is the main pcscd daemon. * * The function \c main() starts up the communication environment.\n - * Then an endless loop is calld to look for Client connections. For each + * Then an endless loop is called to look for Client connections. For each * Client connection a call to \c CreateContextThread() is done. */ @@ -50,9 +50,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#ifdef HAVE_GETOPT_H +#include #include -#endif #ifdef USE_LIBSYSTEMD #include #endif @@ -70,21 +69,17 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "utils.h" #include "eventhandler.h" -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -_Atomic char AraKiri = FALSE; -static char Init = TRUE; -char AutoExit = FALSE; -char SocketActivated = FALSE; +_Atomic bool AraKiri = false; +static bool Init = true; +bool AutoExit = false; +bool SocketActivated = false; static int ExitValue = EXIT_FAILURE; int HPForceReaderPolling = 0; +bool disable_polkit = false; static int pipefd[] = {-1, -1}; static int signal_handler_fd[] = {-1, -1}; -char Add_Serial_In_Name = TRUE; -char Add_Interface_In_Name = TRUE; +bool Add_Serial_In_Name = true; +bool Add_Interface_In_Name = true; /* * Some internal functions @@ -109,7 +104,7 @@ static void SVCServiceRunLoop(void) LONG rv; uint32_t dwClientID = 0; /* Connection ID used to reference the Client */ - while (TRUE) + while (true) { if (AraKiri) { @@ -119,10 +114,12 @@ static void SVCServiceRunLoop(void) #endif (void)SYS_Sleep(1); + /* stop all the clients */ + ContextsDeinitialize(); + /* now stop all the drivers */ RFCleanupReaders(); EHDeinitializeEventStructures(); - ContextsDeinitialize(); at_exit(); } @@ -178,9 +175,9 @@ static void *signal_thread(void *arg) { (void)arg; - while (TRUE) + while (true) { - int r; + ssize_t r; int sig; r = read(signal_handler_fd[0], &sig, sizeof sig); @@ -199,7 +196,7 @@ static void *signal_thread(void *arg) if (! AraKiri) HPReCheckSerialReaders(); #endif - /* Reenable the signal handler. + /* Re-enable the signal handler. * This is needed on Solaris and HPUX. */ (void)signal(SIGUSR1, signal_trap); @@ -222,10 +219,10 @@ static void *signal_thread(void *arg) } /* the signal handler is called several times for the same Ctrl-C */ - if (AraKiri == FALSE) + if (AraKiri == false) { Log1(PCSC_LOG_INFO, "Preparing for suicide"); - AraKiri = TRUE; + AraKiri = true; /* if still in the init/loading phase the AraKiri will not be * seen by the main event loop @@ -258,8 +255,8 @@ static void *signal_thread(void *arg) int main(int argc, char **argv) { int rv; - char setToForeground; - char HotPlug; + bool setToForeground; + bool HotPlug; #ifdef USE_SERIAL char *newReaderConfig = NULL; #endif @@ -290,13 +287,14 @@ int main(int argc, char **argv) {"auto-exit", 0, NULL, 'x'}, {"reader-name-no-serial", 0, NULL, 'S'}, {"reader-name-no-interface", 0, NULL, 'I'}, + {"disable-polkit", 0, NULL, 1}, {NULL, 0, NULL, 0} }; #endif #define OPT_STRING "c:fTdhvaieCHt:r:s:xSI" - setToForeground = FALSE; - HotPlug = FALSE; + setToForeground = false; + HotPlug = false; /* * test the version @@ -335,6 +333,11 @@ int main(int argc, char **argv) "force-reader-polling") == 0) HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1; break; + case 1: + if (strcmp(long_options[option_index].name, + "disable-polkit") == 0) + disable_polkit = true; + break; #endif #ifdef USE_SERIAL case 'c': @@ -344,7 +347,7 @@ int main(int argc, char **argv) #endif case 'f': - setToForeground = TRUE; + setToForeground = true; /* debug to stdout instead of default syslog */ DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG); Log1(PCSC_LOG_INFO, @@ -387,7 +390,7 @@ int main(int argc, char **argv) case 'H': /* debug to stdout instead of default syslog */ DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG); - HotPlug = TRUE; + HotPlug = true; break; case 't': @@ -409,17 +412,17 @@ int main(int argc, char **argv) break; case 'x': - AutoExit = TRUE; + AutoExit = true; Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity", TIME_BEFORE_SUICIDE); break; case 'S': - Add_Serial_In_Name = FALSE; + Add_Serial_In_Name = false; break; case 'I': - Add_Interface_In_Name = FALSE; + Add_Interface_In_Name = false; break; default: @@ -450,11 +453,11 @@ int main(int argc, char **argv) { if (rv == 1) { - SocketActivated = TRUE; + SocketActivated = true; Log1(PCSC_LOG_INFO, "Started by systemd"); } else - SocketActivated = FALSE; + SocketActivated = false; } #endif @@ -566,7 +569,7 @@ int main(int argc, char **argv) /* in the father */ { char buf; - int ret; + ssize_t ret; /* close write side */ close(pipefd[1]); @@ -630,7 +633,7 @@ int main(int argc, char **argv) /* set mode so that the directory is world readable and * executable even is umask is restrictive - * The directory containes files used by libpcsclite */ + * The directory contains files used by libpcsclite */ (void)chmod(PCSCLITE_IPC_DIR, mode); } @@ -705,7 +708,7 @@ int main(int argc, char **argv) /* * post initialization */ - Init = FALSE; + Init = false; /* * Hotplug rescan @@ -743,19 +746,20 @@ int main(int argc, char **argv) (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent * when the shell is exited */ + const char *hpDirPath = SYS_GetEnv("PCSCLITE_HP_DROPDIR"); + if (NULL == hpDirPath) + hpDirPath = PCSCLITE_HP_DROPDIR; + Log2(PCSC_LOG_INFO, "Using drivers directory: %s", hpDirPath); + #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB) /* * Set up the search for USB/PCMCIA devices */ - rv = HPSearchHotPluggables(); -#ifndef USE_SERIAL + rv = HPSearchHotPluggables(hpDirPath); if (rv) at_exit(); -#else - (void)rv; -#endif - rv = HPRegisterForHotplugEvents(); + rv = HPRegisterForHotplugEvents(hpDirPath); if (rv) { Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed"); @@ -838,7 +842,7 @@ static void clean_temp_files(void) static void signal_trap(int sig) { - int r; + ssize_t r; r = write(signal_handler_fd[1], &sig, sizeof sig); if (r < 0) @@ -847,13 +851,13 @@ static void signal_trap(int sig) static void print_version(void) { - printf("%s version %s.\n", PACKAGE, VERSION); + printf("pcsc-lite version " VERSION "\n"); printf("Copyright (C) 1999-2002 by David Corcoran .\n"); - printf("Copyright (C) 2001-2022 by Ludovic Rousseau .\n"); + printf("Copyright (C) 2001-2024 by Ludovic Rousseau .\n"); printf("Copyright (C) 2003-2004 by Damien Sauveron .\n"); printf("Report bugs to .\n"); - printf("Enabled features:%s\n", PCSCLITE_FEATURES); + printf("Enabled features: " PCSCLITE_FEATURES "\n"); printf("MAX_READERNAME: %d, PCSCLITE_MAX_READERS_CONTEXTS: %d\n", MAX_READERNAME, PCSCLITE_MAX_READERS_CONTEXTS); } @@ -884,6 +888,7 @@ static void print_usage(char const * const progname) printf(" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE); printf(" -S, --reader-name-no-serial do not include the USB serial number in the name\n"); printf(" -I, --reader-name-no-interface do not include the USB interface name in the name\n"); + printf(" --disable-polkit disable polkit support\n"); #else printf(" -a log APDU commands and results\n"); #ifdef USE_SERIAL diff --git a/src/prothandler.c b/src/prothandler.c index 56c00eaa..f4a4e05e 100644 --- a/src/prothandler.c +++ b/src/prothandler.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2004-2011 + * Copyright (C) 2004-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -36,16 +36,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include #include "misc.h" -#include "pcscd.h" #include "debuglog.h" -#include "readerfactory.h" #include "prothandler.h" -#include "atrhandler.h" #include "ifdwrapper.h" -#include "eventhandler.h" /** * Determine which protocol to use. @@ -104,6 +99,7 @@ DWORD PHSetProtocol(struct ReaderContext * rContext, /* App wants unsupported protocol */ return SET_PROTOCOL_WRONG_ARGUMENT; +again: Log2(PCSC_LOG_INFO, "Attempting PTS to T=%d", (SCARD_PROTOCOL_T0 == ucChosen ? 0 : 1)); rv = IFDSetPTS(rContext, ucChosen, 0x00, 0x00, 0x00, 0x00); @@ -119,9 +115,25 @@ DWORD PHSetProtocol(struct ReaderContext * rContext, /* protocol not supported */ if (protocol != dwPreferred) { - Log3(PCSC_LOG_INFO, - "Set PTS failed (%ld). Using T=%d", rv, - (SCARD_PROTOCOL_T0 == protocol) ? 0 : 1); + if (protocol & dwPreferred) + { + Log3(PCSC_LOG_INFO, + "Set PTS failed (%ld). Using T=%d", rv, + (SCARD_PROTOCOL_T0 == protocol) ? 0 : 1); + + /* try again with the other protocol */ + ucChosen = protocol; + + /* but no other protocol should be tried after that */ + dwPreferred = protocol; + + goto again; + } + else + { + Log2(PCSC_LOG_INFO, "Set PTS failed (%ld)", rv); + protocol = SET_PROTOCOL_WRONG_ARGUMENT; + } } else { diff --git a/src/prothandler.h b/src/prothandler.h index d3a7de5f..24c8302e 100644 --- a/src/prothandler.h +++ b/src/prothandler.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2004 + * Copyright (C) 2004-2021 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/readerfactory.c b/src/readerfactory.c index 1cb4197b..df2a54e7 100644 --- a/src/readerfactory.c +++ b/src/readerfactory.c @@ -5,7 +5,7 @@ * David Corcoran * Copyright (C) 2003-2004 * Damien Sauveron - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Copyright (C) 2009 * Jean-Luc Giraud @@ -49,10 +49,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#ifdef HAVE_ALLOCA_H -#include -#endif #include +#include #include "misc.h" #include "pcscd.h" @@ -66,11 +64,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "configfile.h" #include "utils.h" -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - static READER_CONTEXT * sReadersContexts[PCSCLITE_MAX_READERS_CONTEXTS]; READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]; static int maxReaderHandles = PCSC_MAX_READER_HANDLES; @@ -80,8 +73,8 @@ static char *ConfigFile = NULL; static int ConfigFileCRC = 0; #endif static pthread_mutex_t LockMutex = PTHREAD_MUTEX_INITIALIZER; +int16_t ReaderEvents = 1; -#define IDENTITY_SHIFT 16 static LONG removeReader(READER_CONTEXT * sReader); static int RDR_CLIHANDLES_seeker(const void *el, const void *key) @@ -172,7 +165,7 @@ LONG RFAddReader(const char *readerNameLong, int port, const char *library, return SCARD_E_INVALID_VALUE; #ifdef FILTER_NAMES - const char *ro_filter = getenv("PCSCLITE_FILTER_IGNORE_READER_NAMES"); + const char *ro_filter = SYS_GetEnv("PCSCLITE_FILTER_IGNORE_READER_NAMES"); if (ro_filter) { char *filter, *next; @@ -407,6 +400,12 @@ LONG RFAddReader(const char *readerNameLong, int port, const char *library, } } + /* we have one more reader */ + ReaderEvents++; + /* wrap? */ + if (ReaderEvents < 0) + ReaderEvents = 1; + /* Call on the driver to see if there are multiple slots */ dwGetSize = sizeof(ucGetData); rv = IFDGetCapabilities((sReadersContexts[dwContext]), @@ -588,7 +587,7 @@ LONG RFRemoveReader(const char *readerName, int port, int flags) return SCARD_E_INVALID_VALUE; #ifdef FILTER_NAMES - extend = getenv("PCSCLITE_FILTER_EXTEND_READER_NAMES"); + extend = SYS_GetEnv("PCSCLITE_FILTER_EXTEND_READER_NAMES"); if (extend) extend_size = strlen(extend); #endif @@ -630,6 +629,12 @@ LONG RFRemoveReader(const char *readerName, int port, int flags) } } + /* we have one less reader */ + ReaderEvents++; + /* wrap? */ + if (ReaderEvents < 0) + ReaderEvents = 1; + return SCARD_S_SUCCESS; } @@ -712,13 +717,13 @@ LONG RFSetReaderName(READER_CONTEXT * rContext, const char *readerName, DWORD valueLength; int currentDigit = -1; int supportedChannels = 0; - int usedDigits[PCSCLITE_MAX_READERS_CONTEXTS]; + bool usedDigits[PCSCLITE_MAX_READERS_CONTEXTS]; int i; const char *extend = ""; /* Clear the list */ for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) - usedDigits[i] = FALSE; + usedDigits[i] = false; if (dwNumReadersContexts != 0) { @@ -770,7 +775,7 @@ LONG RFSetReaderName(READER_CONTEXT * rContext, const char *readerName, currentDigit = strtol(reader + strlen(reader) - 5, NULL, 16); /* This spot is taken */ - usedDigits[currentDigit] = TRUE; + usedDigits[currentDigit] = true; } } } @@ -786,7 +791,7 @@ LONG RFSetReaderName(READER_CONTEXT * rContext, const char *readerName, for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { /* get the first free digit */ - if (usedDigits[i] == FALSE) + if (usedDigits[i] == false) break; } @@ -806,7 +811,7 @@ LONG RFSetReaderName(READER_CONTEXT * rContext, const char *readerName, } #ifdef FILTER_NAMES - extend = getenv("PCSCLITE_FILTER_EXTEND_READER_NAMES"); + extend = SYS_GetEnv("PCSCLITE_FILTER_EXTEND_READER_NAMES"); if (NULL == extend) extend = ""; #endif @@ -876,6 +881,7 @@ LONG RFReaderInfoById(SCARDHANDLE hCard, READER_CONTEXT * * sReader) LONG RFLoadReader(READER_CONTEXT * rContext) { + LONG ret = SCARD_S_SUCCESS; if (rContext->vHandle != 0) { Log2(PCSC_LOG_INFO, "Reusing already loaded driver for %s", @@ -884,7 +890,10 @@ LONG RFLoadReader(READER_CONTEXT * rContext) return SCARD_S_SUCCESS; } - return DYN_LoadLibrary(&rContext->vHandle, rContext->library); + rContext->vHandle = DYN_LoadLibrary(rContext->library); + if (NULL == rContext->vHandle) + ret = SCARD_F_UNKNOWN_ERROR; + return ret; } LONG RFBindFunctions(READER_CONTEXT * rContext) @@ -892,7 +901,7 @@ LONG RFBindFunctions(READER_CONTEXT * rContext) int rv; void *f; - rv = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannelByName", TRUE); + rv = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannelByName", true); if (SCARD_S_SUCCESS == rv) { /* Ifd Handler 3.0 found */ @@ -900,7 +909,7 @@ LONG RFBindFunctions(READER_CONTEXT * rContext) } else { - rv = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannel", FALSE); + rv = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannel", false); if (SCARD_S_SUCCESS == rv) { /* Ifd Handler 2.0 found */ @@ -920,7 +929,7 @@ LONG RFBindFunctions(READER_CONTEXT * rContext) #define GET_ADDRESS_OPTIONALv2(s, code) \ { \ void *f1 = NULL; \ - int rvl = DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s, FALSE); \ + int rvl = DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s, false); \ if (SCARD_S_SUCCESS != rvl) \ { \ code \ @@ -952,7 +961,7 @@ LONG RFBindFunctions(READER_CONTEXT * rContext) #define GET_ADDRESS_OPTIONALv3(s, code) \ { \ void *f1 = NULL; \ - int rvl = DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s, FALSE); \ + int rvl = DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s, false); \ if (SCARD_S_SUCCESS != rvl) \ { \ code \ @@ -981,7 +990,7 @@ LONG RFBindFunctions(READER_CONTEXT * rContext) } else { - /* Who knows what could have happenned for it to get here. */ + /* Who knows what could have happened for it to get here. */ Log1(PCSC_LOG_CRITICAL, "IFD Handler not 1.0/2.0 or 3.0"); return SCARD_F_UNKNOWN_ERROR; } @@ -1003,7 +1012,8 @@ LONG RFUnloadReader(READER_CONTEXT * rContext) if (*rContext->pFeeds == 1) { Log1(PCSC_LOG_INFO, "Unloading reader driver."); - (void)DYN_CloseLibrary(&rContext->vHandle); + (void)DYN_CloseLibrary(rContext->vHandle); + rContext->vHandle = NULL; } rContext->vHandle = NULL; @@ -1163,6 +1173,7 @@ void RFUnInitializeReader(READER_CONTEXT * rContext) memset(rContext->readerState->cardAtr, 0, sizeof(rContext->readerState->cardAtr)); rContext->readerState->readerState = 0; + rContext->readerState->eventCounter = 0; rContext->readerState->readerSharing = 0; rContext->readerState->cardAtrLength = READER_NOT_INITIALIZED; rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED; @@ -1418,15 +1429,15 @@ void RFCleanupReaders(void) #ifdef USE_USB void RFWaitForReaderInit(void) { - int i, need_to_wait; + bool need_to_wait; do { - need_to_wait = FALSE; - for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) + need_to_wait = false; + for (int i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) { /* reader is present */ - if (sReadersContexts[i]->vHandle != NULL) + if (sReadersContexts[i] && sReadersContexts[i]->vHandle != NULL) { /* but card state is not yet available */ if (READER_NOT_INITIALIZED @@ -1434,7 +1445,7 @@ void RFWaitForReaderInit(void) { Log2(PCSC_LOG_DEBUG, "Waiting init for reader: %s", sReadersContexts[i]->readerState->readerName); - need_to_wait = TRUE; + need_to_wait = true; } } } @@ -1523,7 +1534,7 @@ void RFReCheckReaderConf(void) for (i=0; reader_list[i].pcFriendlyname; i++) { int r; - char present = FALSE; + char present = false; Log2(PCSC_LOG_DEBUG, "refresh reader: %s", reader_list[i].pcFriendlyname); @@ -1549,7 +1560,7 @@ void RFReCheckReaderConf(void) DWORD dwStatus = 0; /* the reader was already started */ - present = TRUE; + present = true; /* verify the reader is still connected */ if (IFDStatusICC(sReadersContexts[r], &dwStatus) diff --git a/src/readerfactory.h b/src/readerfactory.h index c8b31dfb..289be650 100644 --- a/src/readerfactory.h +++ b/src/readerfactory.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -119,12 +119,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. FCT_MAP_V3 psFunctions_v3; /**< API V3.0 */ } psFunctions; /**< driver functions */ - LPVOID vHandle; /**< Dlopen handle */ + _Atomic LPVOID vHandle; /**< Dlopen handle */ int version; /**< IFD Handler version number */ int port; /**< Port ID */ int slot; /**< Current Reader Slot */ _Atomic SCARDHANDLE hLockId; /**< Lock Id */ - int LockCount; /**< number of recursive locks */ + _Atomic int LockCount; /**< number of recursive locks */ _Atomic int32_t contexts; /**< Number of open contexts */ int * pFeeds; /**< Number of shared client to lib */ int * pMutex; /**< Number of client to mutex */ diff --git a/src/simclist.c b/src/simclist.c index 659aab97..c5526990 100644 --- a/src/simclist.c +++ b/src/simclist.c @@ -168,7 +168,7 @@ typedef INT64 int64_t; #include "simclist.h" -/* minumum number of elements for sorting with quicksort instead of insertion */ +/* minimum number of elements for sorting with quicksort instead of insertion */ #define SIMCLIST_MINQUICKSORTELS 24 @@ -217,7 +217,7 @@ static inline void list_sort_selectionsort(list_t *restrict l, int versus, static void *list_get_minmax(const list_t *restrict l, int versus); -static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart); +static struct list_entry_s *list_findpos(const list_t *restrict l, int posstart); /* * Random Number Generator @@ -440,7 +440,7 @@ static void *list_get_minmax(const list_t *restrict l, int versus) { } /* set tmp to point to element at index posstart in l */ -static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart) { +static struct list_entry_s *list_findpos(const list_t *restrict l, int posstart) { struct list_entry_s *ptr; float x; int i; @@ -661,7 +661,7 @@ int list_clear(list_t *restrict l) { if (l->head_sentinel && l->tail_sentinel) { if (l->attrs.copy_data) { /* also free user data */ - /* spare a loop conditional with two loops: spareing elems and freeing elems */ + /* spare a loop conditional with two loops: sparing elems and freeing elems */ for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) { /* move elements as spares as long as there is room */ if (s->data != NULL) free(s->data); @@ -676,7 +676,7 @@ int list_clear(list_t *restrict l) { l->head_sentinel->next = l->tail_sentinel; l->tail_sentinel->prev = l->head_sentinel; } else { /* only free element containers */ - /* spare a loop conditional with two loops: spareing elems and freeing elems */ + /* spare a loop conditional with two loops: sparing elems and freeing elems */ for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) { /* move elements as spares as long as there is room */ l->spareels[l->spareelsnum++] = s; diff --git a/src/simclist.h b/src/simclist.h index 2ce9d491..e4a9cf32 100644 --- a/src/simclist.h +++ b/src/simclist.h @@ -75,7 +75,7 @@ typedef struct { * -# receives two references to elements a and b * -# returns {<0, 0, >0} if (a > b), (a == b), (a < b) respectively * - * It is responsability of the function to handle possible NULL values. + * It is responsibility of the function to handle possible NULL values. */ typedef int (*element_comparator)(const void *a, const void *b); @@ -87,7 +87,7 @@ typedef int (*element_comparator)(const void *a, const void *b); * -# receives a reference to some indicator data * -# returns non-0 if the element matches the indicator, 0 otherwise * - * It is responsability of the function to handle possible NULL values in any + * It is responsibility of the function to handle possible NULL values in any * argument. */ typedef int (*element_seeker)(const void *el, const void *indicator); @@ -99,7 +99,7 @@ typedef int (*element_seeker)(const void *el, const void *indicator); * -# receives the reference to an element el * -# returns its size in bytes * - * It is responsability of the function to handle possible NULL values. + * It is responsibility of the function to handle possible NULL values. */ typedef size_t (*element_meter)(const void *el); @@ -110,7 +110,7 @@ typedef size_t (*element_meter)(const void *el); * -# receives the reference to an element el * -# returns a hash value for el * - * It is responsability of the function to handle possible NULL values. + * It is responsibility of the function to handle possible NULL values. */ typedef list_hash_t (*element_hash_computer)(const void *el); @@ -120,7 +120,7 @@ typedef list_hash_t (*element_hash_computer)(const void *el); * A serializer function is one that gets a reference to an element, * and returns a reference to a buffer that contains its serialization * along with the length of this buffer. - * It is responsability of the function to handle possible NULL values, + * It is responsibility of the function to handle possible NULL values, * returning a NULL buffer and a 0 buffer length. * * These functions have 3 goals: @@ -259,7 +259,7 @@ int list_attributes_seeker(list_t *restrict l, element_seeker seeker_fun); * the list by its actual data is not free()d. With this option, every * deletion causes element data to be freed. * - * It is responsability of this function to correctly handle NULL values, if + * It is responsibility of this function to correctly handle NULL values, if * NULL elements are inserted into the list. * * @param l list to operate @@ -439,7 +439,7 @@ int list_insert_at(list_t *restrict l, const void *data, unsigned int pos); * expunge the first found given element from the list. * * Inspects the given list looking for the given element; if the element - * is found, it is removed. Only the first occurence is removed. + * is found, it is removed. Only the first occurrence is removed. * If a comparator function was not set, elements are compared by reference. * Otherwise, the comparator is used to match the element. * @@ -641,7 +641,7 @@ int list_hash(const list_t *restrict l, list_hash_t *restrict hash); #ifndef SIMCLIST_NO_DUMPRESTORE /** - * get meta informations on a list dump on filedescriptor. + * get meta information on a list dump on filedescriptor. * * [ advanced function ] * @@ -658,7 +658,7 @@ int list_hash(const list_t *restrict l, list_hash_t *restrict hash); int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *restrict info); /** - * get meta informations on a list dump on file. + * get meta information on a list dump on file. * * [ advanced function ] * diff --git a/src/strlcpy.3 b/src/strlcpy.3 deleted file mode 100644 index 63129888..00000000 --- a/src/strlcpy.3 +++ /dev/null @@ -1,186 +0,0 @@ -.\" $OpenBSD: strlcpy.3,v 1.18 2005/08/06 03:24:19 jaredy Exp $ -.\" -.\" Copyright (c) 1998, 2000 Todd C. Miller -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd June 22, 1998 -.Dt STRLCPY 3 -.Os -.Sh NAME -.Nm strlcpy , -.Nm strlcat -.Nd size-bounded string copying and concatenation -.Sh SYNOPSIS -.Fd #include -.Ft size_t -.Fn strlcpy "char *dst" "const char *src" "size_t size" -.Ft size_t -.Fn strlcat "char *dst" "const char *src" "size_t size" -.Sh DESCRIPTION -The -.Fn strlcpy -and -.Fn strlcat -functions copy and concatenate strings respectively. -They are designed -to be safer, more consistent, and less error prone replacements for -.Xr strncpy 3 -and -.Xr strncat 3 . -Unlike those functions, -.Fn strlcpy -and -.Fn strlcat -take the full size of the buffer (not just the length) and guarantee to -NUL-terminate the result (as long as -.Fa size -is larger than 0 or, in the case of -.Fn strlcat , -as long as there is at least one byte free in -.Fa dst ) . -Note that a byte for the NUL should be included in -.Fa size . -Also note that -.Fn strlcpy -and -.Fn strlcat -only operate on true -.Dq C -strings. -This means that for -.Fn strlcpy -.Fa src -must be NUL-terminated and for -.Fn strlcat -both -.Fa src -and -.Fa dst -must be NUL-terminated. -.Pp -The -.Fn strlcpy -function copies up to -.Fa size -- 1 characters from the NUL-terminated string -.Fa src -to -.Fa dst , -NUL-terminating the result. -.Pp -The -.Fn strlcat -function appends the NUL-terminated string -.Fa src -to the end of -.Fa dst . -It will append at most -.Fa size -- strlen(dst) - 1 bytes, NUL-terminating the result. -.Sh RETURN VALUES -The -.Fn strlcpy -and -.Fn strlcat -functions return the total length of the string they tried to create. -For -.Fn strlcpy -that means the length of -.Fa src . -For -.Fn strlcat -that means the initial length of -.Fa dst -plus -the length of -.Fa src . -While this may seem somewhat confusing, it was done to make -truncation detection simple. -.Pp -Note, however, that if -.Fn strlcat -traverses -.Fa size -characters without finding a NUL, the length of the string is considered -to be -.Fa size -and the destination string will not be NUL-terminated (since there was -no space for the NUL). -This keeps -.Fn strlcat -from running off the end of a string. -In practice this should not happen (as it means that either -.Fa size -is incorrect or that -.Fa dst -is not a proper -.Dq C -string). -The check exists to prevent potential security problems in incorrect code. -.Sh EXAMPLES -The following code fragment illustrates the simple case: -.Bd -literal -offset indent -char *s, *p, buf[BUFSIZ]; - -\&... - -(void)strlcpy(buf, s, sizeof(buf)); -(void)strlcat(buf, p, sizeof(buf)); -.Ed -.Pp -To detect truncation, perhaps while building a pathname, something -like the following might be used: -.Bd -literal -offset indent -char *dir, *file, pname[MAXPATHLEN]; - -\&... - -if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname)) - goto toolong; -if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname)) - goto toolong; -.Ed -.Pp -Since it is known how many characters were copied the first time, things -can be sped up a bit by using a copy instead of an append: -.Bd -literal -offset indent -char *dir, *file, pname[MAXPATHLEN]; -size_t n; - -\&... - -n = strlcpy(pname, dir, sizeof(pname)); -if (n >= sizeof(pname)) - goto toolong; -if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n) - goto toolong; -.Ed -.Pp -However, one may question the validity of such optimizations, as they -defeat the whole purpose of -.Fn strlcpy -and -.Fn strlcat . -As a matter of fact, the first version of this manual page got it wrong. -.Sh SEE ALSO -.Xr snprintf 3 , -.Xr strncat 3 , -.Xr strncpy 3 -.Sh HISTORY -The -.Fn strlcpy -and -.Fn strlcat -functions first appeared in -.Ox 2.4 . diff --git a/src/strlcpy.c b/src/strlcpy.c deleted file mode 100644 index 437df6dc..00000000 --- a/src/strlcpy.c +++ /dev/null @@ -1,60 +0,0 @@ -/* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef HAVE_STRLCPY - -#include -#include -#include "strlcpycat.h" - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t -strlcpy(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} - -#endif diff --git a/src/sys_generic.h b/src/sys_generic.h index b68c3362..a4979b55 100644 --- a/src/sys_generic.h +++ b/src/sys_generic.h @@ -3,7 +3,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2022 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -49,4 +49,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. void SYS_InitRandom(void); + const char * SYS_GetEnv(const char *name); + #endif /* __sys_generic_h__ */ diff --git a/src/sys_unix.c b/src/sys_unix.c index d756648b..644e39ce 100644 --- a/src/sys_unix.c +++ b/src/sys_unix.c @@ -5,7 +5,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -38,6 +38,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" +#define _GNU_SOURCE /* for secure_getenv(3) */ #include #include #include @@ -47,10 +48,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif /* HAVE_GETRANDOM */ #include #include +#include #include "misc.h" #include "sys_generic.h" -#include "PCSC/debuglog.h" +#include "debuglog.h" /** * @brief Makes the current process sleep for some seconds. @@ -114,7 +116,9 @@ INTERNAL int SYS_RandomInt(void) ret = getrandom(c, sizeof c, 0); if (-1 == ret) { +#ifdef PCSCD Log2(PCSC_LOG_ERROR, "getrandom() failed: %s", strerror(errno)); +#endif return lrand48(); } // this loop avoids trap representations that may occur in the naive solution @@ -125,7 +129,7 @@ INTERNAL int SYS_RandomInt(void) // the casts are for the sake of clarity return (int)(ui & (unsigned int)INT_MAX); #else - int r = lrand48(); // this is not thread-safe + int r = (int)lrand48(); // this is not thread-safe return r; #endif /* HAVE_GETRANDOM */ } @@ -154,3 +158,23 @@ INTERNAL void SYS_InitRandom(void) #endif /* HAVE_GETRANDOM */ } +/** + * (More) secure version of getenv(3) + * + * @param[in] name variable environment name + * + * @return value of the environment variable called "name" + */ +INTERNAL const char * SYS_GetEnv(const char *name) +{ +#ifdef HAVE_SECURE_GETENV + return secure_getenv(name); +#else + /* Otherwise, make sure current process is not tainted by uid or gid + * changes */ + if (issetugid()) + return NULL; + return getenv(name); +#endif +} + diff --git a/src/testpcsc.c b/src/testpcsc.c index 15499d88..c22ccf08 100644 --- a/src/testpcsc.c +++ b/src/testpcsc.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999 * David Corcoran - * Copyright (C) 2004-2010 + * Copyright (C) 2004-2022 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -76,10 +76,10 @@ static void test_rv(LONG rv, SCARDCONTEXT hContext, int dont_panic) int main(/*@unused@*/ int argc, /*@unused@*/ char **argv) { SCARDHANDLE hCard; - SCARDCONTEXT hContext; + SCARDCONTEXT hContext = -1; SCARD_READERSTATE rgReaderStates[1]; DWORD dwReaderLen, dwState, dwProt, dwAtrLen; - DWORD dwPref, dwReaders = 0; + DWORD dwPref = -1, dwReaders = 0; char *pcReader = NULL, *mszReaders; #ifdef USE_AUTOALLOCATE unsigned char *pbAtr = NULL; @@ -94,7 +94,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char **argv) DWORD dwBufLen; unsigned char *pbAttr = NULL; DWORD pcbAttrLen; - char *mszGroups; + char *mszGroups = NULL; DWORD dwGroups = 0; long rv; DWORD i; @@ -188,7 +188,7 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char **argv) mszReaders = calloc(dwReaders, sizeof(char)); rv = SCardListReaders(hContext, mszGroups, mszReaders, &dwReaders); #endif - test_rv(rv, hContext, DONT_PANIC); + test_rv(rv, hContext, PANIC); /* * Have to understand the multi-string here @@ -283,14 +283,6 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char **argv) printf("\n" NORMAL); printf("Testing SCardControl\t\t: "); -#ifdef PCSC_PRE_120 - { - char buffer[1024] = "Foobar"; - DWORD cbRecvLength = sizeof(buffer); - - rv = SCardControl(hCard, buffer, 7, buffer, &cbRecvLength); - } -#else { char buffer[1024] = { 0x02 }; DWORD cbRecvLength = sizeof(buffer); @@ -304,7 +296,6 @@ int main(/*@unused@*/ int argc, /*@unused@*/ char **argv) printf(" "); } } -#endif test_rv(rv, hContext, DONT_PANIC); printf("Testing SCardGetAttrib\t\t: "); diff --git a/src/tokenparser.l b/src/tokenparser.l index e829a36f..afc2aa71 100644 --- a/src/tokenparser.l +++ b/src/tokenparser.l @@ -5,7 +5,7 @@ * * Copyright (C) 2001-2003 * David Corcoran - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2026 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -59,6 +59,7 @@ void tperrorCheck (char *pcToken_error); static list_t *ListKeys; static list_t *ListValues; +static const char * Filename; %} @@ -120,6 +121,15 @@ static void eval_value(char *pcToken, list_t *list_values) /* foobar * 012345678 : 8 is the first string character index */ + /* list_values may be NULL if the Info.plist file is corrupted and + * eval_key() has not yet been called */ + if (! list_values) + { + Log3(PCSC_LOG_CRITICAL, "Corrupted bundle file %s before: %s", + Filename, pcToken); + return; + } + /* calculate the argument length */ for (len=0; pcToken[len+8] != '<'; len++) ; @@ -215,6 +225,7 @@ int bundleParse(const char *fileName, list_t *l) fileName, strerror(errno)); return 1; } + Filename = fileName; r = list_init(l); assert(r >= 0); diff --git a/src/utils.c b/src/utils.c index 2a3e5e6a..b5199ee7 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,7 +1,7 @@ /* * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) * - * Copyright (C) 2006-2011 + * Copyright (C) 2006-2021 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/utils.h b/src/utils.h index 791883b1..0d1fe3b0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,7 +1,7 @@ /* * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) * - * Copyright (C) 2006-2009 + * Copyright (C) 2006-2021 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without diff --git a/src/winscard.c b/src/winscard.c index 030d1362..82fd1308 100644 --- a/src/winscard.c +++ b/src/winscard.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999-2004 * David Corcoran - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -71,7 +71,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @section Internals * - * PC/SC Lite is formed by a server deamon (pcscd) and a client + * PC/SC Lite is formed by a server daemon (pcscd) and a client * library (libpcsclite.so) that communicate via IPC. * * The file \em winscard_clnt.c in the client-side exposes the API for @@ -122,11 +122,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #undef DO_PROFILE #ifdef DO_PROFILE -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif - #define PROFILE_FILE "/tmp/pcscd_profile" #include #include @@ -135,18 +130,18 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct timeval profile_time_start; FILE *fd; -char profile_tty; +bool profile_tty; #define PROFILE_START profile_start(__FUNCTION__); #define PROFILE_END profile_end(__FUNCTION__, __LINE__); static void profile_start(const char *f) { - static char initialized = FALSE; + static bool initialized = false; if (!initialized) { - initialized = TRUE; + initialized = true; fd = fopen(PROFILE_FILE, "a+"); if (NULL == fd) { @@ -158,9 +153,9 @@ static void profile_start(const char *f) fflush(fd); if (isatty(fileno(stderr))) - profile_tty = TRUE; + profile_tty = true; else - profile_tty = FALSE; + profile_tty = false; } gettimeofday(&profile_time_start, NULL); @@ -383,6 +378,9 @@ LONG SCardConnect(/*@unused@*/ SCARDCONTEXT hContext, LPCSTR szReader, if (dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD) dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; + /* restrict to the protocols requested by the user */ + availableProtocols &= dwPreferredProtocols; + ret = PHSetProtocol(rContext, dwPreferredProtocols, availableProtocols, defaultProtocol); @@ -447,7 +445,7 @@ LONG SCardConnect(/*@unused@*/ SCARDCONTEXT hContext, LPCSTR szReader, * Prepare the SCARDHANDLE identity */ - /* we need a lock to avoid concurent generation of handles leading + /* we need a lock to avoid concurrent generation of handles leading * to a possible hCard handle duplication */ (void)pthread_mutex_lock(&LockMutex); @@ -680,6 +678,9 @@ LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, if (dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD) dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; + /* restrict to the protocols requested by the user */ + availableProtocols &= dwPreferredProtocols; + ret = PHSetProtocol(rContext, dwPreferredProtocols, availableProtocols, defaultProtocol); @@ -945,7 +946,7 @@ LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) else if (dwDisposition == SCARD_EJECT_CARD) { UCHAR controlBuffer[5]; - UCHAR receiveBuffer[MAX_BUFFER_SIZE]; + UCHAR receiveBuffer[MAX_BUFFER_SIZE] = { 0 }; DWORD receiveLength; /* diff --git a/src/winscard_clnt.c b/src/winscard_clnt.c index 78a651d6..fc8db9cf 100644 --- a/src/winscard_clnt.c +++ b/src/winscard_clnt.c @@ -7,7 +7,7 @@ * Damien Sauveron * Copyright (C) 2005 * Martin Paljak - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2025 * Ludovic Rousseau * Copyright (C) 2009 * Jean-Luc Giraud @@ -114,13 +114,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "misc.h" #include "pcscd.h" #include "winscard.h" #include "debuglog.h" -#include "readerfactory.h" #include "eventhandler.h" #include "sys_generic.h" #include "winscard_msg.h" @@ -134,12 +134,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //#define DO_PROFILE -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -static char sharing_shall_block = TRUE; +static bool sharing_shall_block = true; +static int Protocol_version; #define COLOR_RED "\33[01;31m" #define COLOR_GREEN "\33[32m" @@ -185,14 +181,14 @@ static void trace(const char *func, const char direction, const char *fmt, ...) pthread_t threads[MAX_THREADS]; struct timeval profile_time_start[MAX_THREADS]; FILE *profile_fd; -char profile_tty; +bool profile_tty; #define PROFILE_START profile_start(); #define PROFILE_END(rv) profile_end(__FUNCTION__, rv); static void profile_start(void) { - static char initialized = FALSE; + static bool initialized = false; pthread_t t; int i; @@ -200,7 +196,7 @@ static void profile_start(void) { char filename[80]; - initialized = TRUE; + initialized = true; sprintf(filename, "%s-%d", PROFILE_FILE, getuid()); profile_fd = fopen(filename, "a+"); if (NULL == profile_fd) @@ -212,9 +208,9 @@ static void profile_start(void) fprintf(profile_fd, "\nStart a new profile\n"); if (isatty(fileno(stderr))) - profile_tty = TRUE; + profile_tty = true; else - profile_tty = FALSE; + profile_tty = false; } t = pthread_self(); @@ -255,14 +251,10 @@ static void profile_end(const char *f, LONG rv) if (profile_tty) { - if (rv != SCARD_S_SUCCESS) - fprintf(stderr, - COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld " - COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n", - f, d, rv, pcsc_stringify_error(rv)); - else - fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld" - COLOR_NORMAL "\n", f, d); + fprintf(stderr, + COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld " + COLOR_BLUE "0x%08lX" COLOR_NORMAL "\n", + f, d, rv); } fprintf(profile_fd, "%s %ld\n", f, d); fflush(profile_fd); @@ -314,7 +306,7 @@ struct _psContextMap SCARDCONTEXT hContext; /**< Application Context ID */ pthread_mutex_t mMutex; /**< Mutex for this context */ list_t channelMapList; - char cancellable; /**< We are in a cancellable call */ + bool cancellable; /**< We are in a cancellable call */ }; /** * @brief Represents an Application Context on the Client side. @@ -324,6 +316,7 @@ struct _psContextMap typedef struct _psContextMap SCONTEXTMAP; static list_t contextMapList; +pthread_mutex_t contextMapList_lock; /**< lock for the above list */ static int SCONTEXTMAP_seeker(const void *el, const void *key) { @@ -346,7 +339,8 @@ static int SCONTEXTMAP_seeker(const void *el, const void *key) /** * Make sure the initialization code is executed only once. */ -static short isExecuted = 0; +static bool isExecuted = false; +static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT; /** @@ -359,13 +353,7 @@ static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER; * Area used to read status information about the readers. */ static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]; - -/** Protocol Control Information for T=0 */ -PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) }; -/** Protocol Control Information for T=1 */ -PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) }; -/** Protocol Control Information for raw access */ -PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, sizeof(SCARD_IO_REQUEST) }; +static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER; static LONG SCardAddContext(SCARDCONTEXT, DWORD); @@ -384,6 +372,7 @@ static void SCardRemoveHandle(SCARDHANDLE); static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen); +static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents); static LONG getReaderStates(SCONTEXTMAP * currentContextMap); static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap); static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap); @@ -418,10 +407,10 @@ inline static void SCardUnlockThread(void) * * @param[in] hContext Application Context whose index will be find. * - * @return \c TRUE if the context exists - * @return \c FALSE if the context does not exist + * @return \c true if the context exists + * @return \c false if the context does not exist */ -static int SCardGetContextValidity(SCARDCONTEXT hContext) +static bool SCardGetContextValidity(SCARDCONTEXT hContext) { SCONTEXTMAP * currentContextMap; @@ -440,8 +429,8 @@ static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, * * This must be the first WinSCard function called in a PC/SC application. * Each thread of an application shall use its own \ref SCARDCONTEXT, unless - * calling \ref SCardCancel(), which MUST be called with the same context as the - * context used to call \ref SCardGetStatusChange(). + * calling SCardCancel(), which MUST be called with the same context as the + * context used to call SCardGetStatusChange(). * * @ingroup API * @param[in] dwScope Scope of the establishment. @@ -460,6 +449,7 @@ static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, * @retval SCARD_E_INVALID_VALUE Invalid scope type passed (\ref SCARD_E_INVALID_VALUE ) * @retval SCARD_E_NO_MEMORY There is no free slot to store \p hContext (\ref SCARD_E_NO_MEMORY) * @retval SCARD_E_NO_SERVICE The server is not running (\ref SCARD_E_NO_SERVICE) + * @retval SCARD_E_SERVICE_STOPPED Wrong communication protocol version (\ref SCARD_E_SERVICE_STOPPED) * @retval SCARD_F_COMM_ERROR An internal communications error has been detected (\ref SCARD_F_COMM_ERROR) * @retval SCARD_F_INTERNAL_ERROR An internal consistency check failed (\ref SCARD_F_INTERNAL_ERROR) * @@ -498,10 +488,54 @@ LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, #ifdef DESTRUCTOR DESTRUCTOR static void destructor(void) { + (void)pthread_mutex_lock(&contextMapList_lock); list_destroy(&contextMapList); + (void)pthread_mutex_unlock(&contextMapList_lock); + + (void)pthread_mutex_destroy(&contextMapList_lock); } #endif +/* + * Do this only once: + * - Initialize context list. + */ +static void init_lib(void) +{ + int lrv; + + /* NOTE: The list will be freed only if DESTRUCTOR is defined. + * Applications which load and unload the library may leak + * the list's internal structures. */ + lrv = list_init(&contextMapList); + if (lrv < 0) + { + Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", + lrv); + return; + } + + lrv = list_attributes_seeker(&contextMapList, + SCONTEXTMAP_seeker); + if (lrv <0) + { + Log2(PCSC_LOG_CRITICAL, + "list_attributes_seeker failed with return value: %d", lrv); + list_destroy(&contextMapList); + return; + } + + if (SYS_GetEnv("PCSCLITE_NO_BLOCKING")) + { + Log1(PCSC_LOG_INFO, "Disable shared blocking"); + sharing_shall_block = false; + } + + (void)pthread_mutex_init(&contextMapList_lock, NULL); + + isExecuted = true; +} + /** * @brief Creates a communication context to the PC/SC Resource * Manager. @@ -536,6 +570,7 @@ static LONG SCardEstablishContextTH(DWORD dwScope, LONG rv; struct establish_struct scEstablishStruct; uint32_t dwClientID = 0; + struct version_struct veStr; (void)pvReserved1; (void)pvReserved2; @@ -544,44 +579,9 @@ static LONG SCardEstablishContextTH(DWORD dwScope, else *phContext = 0; - /* - * Do this only once: - * - Initialize context list. - */ - if (isExecuted == 0) - { - int lrv; - - /* NOTE: The list will be freed only if DESTRUCTOR is defined. - * Applications which load and unload the library may leak - * the list's internal structures. */ - lrv = list_init(&contextMapList); - if (lrv < 0) - { - Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", - lrv); - return SCARD_E_NO_MEMORY; - } - - lrv = list_attributes_seeker(&contextMapList, - SCONTEXTMAP_seeker); - if (lrv <0) - { - Log2(PCSC_LOG_CRITICAL, - "list_attributes_seeker failed with return value: %d", lrv); - list_destroy(&contextMapList); - return SCARD_E_NO_MEMORY; - } - - if (getenv("PCSCLITE_NO_BLOCKING")) - { - Log1(PCSC_LOG_INFO, "Disable shared blocking"); - sharing_shall_block = FALSE; - } - - isExecuted = 1; - } - + pthread_once(&init_lib_control, init_lib); + if (!isExecuted) + return SCARD_E_NO_MEMORY; /* Establishes a connection to the server */ if (ClientSetupSession(&dwClientID) != 0) @@ -589,37 +589,57 @@ static LONG SCardEstablishContextTH(DWORD dwScope, return SCARD_E_NO_SERVICE; } - { /* exchange client/server protocol versions */ - struct version_struct veStr; + veStr.major = PROTOCOL_VERSION_MAJOR; + veStr.minor = PROTOCOL_VERSION_MINOR; + +connect_again: + /* exchange client/server protocol versions */ - veStr.major = PROTOCOL_VERSION_MAJOR; - veStr.minor = PROTOCOL_VERSION_MINOR; - veStr.rv = SCARD_S_SUCCESS; + veStr.rv = SCARD_S_SUCCESS; - rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr), + rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr), &veStr); - if (rv != SCARD_S_SUCCESS) - goto cleanup; + if (rv != SCARD_S_SUCCESS) + goto cleanup; - /* Read a message from the server */ - rv = MessageReceive(&veStr, sizeof(veStr), dwClientID); - if (rv != SCARD_S_SUCCESS) - { - Log1(PCSC_LOG_CRITICAL, + /* Read a message from the server */ + rv = MessageReceive(&veStr, sizeof(veStr), dwClientID); + if (rv != SCARD_S_SUCCESS) + { + Log1(PCSC_LOG_CRITICAL, "Your pcscd is too old and does not support CMD_VERSION"); - goto cleanup; - } + goto cleanup; + } - Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d", + Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d", veStr.major, veStr.minor); + Log3(PCSC_LOG_INFO, "Client is protocol version %d:%d", + PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR); - if (veStr.rv != SCARD_S_SUCCESS) + if (SCARD_E_SERVICE_STOPPED == veStr.rv) + { + /* server complained about our protocol version? */ + if (PROTOCOL_VERSION_MAJOR == veStr.major) { - rv = veStr.rv; - goto cleanup; + if (PROTOCOL_VERSION_MINOR_CLIENT_BACKWARD <= veStr.minor) + { + /* try again with the protocol version proposed by + * the server */ + Log1(PCSC_LOG_INFO, "Using backward compatibility"); + goto connect_again; + } } } + if (veStr.rv != SCARD_S_SUCCESS) + { + rv = veStr.rv; + goto cleanup; + } + + /* store protocol version of the server */ + Protocol_version = veStr.major * 1000 + veStr.minor; + again: /* * Try to establish an Application Context with the server @@ -922,7 +942,7 @@ LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE) * @retval SCARD_E_INVALID_PARAMETER \p phContext is null. (\ref SCARD_E_INVALID_PARAMETER) - * @retval SCARD_E_INVALID_VALUE Invalid sharing mode, requested protocol, or reader name (\ref SCARD_E_INVALID_VALUE) + * @retval SCARD_E_INVALID_VALUE Invalid \p hCard, sharing mode, requested protocol, or reader name (\ref SCARD_E_INVALID_VALUE) * @retval SCARD_E_NO_SERVICE The server is not running (\ref SCARD_E_NO_SERVICE) * @retval SCARD_E_NO_SMARTCARD No smart card present (\ref SCARD_E_NO_SMARTCARD) * @retval SCARD_E_PROTO_MISMATCH Requested protocol is unknown (\ref SCARD_E_PROTO_MISMATCH) @@ -1113,13 +1133,13 @@ LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) /** * @brief Establishes a temporary exclusive access mode for - * doing a serie of commands in a transaction. + * doing a series of commands in a transaction. * * You might want to use this when you are selecting a few files and then * writing a large file so you can make sure that another application will * not change the current file. If another application has a lock on this - * reader or this application is in \ref SCARD_SHARE_EXCLUSIVE there will be no - * action taken. + * reader or this application is in \ref SCARD_SHARE_EXCLUSIVE the + * function will block until it can continue. * * @ingroup API * @param[in] hCard Connection made from SCardConnect(). @@ -1131,6 +1151,7 @@ LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE) * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION) * @retval SCARD_F_COMM_ERROR An internal communications error has been detected (\ref SCARD_F_COMM_ERROR) + * @retval SCARD_E_INVALID_VALUE An invalid value is used for \p hCard (for example the reader is no more present) (\ref SCARD_E_INVALID_VALUE) * * @code * SCARDCONTEXT hContext; @@ -1225,7 +1246,7 @@ LONG SCardBeginTransaction(SCARDHANDLE hCard) * @return Error code. * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS) * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE) - * @retval SCARD_E_INVALID_VALUE Invalid value for \p dwDisposition (\ref SCARD_E_INVALID_VALUE) + * @retval SCARD_E_INVALID_VALUE Invalid value for \p dwDisposition or \p hCard (\ref SCARD_E_INVALID_VALUE) * @retval SCARD_E_NO_SERVICE The server is not running (\ref SCARD_E_NO_SERVICE) * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE) * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION) @@ -1440,6 +1461,9 @@ LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, if (rv == -1) return SCARD_E_INVALID_HANDLE; + /* lock access to readerStates[] */ + (void)pthread_mutex_lock(&readerStatesMutex); + /* synchronize reader states with daemon */ rv = getReaderStates(currentContextMap); if (rv != SCARD_S_SUCCESS) @@ -1483,6 +1507,7 @@ LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv)) { (void)pthread_mutex_unlock(¤tContextMap->mMutex); + (void)pthread_mutex_unlock(&readerStatesMutex); (void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE); goto retry; } @@ -1565,6 +1590,7 @@ LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, end: (void)pthread_mutex_unlock(¤tContextMap->mMutex); + (void)pthread_mutex_unlock(&readerStatesMutex); PROFILE_END(rv) @@ -1589,11 +1615,15 @@ LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, * be used to detect a card removal/insertion between two calls to * SCardGetStatusChange() * - * To wait for a reader event (reader added or removed) you may use the special - * reader name \c "\\?PnP?\Notification". If a reader event occurs the state of - * this reader will change and the bit \ref SCARD_STATE_CHANGED will be set. + * To wait for a reader event (reader added or removed) you may use the + * special reader name \c "\\?PnP?\Notification". If a reader event + * occurs the state of this reader will change and the bit \ref + * SCARD_STATE_CHANGED will be set. + * To detect a reader event betweeen 2 calls to SCardGetStatusChange() + * you can use the upper 16 bits of \p dwCurrentState. See https://blog.apdu.fr/posts/2024/08/improved-scardgetstatuschange-for-pnpnotification-special-reader/ + * - * To cancel the ongoing call, use \ref SCardCancel() with the same + * To cancel the ongoing call, use SCardCancel() with the same * \ref SCARDCONTEXT. * * @code @@ -1689,14 +1719,16 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCONTEXTMAP * currentContextMap; int currentReaderCount = 0; LONG rv = SCARD_S_SUCCESS; + int pnp_reader = -1; PROFILE_START API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders) #ifdef DO_TRACE for (j=0; j= 0) + { + int readerEvents; + currReader = &rgReaderStates[pnp_reader]; + + /* PnP special reader */ + if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents)) + { + int previousReaderEvents = currReader->dwCurrentState >> 16; + + // store readerEvents in .dwEventState high word + currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16); + if ( + /* the value has changed since the last call */ + (previousReaderEvents != readerEvents) + /* backward compatibility: only if we had a non-null + * reader events value */ + && previousReaderEvents) + { + currReader->dwEventState |= SCARD_STATE_CHANGED; + rv = SCARD_S_SUCCESS; + dwBreakFlag = 1; + } + } + } + /* Get the initial reader count on the system */ for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++) if (readerStates[j].readerName[0] != '\0') @@ -1807,6 +1877,9 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, const char *readerName; int i; + /* lock access to readerStates[] */ + (void)pthread_mutex_lock(&readerStatesMutex); + /* Looks for correct readernames */ readerName = currReader->szReader; for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) @@ -1829,9 +1902,17 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, if (newReaderCount != currentReaderCount) { + int readerEvents; + Log1(PCSC_LOG_INFO, "Reader list changed"); currentReaderCount = newReaderCount; + if (SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents)) + { + // store readerEvents in .dwEventState high word + currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16); + } + currReader->dwEventState |= SCARD_STATE_CHANGED; dwBreakFlag = 1; } @@ -2052,6 +2133,8 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, dwBreakFlag = 1; } } /* End of SCARD_STATE_UNKNOWN */ + + (void)pthread_mutex_unlock(&readerStatesMutex); } /* End of SCARD_STATE_IGNORE */ /* Counter and resetter */ @@ -2077,7 +2160,7 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, waitStatusStruct.rv = SCARD_S_SUCCESS; /* another thread can do SCardCancel() */ - currentContextMap->cancellable = TRUE; + currentContextMap->cancellable = true; /* * Read a message from the server @@ -2086,9 +2169,9 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, &waitStatusStruct, sizeof(waitStatusStruct), currentContextMap->dwClientID, dwTime); - /* SCardCancel() will return immediatly with success + /* SCardCancel() will return immediately with success * because something changed on the daemon side. */ - currentContextMap->cancellable = FALSE; + currentContextMap->cancellable = false; /* timeout */ if (SCARD_E_TIMEOUT == rv) @@ -2108,7 +2191,9 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, } /* synchronize reader states with daemon */ + (void)pthread_mutex_lock(&readerStatesMutex); rv = getReaderStatesAndRegisterForEvents(currentContextMap); + (void)pthread_mutex_unlock(&readerStatesMutex); if (rv != SCARD_S_SUCCESS) goto end; @@ -2152,8 +2237,9 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, #ifdef DO_TRACE for (j=0; j + * * Click here for a list of supported commands by some drivers. * @param[in] pbSendBuffer Command to send to the reader. * @param[in] cbSendLength Length of the command. @@ -2338,7 +2424,7 @@ LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, * - \ref SCARD_ATTR_DEVICE_FRIENDLY_NAME * Implemented by pcsc-lite if the IFD Handler (driver) returns \ref * IFD_ERROR_TAG. pcsc-lite then returns the same reader name as - * returned by \ref SCardListReaders(). + * returned by SCardListReaders(). * - \ref SCARD_ATTR_DEVICE_IN_USE * - \ref SCARD_ATTR_DEVICE_SYSTEM_NAME * - \ref SCARD_ATTR_DEVICE_UNIT @@ -2384,6 +2470,7 @@ LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, * @retval SCARD_E_NO_SERVICE The server is not running (\ref SCARD_E_NO_SERVICE) * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE) * @retval SCARD_F_COMM_ERROR An internal communications error has been detected (\ref SCARD_F_COMM_ERROR) + * @retval SCARD_E_INVALID_VALUE An invalid value is used for \p hCard (for example the reader is no more present) (\ref SCARD_E_INVALID_VALUE) * * @code * LONG rv; @@ -2579,7 +2666,7 @@ static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId, if (*pcbAttrLen < scGetSetStruct.cbAttrLen) { /* restrict the value of scGetSetStruct.cbAttrLen to avoid a - * buffer overflow in the memcpy() bellow */ + * buffer overflow in the memcpy() below */ DWORD correct_value = scGetSetStruct.cbAttrLen; scGetSetStruct.cbAttrLen = *pcbAttrLen; *pcbAttrLen = correct_value; @@ -2634,7 +2721,7 @@ static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId, * @retval SCARD_E_INSUFFICIENT_BUFFER \p cbRecvLength was not large enough for the card response. The expected size is now in \p cbRecvLength (\ref SCARD_E_INSUFFICIENT_BUFFER) * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE) * @retval SCARD_E_INVALID_PARAMETER \p pbSendBuffer or \p pbRecvBuffer or \p pcbRecvLength or \p pioSendPci is null (\ref SCARD_E_INVALID_PARAMETER) - * @retval SCARD_E_INVALID_VALUE Invalid Protocol, reader name, etc (\ref SCARD_E_INVALID_VALUE) + * @retval SCARD_E_INVALID_VALUE Invalid \p hCard, Protocol, reader name, etc (\ref SCARD_E_INVALID_VALUE) * @retval SCARD_E_NO_SERVICE The server is not running (\ref SCARD_E_NO_SERVICE) * @retval SCARD_E_NOT_TRANSACTED APDU exchange not successful (\ref SCARD_E_NOT_TRANSACTED) * @retval SCARD_E_PROTO_MISMATCH Connect protocol is different than desired (\ref SCARD_E_PROTO_MISMATCH) @@ -2793,6 +2880,10 @@ LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, * Encoding: * The reader names and group names are encoded using UTF-8. * + * The reader names is a multi-string and separated by a null character + * (\c '\0') and ended by a double null character like + * \c "Reader foo 00 00\0Reader bar 01 00\0\0". + * * @ingroup API * @param[in] hContext Connection context to the PC/SC Resource Manager. * @param[in] mszGroups List of groups to list readers (not used). @@ -2870,6 +2961,9 @@ LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups, return SCARD_E_INVALID_HANDLE; } + /* lock access to readerStates[] */ + (void)pthread_mutex_lock(&readerStatesMutex); + /* synchronize reader states with daemon */ rv = getReaderStates(currentContextMap); if (rv != SCARD_S_SUCCESS) @@ -2937,6 +3031,7 @@ LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups, *pcchReaders = dwReadersLen; (void)pthread_mutex_unlock(¤tContextMap->mMutex); + (void)pthread_mutex_unlock(&readerStatesMutex); PROFILE_END(rv) API_TRACE_OUT("%d", *pcchReaders) @@ -3087,8 +3182,8 @@ LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, } /** - * Cancels a specific blocking \ref SCardGetStatusChange() function. - * MUST be called with the same \ref SCARDCONTEXT as \ref + * Cancels a specific blocking SCardGetStatusChange() function. + * MUST be called with the same \ref SCARDCONTEXT as * SCardGetStatusChange(). * * @ingroup API @@ -3123,7 +3218,7 @@ LONG SCardCancel(SCARDCONTEXT hContext) LONG rv = SCARD_S_SUCCESS; uint32_t dwClientID = 0; struct cancel_struct scCancelStruct; - char cancellable; + bool cancellable; PROFILE_START API_TRACE_IN("%ld", hContext) @@ -3256,7 +3351,7 @@ static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID) Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap); newContextMap->hContext = hContext; newContextMap->dwClientID = dwClientID; - newContextMap->cancellable = FALSE; + newContextMap->cancellable = false; (void)pthread_mutex_init(&newContextMap->mMutex, NULL); @@ -3277,7 +3372,9 @@ static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID) goto error; } + (void)pthread_mutex_lock(&contextMapList_lock); lrv = list_append(&contextMapList, newContextMap); + (void)pthread_mutex_unlock(&contextMapList_lock); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d", @@ -3342,7 +3439,13 @@ static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT hContext) */ static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT hContext) { - return list_seek(&contextMapList, &hContext); + SCONTEXTMAP * currentContextMap; + + (void)pthread_mutex_lock(&contextMapList_lock); + currentContextMap = list_seek(&contextMapList, &hContext); + (void)pthread_mutex_unlock(&contextMapList_lock); + + return currentContextMap; } /** @@ -3391,7 +3494,9 @@ static void SCardCleanContext(SCONTEXTMAP * targetContextMap) } list_destroy(&targetContextMap->channelMapList); + (void)pthread_mutex_lock(&contextMapList_lock); lrv = list_delete(&contextMapList, targetContextMap); + (void)pthread_mutex_unlock(&contextMapList_lock); if (lrv < 0) { Log2(PCSC_LOG_CRITICAL, @@ -3482,6 +3587,7 @@ static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard, static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard, SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap) { + LONG rv = -1; int listSize; int list_index; SCONTEXTMAP * currentContextMap; @@ -3491,6 +3597,7 @@ static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard, *targetContextMap = NULL; *targetChannelMap = NULL; + (void)pthread_mutex_lock(&contextMapList_lock); listSize = list_size(&contextMapList); for (list_index = 0; list_index < listSize; list_index++) @@ -3508,11 +3615,14 @@ static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard, { *targetContextMap = currentContextMap; *targetChannelMap = currentChannelMap; - return SCARD_S_SUCCESS; + rv = SCARD_S_SUCCESS; + break; } } - return -1; + (void)pthread_mutex_unlock(&contextMapList_lock); + + return rv; } /** @@ -3541,6 +3651,30 @@ LONG SCardCheckDaemonAvailability(void) return SCARD_S_SUCCESS; } +static LONG getReaderEvents(SCONTEXTMAP * currentContextMap, int *readerEvents) +{ + int32_t dwClientID = currentContextMap->dwClientID; + LONG rv; + struct get_reader_events get_reader_events = {0}; + + /* CMD_GET_READER_EVENTS was added in protocol 4:5 */ + if (Protocol_version < 4005) + return SCARD_E_UNSUPPORTED_FEATURE; + + rv = MessageSendWithHeader(CMD_GET_READER_EVENTS, dwClientID, 0, NULL); + if (rv != SCARD_S_SUCCESS) + return rv; + + /* Read a message from the server */ + rv = MessageReceive(&get_reader_events, sizeof(get_reader_events), dwClientID); + if (rv != SCARD_S_SUCCESS) + return rv; + + *readerEvents = get_reader_events.readerEvents; + + return SCARD_S_SUCCESS; +} + static LONG getReaderStates(SCONTEXTMAP * currentContextMap) { int32_t dwClientID = currentContextMap->dwClientID; diff --git a/src/winscard_msg.c b/src/winscard_msg.c index c5216eff..a1eb6dba 100644 --- a/src/winscard_msg.c +++ b/src/winscard_msg.c @@ -5,7 +5,7 @@ * David Corcoran * Copyright (C) 2003-2004 * Damien Sauveron - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2024 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -56,9 +56,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#ifdef HAVE_SYS_FILIO_H -#include -#endif #include "misc.h" #include "pcscd.h" @@ -82,26 +79,27 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define member_size(type, member) sizeof(((type *)0)->member) -char *getSocketName(void) +static char SocketName[member_size(struct sockaddr_un, sun_path)]; +static pthread_once_t SocketName_init_control = PTHREAD_ONCE_INIT; +static void SocketName_init(void) { - static char socketName[member_size(struct sockaddr_un, sun_path)]; + /* socket name not yet initialized */ + const char *socketNameEnv; - if ('\0' == socketName[0]) - { - /* socket name not yet initialized */ - char *socketNameEnv; - - socketNameEnv = getenv("PCSCLITE_CSOCK_NAME"); - if (socketNameEnv) - strncpy(socketName, socketNameEnv, sizeof(socketName)); - else - strncpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName)); + socketNameEnv = SYS_GetEnv("PCSCLITE_CSOCK_NAME"); + if (socketNameEnv) + strncpy(SocketName, socketNameEnv, sizeof SocketName); + else + strncpy(SocketName, PCSCLITE_CSOCK_NAME, sizeof SocketName); - /* Ensure a NUL byte */ - socketName[sizeof socketName -1] = '\0'; - } + /* Ensure a NUL byte */ + SocketName[sizeof SocketName -1] = '\0'; +} - return socketName; +char *getSocketName(void) +{ + pthread_once(&SocketName_init_control, SocketName_init); + return SocketName; } /** @@ -178,7 +176,7 @@ INTERNAL void ClientCloseSession(uint32_t dwClientID) } /** - * @brief Called by the Client to get the reponse from the server or vice-versa. + * @brief Called by the Client to get the response from the server or vice-versa. * * Reads the message from the file \c filedes. * @@ -240,7 +238,7 @@ INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, /* try to read only when socket is readable */ if (pollret > 0) { - int readed; + ssize_t bytes_read; if (!(read_fd.revents & POLLIN)) { @@ -248,14 +246,14 @@ INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, retval = SCARD_F_COMM_ERROR; break; } - readed = read(filedes, buffer, remaining); + bytes_read = read(filedes, buffer, remaining); - if (readed > 0) + if (bytes_read > 0) { /* we got something */ - buffer += readed; - remaining -= readed; - } else if (readed == 0) + buffer += bytes_read; + remaining -= bytes_read; + } else if (bytes_read == 0) { /* peer closed the socket */ retval = SCARD_F_COMM_ERROR; @@ -380,7 +378,7 @@ INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, /* try to write only when the file descriptor is writable */ if (pollret > 0) { - int written; + ssize_t written; if (!(write_fd.revents & POLLOUT)) { @@ -441,7 +439,7 @@ INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, } /** - * @brief Called by the Client to get the reponse from the server or vice-versa. + * @brief Called by the Client to get the response from the server or vice-versa. * * Reads the message from the file \c filedes. * @@ -480,7 +478,7 @@ INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, /* try to read only when socket is readable */ if (pollret > 0) { - int readed; + ssize_t bytes_read; if (!(read_fd.revents & POLLIN)) { @@ -488,14 +486,14 @@ INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, retval = SCARD_F_COMM_ERROR; break; } - readed = read(filedes, buffer, remaining); + bytes_read = read(filedes, buffer, remaining); - if (readed > 0) + if (bytes_read > 0) { /* we got something */ - buffer += readed; - remaining -= readed; - } else if (readed == 0) + buffer += bytes_read; + remaining -= bytes_read; + } else if (bytes_read == 0) { /* peer closed the socket */ retval = SCARD_F_COMM_ERROR; @@ -506,7 +504,7 @@ INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, * other errors are fatal */ if (errno != EINTR && errno != EAGAIN) { - /* connection reseted by pcscd? */ + /* connection reset by pcscd? */ if (ECONNRESET == errno) retval = SCARD_W_SECURITY_VIOLATION; else diff --git a/src/winscard_msg.h b/src/winscard_msg.h index 3efd4d66..1a5f8b71 100644 --- a/src/winscard_msg.h +++ b/src/winscard_msg.h @@ -5,7 +5,7 @@ * David Corcoran * Copyright (C) 2003-2004 * Damien Sauveron - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2025 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -49,7 +49,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** Major version of the current message protocol */ #define PROTOCOL_VERSION_MAJOR 4 /** Minor version of the current message protocol */ -#define PROTOCOL_VERSION_MINOR 4 +#define PROTOCOL_VERSION_MINOR 5 +/** Minor version the client also supports */ +#define PROTOCOL_VERSION_MINOR_CLIENT_BACKWARD 4 +/** Minor version the server also supports */ +#define PROTOCOL_VERSION_MINOR_SERVER_BACKWARD 4 /** * @brief Information transmitted in \ref CMD_VERSION Messages. @@ -96,6 +100,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. CMD_GET_READERS_STATE = 0x12, /**< get the readers state */ CMD_WAIT_READER_STATE_CHANGE = 0x13, /**< wait for a reader state change */ CMD_STOP_WAITING_READER_STATE_CHANGE = 0x14, /**< stop waiting for a reader state change */ + CMD_GET_READER_EVENTS = 0x15, /**< get the number of reader events */ CMD_ENUM_LAST }; @@ -270,6 +275,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. uint32_t rv; }; + struct get_reader_events + { + uint32_t readerEvents; + uint32_t rv; + }; + /* * Now some function definitions */ diff --git a/src/winscard_msg_srv.c b/src/winscard_msg_srv.c index 126e7d2a..0b44bbcf 100644 --- a/src/winscard_msg_srv.c +++ b/src/winscard_msg_srv.c @@ -5,7 +5,7 @@ * David Corcoran * Copyright (C) 2003-2004 * Damien Sauveron - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2023 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without @@ -54,9 +54,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#ifdef HAVE_SYS_FILIO_H -#include -#endif #ifdef USE_LIBSYSTEMD #include #endif @@ -68,7 +65,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "winscard_msg.h" /** - * Socket to a file, used for clients-server comminication. + * Socket to a file, used for clients-server communication. */ static int commonSocket = 0; extern char AraKiri; diff --git a/src/winscard_svc.c b/src/winscard_svc.c index 6149f4ee..6189193a 100644 --- a/src/winscard_svc.c +++ b/src/winscard_svc.c @@ -5,7 +5,7 @@ * David Corcoran * Copyright (C) 2003-2004 * Damien Sauveron - * Copyright (C) 2002-2011 + * Copyright (C) 2002-2025 * Ludovic Rousseau * Copyright (C) 2009 * Jean-Luc Giraud @@ -52,6 +52,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "pcscd.h" #include "winscard.h" @@ -71,7 +72,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * An Application Context contains Channels (\c hCard). */ -extern char AutoExit; +extern bool AutoExit; static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS; static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES; @@ -98,6 +99,7 @@ static void MSGCleanupClient(SCONTEXT *); static void * ContextThread(LPVOID pdwIndex); extern READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]; +extern int16_t ReaderEvents; static int contextsListhContext_seeker(const void *el, const void *key) { @@ -148,14 +150,33 @@ LONG ContextsInitialize(int customMaxThreadCounter, void ContextsDeinitialize(void) { int listSize; + (void)pthread_mutex_lock(&contextsList_lock); listSize = list_size(&contextsList); #ifdef NO_LOG (void)listSize; #endif Log2(PCSC_LOG_DEBUG, "remaining threads: %d", listSize); - /* This is currently a no-op. It should terminate the threads properly. */ + /* terminate all the client threads */ + int rv = list_iterator_start(&contextsList); + if (0 == rv) + Log1(PCSC_LOG_ERROR, "list_iterator_start failed"); + else + { + while (list_iterator_hasnext(&contextsList)) + { + SCONTEXT * elt = list_iterator_next(&contextsList); + Log3(PCSC_LOG_DEBUG, "Cancel dwClientID=%d hContext: %p", + elt->dwClientID, elt); + EHTryToUnregisterClientForEvent(elt->dwClientID); + close(elt->dwClientID); + Log2(PCSC_LOG_DEBUG, "Waiting client: %d", elt->dwClientID); + pthread_join(elt->pthThread, NULL); + Log2(PCSC_LOG_INFO, "Client %d terminated", elt->dwClientID); + } + } list_destroy(&contextsList); + (void)pthread_mutex_unlock(&contextsList_lock); } /** @@ -165,7 +186,7 @@ void ContextsDeinitialize(void) * * @return Error code. * @retval SCARD_S_SUCCESS Success. - * @retval SCARD_F_INTERNAL_ERROR Exceded the maximum number of simultaneous Application Contexts. + * @retval SCARD_F_INTERNAL_ERROR Exceeded the maximum number of simultaneous Application Contexts. * @retval SCARD_E_NO_MEMORY Error creating the Context Thread. */ LONG CreateContextThread(uint32_t *pdwClientID) @@ -209,7 +230,7 @@ LONG CreateContextThread(uint32_t *pdwClientID) /* 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 + * useful even on a 64-bit CPU since the API between pcscd and * libpcscliter uses "int32_t hCard;" */ lrv = list_attributes_comparator(&newContext->cardsList, @@ -276,7 +297,7 @@ LONG CreateContextThread(uint32_t *pdwClientID) * * For each Client message a new instance of this thread is created. * - * @param[in] dwIndex Index of an avaiable Application Context slot in + * @param[in] dwIndex Index of an available Application Context slot in * \c SCONTEXT *. */ #ifndef NO_LOG @@ -302,6 +323,7 @@ static const char *CommandsText[] = { "CMD_GET_READERS_STATE", "CMD_WAIT_READER_STATE_CHANGE", "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */ + "CMD_GET_READER_EVENTS", "NULL" }; #endif @@ -385,7 +407,11 @@ static void * ContextThread(LPVOID newContext) veStr.major, veStr.minor); Log3(PCSC_LOG_ERROR, "Server protocol is %d:%d", PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR); - veStr.rv = SCARD_E_SERVICE_STOPPED; + + if (veStr.minor < PROTOCOL_VERSION_MINOR_SERVER_BACKWARD) + veStr.rv = SCARD_E_SERVICE_STOPPED; + else + Log1(PCSC_LOG_INFO, "Enable backward compatibility"); } /* set the server protocol version */ @@ -430,7 +456,7 @@ static void * ContextThread(LPVOID newContext) struct wait_reader_state_change waStr = { .timeOut = 0, - .rv = 0 + .rv = SCARD_S_SUCCESS }; LONG rv; @@ -447,6 +473,20 @@ static void * ContextThread(LPVOID newContext) } break; + case CMD_GET_READER_EVENTS: + { + /* nothing to read */ + + struct get_reader_events readerEvents = + { + .readerEvents = ReaderEvents, + .rv = SCARD_S_SUCCESS + }; + + WRITE_BODY(readerEvents); + } + break; + case SCARD_ESTABLISH_CONTEXT: { struct establish_struct esStr; @@ -496,16 +536,19 @@ static void * ContextThread(LPVOID newContext) if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0) { Log2(PCSC_LOG_CRITICAL, "Rejected unauthorized client for '%s'", coStr.szReader); - goto exit; + + coStr.rv = SCARD_W_SECURITY_VIOLATION; + hCard = -1; + dwActiveProtocol = -1; } else { Log2(PCSC_LOG_DEBUG, "Authorized client for '%s'", coStr.szReader); - } - coStr.rv = SCardConnect(coStr.hContext, coStr.szReader, - coStr.dwShareMode, coStr.dwPreferredProtocols, - &hCard, &dwActiveProtocol); + coStr.rv = SCardConnect(coStr.hContext, coStr.szReader, + coStr.dwShareMode, coStr.dwPreferredProtocols, + &hCard, &dwActiveProtocol); + } coStr.hCard = hCard; coStr.dwActiveProtocol = dwActiveProtocol; @@ -620,6 +663,8 @@ static void * ContextThread(LPVOID newContext) /* signal the client only if it was still waiting */ if (SCARD_S_SUCCESS == rv) caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED); + else + caStr.rv = SCARD_S_SUCCESS; } WRITE_BODY(caStr); @@ -682,7 +727,7 @@ static void * ContextThread(LPVOID newContext) if (cbRecvLength > trStr.pcbRecvLength) /* The client buffer is not large enough. * The pbRecvBuffer buffer will NOT be sent a few - * lines bellow. So no buffer overflow is expected. */ + * lines below. So no buffer overflow is expected. */ trStr.rv = SCARD_E_INSUFFICIENT_BUFFER; trStr.ioSendPciProtocol = ioSendPci.dwProtocol; @@ -735,7 +780,7 @@ static void * ContextThread(LPVOID newContext) if (dwBytesReturned > ctStr.cbRecvLength) /* The client buffer is not large enough. * The pbRecvBuffer buffer will NOT be sent a few - * lines bellow. So no buffer overflow is expected. */ + * lines below. So no buffer overflow is expected. */ ctStr.rv = SCARD_E_INSUFFICIENT_BUFFER; ctStr.dwBytesReturned = dwBytesReturned; @@ -824,7 +869,7 @@ LONG MSGSignalClient(uint32_t filedes, LONG rv) struct wait_reader_state_change waStr = { .timeOut = 0, - .rv = 0 + .rv = SCARD_S_SUCCESS }; Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes); @@ -1051,7 +1096,7 @@ static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, /* Should be called just prior to exiting the thread as it de-allocates - * the thread memory strucutres + * the thread memory structures */ static void MSGCleanupClient(SCONTEXT * threadContext) { diff --git a/src/winscard_svc.h b/src/winscard_svc.h index 54b5c36b..f4d34a0c 100644 --- a/src/winscard_svc.h +++ b/src/winscard_svc.h @@ -5,7 +5,7 @@ * David Corcoran * Copyright (C) 2003-2004 * Damien Sauveron - * Copyright (C) 2002-2010 + * Copyright (C) 2002-2018 * Ludovic Rousseau * Redistribution and use in source and binary forms, with or without