aboutsummaryrefslogtreecommitdiffstats
path: root/scd/pcsc-wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/pcsc-wrapper.c')
-rw-r--r--scd/pcsc-wrapper.c631
1 files changed, 0 insertions, 631 deletions
diff --git a/scd/pcsc-wrapper.c b/scd/pcsc-wrapper.c
deleted file mode 100644
index 4f47ee95c..000000000
--- a/scd/pcsc-wrapper.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/* pcsc-wrapper.c - Wrapper for ccessing the PC/SC service
- * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-/*
- This wrapper is required to handle problems with the libpscslite
- library. That library assumes that pthreads are used and fails
- badly if one tries to use it with a procerss using Pth.
-
- The operation model is pretty simple: It reads requests from stdin
- and returns the answer on stdout. There is no direct mapping to the
- pcsc interface but to a higher level one which resembles the code
- used in scdaemon (apdu.c) when not using Pth or while running under
- Windows.
-
- The interface is binary consisting of a command tag and the length
- of the parameter list. The calling process needs to pass the
- version number of the interface on the command line to make sure
- that both agree on the same interface. For each port a separate
- instance of this process needs to be started.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <dlfcn.h>
-
-
-#define PGM "pcsc-wrapper"
-
-/* Allow for a standalone build. */
-#ifdef VERSION
-#define MYVERSION_LINE PGM " (GnuPG) " VERSION
-#define BUGREPORT_LINE "\nReport bugs to <[email protected]>.\n"
-#else
-#define MYVERSION_LINE PGM
-#define BUGREPORT_LINE ""
-#endif
-
-#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
-
-
-static int verbose;
-
-
-/* PC/SC constants and function pointer. */
-#define PCSC_SCOPE_USER 0
-#define PCSC_SCOPE_TERMINAL 1
-#define PCSC_SCOPE_SYSTEM 2
-#define PCSC_SCOPE_GLOBAL 3
-
-#define PCSC_PROTOCOL_T0 1
-#define PCSC_PROTOCOL_T1 2
-#define PCSC_PROTOCOL_RAW 4
-
-#define PCSC_SHARE_EXCLUSIVE 1
-#define PCSC_SHARE_SHARED 2
-#define PCSC_SHARE_DIRECT 3
-
-#define PCSC_LEAVE_CARD 0
-#define PCSC_RESET_CARD 1
-#define PCSC_UNPOWER_CARD 2
-#define PCSC_EJECT_CARD 3
-
-struct pcsc_io_request_s {
- unsigned long protocol;
- unsigned long pci_len;
-};
-
-typedef struct pcsc_io_request_s *pcsc_io_request_t;
-
-
-static int driver_is_open; /* True if the PC/SC driver has been
- initialzied and is ready for
- operations. The follwoing variables
- are then valid. */
-static unsigned long pcsc_context; /* The current PC/CS context. */
-static unsigned long pcsc_card;
-static unsigned long pcsc_protocol;
-static unsigned char current_atr[33];
-static size_t current_atrlen;
-
-long (* pcsc_establish_context) (unsigned long scope,
- const void *reserved1,
- const void *reserved2,
- unsigned long *r_context);
-long (* pcsc_release_context) (unsigned long context);
-long (* pcsc_list_readers) (unsigned long context,
- const char *groups,
- char *readers, unsigned long*readerslen);
-long (* pcsc_connect) (unsigned long context,
- const char *reader,
- unsigned long share_mode,
- unsigned long preferred_protocols,
- unsigned long *r_card,
- unsigned long *r_active_protocol);
-long (* pcsc_disconnect) (unsigned long card,
- unsigned long disposition);
-long (* pcsc_status) (unsigned long card,
- char *reader, unsigned long *readerlen,
- unsigned long *r_state,
- unsigned long *r_protocol,
- unsigned char *atr, unsigned long *atrlen);
-long (* pcsc_begin_transaction) (unsigned long card);
-long (* pcsc_end_transaction) (unsigned long card);
-long (* pcsc_transmit) (unsigned long card,
- const pcsc_io_request_t send_pci,
- const unsigned char *send_buffer,
- unsigned long send_len,
- pcsc_io_request_t recv_pci,
- unsigned char *recv_buffer,
- unsigned long *recv_len);
-long (* pcsc_set_timeout) (unsigned long context,
- unsigned long timeout);
-
-
-
-static void
-bad_request (const char *type)
-{
- fprintf (stderr, PGM ": bad `%s' request\n", type);
- exit (1);
-}
-
-static void
-request_failed (int err)
-{
- if (!err)
- err = -1;
-
- putchar (0x81); /* Simple error/success response. */
-
- putchar (0);
- putchar (0);
- putchar (0);
- putchar (4);
-
- putchar ((err >> 24) & 0xff);
- putchar ((err >> 16) & 0xff);
- putchar ((err >> 8) & 0xff);
- putchar ((err ) & 0xff);
-
- fflush (stdout);
-}
-
-
-static void
-request_succeeded (const void *buffer, size_t buflen)
-{
- size_t len;
-
- putchar (0x81); /* Simple error/success response. */
-
- len = 4 + buflen;
- putchar ((len >> 24) & 0xff);
- putchar ((len >> 16) & 0xff);
- putchar ((len >> 8) & 0xff);
- putchar ((len ) & 0xff);
-
- /* Error code. */
- putchar (0);
- putchar (0);
- putchar (0);
- putchar (0);
-
- /* Optional reponse string. */
- if (buffer)
- fwrite (buffer, buflen, 1, stdout);
-
- fflush (stdout);
-}
-
-
-
-static unsigned long
-read_32 (FILE *fp)
-{
- int c1, c2, c3, c4;
-
- c1 = getc (stdin);
- c2 = getc (stdin);
- c3 = getc (stdin);
- c4 = getc (stdin);
- if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
- {
- fprintf (stderr, PGM ": premature EOF while parsing request\n");
- exit (1);
- }
- return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
-}
-
-
-
-static const char *
-pcsc_error_string (long err)
-{
- const char *s;
-
- if (!err)
- return "okay";
- if ((err & 0x80100000) != 0x80100000)
- return "invalid PC/SC error code";
- err &= 0xffff;
- switch (err)
- {
- case 0x0002: s = "cancelled"; break;
- case 0x000e: s = "can't dispose"; break;
- case 0x0008: s = "insufficient buffer"; break;
- case 0x0015: s = "invalid ATR"; break;
- case 0x0003: s = "invalid handle"; break;
- case 0x0004: s = "invalid parameter"; break;
- case 0x0005: s = "invalid target"; break;
- case 0x0011: s = "invalid value"; break;
- case 0x0006: s = "no memory"; break;
- case 0x0013: s = "comm error"; break;
- case 0x0001: s = "internal error"; break;
- case 0x0014: s = "unknown error"; break;
- case 0x0007: s = "waited too long"; break;
- case 0x0009: s = "unknown reader"; break;
- case 0x000a: s = "timeout"; break;
- case 0x000b: s = "sharing violation"; break;
- case 0x000c: s = "no smartcard"; break;
- case 0x000d: s = "unknown card"; break;
- case 0x000f: s = "proto mismatch"; break;
- case 0x0010: s = "not ready"; break;
- case 0x0012: s = "system cancelled"; break;
- case 0x0016: s = "not transacted"; break;
- case 0x0017: s = "reader unavailable"; break;
- case 0x0065: s = "unsupported card"; break;
- case 0x0066: s = "unresponsive card"; break;
- case 0x0067: s = "unpowered card"; break;
- case 0x0068: s = "reset card"; break;
- case 0x0069: s = "removed card"; break;
- case 0x006a: s = "inserted card"; break;
- case 0x001f: s = "unsupported feature"; break;
- case 0x0019: s = "PCI too small"; break;
- case 0x001a: s = "reader unsupported"; break;
- case 0x001b: s = "duplicate reader"; break;
- case 0x001c: s = "card unsupported"; break;
- case 0x001d: s = "no service"; break;
- case 0x001e: s = "service stopped"; break;
- default: s = "unknown PC/SC error code"; break;
- }
- return s;
-}
-
-static void
-load_pcsc_driver (const char *libname)
-{
- void *handle;
-
- handle = dlopen (libname, RTLD_LAZY);
- if (!handle)
- {
- fprintf (stderr, PGM ": failed to open driver `%s': %s",
- libname, dlerror ());
- exit (1);
- }
-
- pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
- pcsc_release_context = dlsym (handle, "SCardReleaseContext");
- pcsc_list_readers = dlsym (handle, "SCardListReaders");
- pcsc_connect = dlsym (handle, "SCardConnect");
- pcsc_disconnect = dlsym (handle, "SCardDisconnect");
- pcsc_status = dlsym (handle, "SCardStatus");
- pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
- pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
- pcsc_transmit = dlsym (handle, "SCardTransmit");
- pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
-
- if (!pcsc_establish_context
- || !pcsc_release_context
- || !pcsc_list_readers
- || !pcsc_connect
- || !pcsc_disconnect
- || !pcsc_status
- || !pcsc_begin_transaction
- || !pcsc_end_transaction
- || !pcsc_transmit
- /* || !pcsc_set_timeout */)
- {
- /* Note that set_timeout is currently not used and also not
- available under Windows. */
- fprintf (stderr,
- "apdu_open_reader: invalid PC/SC driver "
- "(%d%d%d%d%d%d%d%d%d%d)\n",
- !!pcsc_establish_context,
- !!pcsc_release_context,
- !!pcsc_list_readers,
- !!pcsc_connect,
- !!pcsc_disconnect,
- !!pcsc_status,
- !!pcsc_begin_transaction,
- !!pcsc_end_transaction,
- !!pcsc_transmit,
- !!pcsc_set_timeout );
- dlclose (handle);
- exit (1);
- }
-}
-
-
-
-
-/* Handle a open request. The argument is expected to be a string
- with the port indentification. ARGBUF is always guaranteed to be
- terminted by a 0 which is not counted in ARGLEN. We may modifiy
- ARGBUF. */
-static void
-handle_open (unsigned char *argbuf, size_t arglen)
-{
- long err;
- const char * portstr;
- char *list = NULL;
- unsigned long nreader, listlen, atrlen;
- char *p;
- unsigned long card_state, card_protocol;
- unsigned char atr[33];
-
- /* Make sure there is only the port string */
- if (arglen != strlen (argbuf))
- bad_request ("OPEN");
- portstr = argbuf;
-
- if (driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has already been opened\n");
- request_failed (-1);
- }
-
- err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
-
- err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
- if (!err)
- {
- list = malloc (nreader+1); /* Better add 1 for safety reasons. */
- if (!list)
- {
- fprintf (stderr, PGM": error allocating memory for reader list\n");
- exit (1);
- }
- err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
- }
- if (err)
- {
- fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (pcsc_context);
- free (list);
- request_failed (err);
- return;
- }
-
- listlen = nreader;
- p = list;
- while (nreader)
- {
- if (!*p && !p[1])
- break;
- fprintf (stderr, PGM": detected reader `%s'\n", p);
- if (nreader < (strlen (p)+1))
- {
- fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
- break;
- }
- nreader -= strlen (p)+1;
- p += strlen (p) + 1;
- }
-
- err = pcsc_connect (pcsc_context,
- portstr && *portstr? portstr : list,
- PCSC_SHARE_EXCLUSIVE,
- PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
- &pcsc_card,
- &pcsc_protocol);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (pcsc_context);
- free (list);
- request_failed (err);
- return;
- }
-
- atrlen = 32;
- /* (We need to pass a dummy buffer. We use LIST because it ought to
- be large enough.) */
- err = pcsc_status (pcsc_card,
- list, &listlen,
- &card_state, &card_protocol,
- atr, &atrlen);
- free (list);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (pcsc_context);
- request_failed (err);
- return;
- }
- if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
- {
- fprintf (stderr, PGM": ATR returned by pcsc_status is too large\n");
- exit (4);
- }
- memcpy (current_atr, atr, atrlen);
- current_atrlen = atrlen;
- driver_is_open = 1;
- request_succeeded (current_atr, current_atrlen);
-}
-
-
-
-/* Handle a close request. We expect no arguments. We may modifiy
- ARGBUF. */
-static void
-handle_close (unsigned char *argbuf, size_t arglen)
-{
- if (!driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
- request_failed (-1);
- }
-
- pcsc_release_context (pcsc_context);
-
- request_succeeded (NULL, 0);
-}
-
-
-
-/* Handle a transmit request. The argument is expected to be a bufer
- with the APDU. We may modifiy ARGBUF. */
-static void
-handle_transmit (unsigned char *argbuf, size_t arglen)
-{
- long err;
- struct pcsc_io_request_s send_pci;
- unsigned long recv_len;
- unsigned char buffer[1024];
-
- /* The apdu should at least be one byte. */
- if (!arglen)
- bad_request ("TRANSMIT");
-
- if (!driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
- request_failed (-1);
- }
-
- if ((pcsc_protocol & PCSC_PROTOCOL_T1))
- send_pci.protocol = PCSC_PROTOCOL_T1;
- else
- send_pci.protocol = PCSC_PROTOCOL_T0;
- send_pci.pci_len = sizeof send_pci;
- recv_len = sizeof (buffer);
- err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
- NULL, buffer, &recv_len);
- if (err)
- {
- if (verbose)
- fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
- request_succeeded (buffer, recv_len);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-static void
-print_version (int with_help)
-{
- fputs (MYVERSION_LINE "\n"
- "Copyright (C) 2004 Free Software Foundation, Inc.\n"
- "This program comes with ABSOLUTELY NO WARRANTY.\n"
- "This is free software, and you are welcome to redistribute it\n"
- "under certain conditions. See the file COPYING for details.\n",
- stdout);
-
- if (with_help)
- fputs ("\n"
- "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
- "Helper to connect scdaemon to the PC/SC library\n"
- "\n"
- " --verbose enable extra informational output\n"
- " --version print version of the program and exit\n"
- " --help display this help and exit\n"
- BUGREPORT_LINE, stdout );
-
- exit (0);
-}
-
-
-int
-main (int argc, char **argv)
-{
- int last_argc = -1;
- int api_number = 0;
- int c;
-
- if (argc)
- {
- argc--; argv++;
- }
- while (argc && last_argc != argc )
- {
- last_argc = argc;
- if (!strcmp (*argv, "--"))
- {
- argc--; argv++;
- break;
- }
- else if (!strcmp (*argv, "--version"))
- print_version (0);
- else if (!strcmp (*argv, "--help"))
- print_version (1);
- else if (!strcmp (*argv, "--verbose"))
- {
- verbose = 1;
- argc--; argv++;
- }
- }
- if (argc != 1 && argc != 2)
- {
- fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
- exit (1);
- }
-
- api_number = atoi (*argv);
- argv++; argc--;
- if (api_number != 1)
- {
- fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
- exit (1);
- }
-
- load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
-
- while ((c = getc (stdin)) != EOF)
- {
- size_t arglen;
- unsigned char argbuffer[2048];
-
- arglen = read_32 (stdin);
- if (arglen >= sizeof argbuffer - 1)
- {
- fprintf (stderr, PGM ": request too long\n");
- exit (1);
- }
- if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
- {
- fprintf (stderr, PGM ": error reading request: %s\n",
- strerror (errno));
- exit (1);
- }
- argbuffer[arglen] = 0;
- switch (c)
- {
- case 1:
- handle_open (argbuffer, arglen);
- break;
-
- case 2:
- handle_close (argbuffer, arglen);
- exit (0);
- break;
-
- case 3:
- handle_transmit (argbuffer, arglen);
- break;
-
- default:
- fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
- exit (1);
- }
- free (argbuffer);
- }
- return 0;
-}
-
-
-
-/*
-Local Variables:
-compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
-End:
-*/