Cleanups, fixes and PC/SC support
authorWerner Koch <wk@gnupg.org>
Tue, 5 Aug 2003 17:11:04 +0000 (17:11 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 5 Aug 2003 17:11:04 +0000 (17:11 +0000)
24 files changed:
ChangeLog
NEWS
README
TODO
configure.ac
doc/scdaemon.texi
g10/ChangeLog
g10/Makefile.am
g10/g10.c
g10/pkglue.c
g10/pkglue.h
g10/seckey-cert.c
g10/status.c
g10/status.h
scd/ChangeLog
scd/apdu.c
scd/apdu.h
scd/app-common.h
scd/app-openpgp.c
scd/app.c
scd/sc-copykeys.c
scd/sc-investigate.c
scd/scdaemon.c
scd/scdaemon.h

index b846f27..83e9cba 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2003-08-05  Werner Koch  <wk@gnupg.org>
+
+       * configure.ac (GNUPG_DEFAULT_HONMEDIR): Changed back to ~/.gnupg.
+
 2003-07-31  Werner Koch  <wk@gnupg.org>
 
        * Makefile.am (DISTCLEANFILES): Add g10defs.h
diff --git a/NEWS b/NEWS
index 794ad11..9e6b9f1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,16 @@
 Noteworthy changes in version 1.9.0 (unreleased)
 ------------------------------------------------
 
+ * gpg has been renamed to gpg2 and gpgv to gpgv2.  This is a
+   temporary solution to allow co-existing with stable gpg versions.
+
+ * The default config file is ~/.gnupg/gpg.conf-1.9.0 if it exists.
+
+ * Removed the -k, -kv and -kvv commands.  -k is now an alias to
+   --list-keys.  New command -K as alias for --list-secret-keys.
+
+ * Removed --run-as-shm-coprocess feature.
+
  * gpg does now also use libgcrypt, libgpg-error is required.
 
  * New gpgsm commands --call-dirmngr and --call-protect-tool.
diff --git a/README b/README
index 7aea069..8dea9db 100644 (file)
--- a/README
+++ b/README
@@ -34,6 +34,21 @@ gpgsm:
     prepended before each block.
 
 
+gpg2:
+-----
+
+--card-status
+
+   Show information pertaining smartcards implementing the OpenPGP
+   application.
+
+--change-pin
+
+   Offers a menu to change the PIN of OpenPGP smartcards and to reset
+   the retry counters.
+
+
+
 OPTIONS
 =======
 
@@ -139,6 +154,22 @@ gpg-agent:
   lockups in case of bugs.
 
                      
+scdaemon:
+--------
+
+--ctapi-driver <libraryname>
+
+  The default for Scdaemon is to use the PC/SC API currently provided
+  by libpcsclite.so.  As an alternative the ctAPI can be used by
+  specify this option with the appropriate driver name
+  (e.g. libtowitoko.so).
+
+--reader-port <portname>
+
+  This specifies the port of the chipcard reader.  For PC/SC this is
+  currently ignored and the first PC/SC reader is used.  For the
+  ctAPI, a number must be specified (the default is 32768 for the
+  first USB port).
 
 
 
@@ -174,10 +205,15 @@ gpg.conf
         Options for gpg.  Note that old versions of gpg use the
         filename `options' instead of `gpg.conf'.
 
+gpg.conf-1.9.x
+
+        Options for gpg; tried before gpg.conf
+
+
 policies.txt
 
         A list of allowed CA policies.  This file should give the
-        object identifiers of the policies line by line.  emptry lines
+        object identifiers of the policies line by line.  Empty lines
         and lines startung with a hash mark are ignored.
 
         ++++++++++
diff --git a/TODO b/TODO
index 431f2a2..c9b2d18 100644 (file)
--- a/TODO
+++ b/TODO
@@ -55,5 +55,8 @@ might want to have an agent context for each service request
 * sm/export.c
 ** Return an error code or a status info per user ID.
 
+* scd/apdu.c
+** We need close_reader functionality
+
 * ALL
 ** Return IMPORT_OK status.
index 9d8aef9..060f31d 100644 (file)
@@ -224,7 +224,7 @@ AH_BOTTOM([
 #ifdef HAVE_DRIVE_LETTERS
 #define GNUPG_DEFAULT_HOMEDIR "c:/gnupg"
 #else
-#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg2"
+#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
 #endif 
 #define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
 
@@ -966,7 +966,7 @@ cat >g10defs.tmp <<G10EOF
 #ifdef __VMS
 #define GNUPG_HOMEDIR "/SYS\$LOGIN/gnupg" 
 #else
-#define GNUPG_HOMEDIR "~/.gnupg2
+#define GNUPG_HOMEDIR "~/.gnupg" 
 #endif
 #endif
 /* those are here to be redefined by handcrafted g10defs.h.
index 7b776c7..36274e6 100644 (file)
@@ -142,6 +142,10 @@ be used to specify the port of the card terminal.  A value of 0 refers
 to the first serial device; add 32768 to access USB devices.  The
 default is 32768 (first USB device).
 
+@item --ctapi-driver @var{library}
+Use @var{library} to access the smartcard reader.  The current default
+is @code{libtowitoko.so}.
+
 @end table
 
 All the long options may also be given in the configuration file after
index 335f28f..f878be6 100644 (file)
@@ -1,3 +1,23 @@
+2003-08-05  Werner Koch  <wk@gnupg.org>
+
+       * Makefile.am (install-data-local): Dropped check for the ancient
+       gpgm tool.
+       (bin_PROGRAMS): Renamed gpg to gpg2 and gpgv to gpgv2.  This is so
+       that it won't conflict with the current stable version of gpg.
+
+       * pkglue.c (pk_check_secret_key): New.
+       * seckey-cert.c (do_check): Reenable this test here again.
+
+       * g10.c (main): Add command -K as an alias for
+       --list-secret-keys. Command "-k" is now an alias to --list-keys.
+       Remove special treatment of -kv and -kvv.
+       (set_cmd): Ditto.
+       (main): Strip a "-cvs" suffix when testing for a version specific
+       config file.
+
+       * status.h, status.c, g10.c [USE_SHM_COPROCESSING]: Removed.  This
+       is not any longer available.
+
 2003-07-29  Werner Koch  <wk@gnupg.org>
 
        * g10.c (main): Add secmem features and set the random seed file.
index d698494..59213d0 100644 (file)
@@ -31,8 +31,7 @@ AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
 endif
 needed_libs = ../common/libcommon.a ../jnlib/libjnlib.a
 
-#noinst_PROGRAMS = gpgd
-bin_PROGRAMS = gpg gpgv
+bin_PROGRAMS = gpg2 gpgv2
 
 common_source =  \
              global.h gpg.h    \
@@ -65,7 +64,7 @@ common_source =  \
              keylist.c         \
              pkglue.c pkglue.h 
 
-gpg_SOURCES  = g10.c           \
+gpg2_SOURCES  = g10.c          \
              $(common_source)  \
              pkclist.c         \
              skclist.c         \
@@ -99,7 +98,7 @@ gpg_SOURCES  = g10.c          \
              card-util.c \
              exec.c exec.h
 
-gpgv_SOURCES = gpgv.c           \
+gpgv2_SOURCES = gpgv.c           \
              $(common_source)  \
              verify.c          
 
@@ -111,8 +110,8 @@ gpgv_SOURCES = gpgv.c           \
 #             $(common_source)
 
 LDADD =  $(needed_libs) @INTLLIBS@ @CAPLIBS@ @ZLIBS@ 
-gpg_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error
-gpgv_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error
+gpg2_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error
+gpgv2_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error
 
 $(PROGRAMS): $(needed_libs)
 
@@ -120,8 +119,4 @@ install-data-local:
        $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
        $(INSTALL_DATA) $(srcdir)/options.skel \
                                $(DESTDIR)$(pkgdatadir)/options.skel
-       @set -e;\
-        if test -f $(DESTDIR)$(bindir)/gpgm ; then \
-          echo "removing obsolete gpgm binary" ;   \
-          rm $(DESTDIR)$(bindir)/gpgm ;            \
-        fi
+
index f895561..aef7699 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -61,7 +61,8 @@ enum cmd_and_opt_values { aNull = 0,
     aEncr        = 'e',
     aEncrFiles,
     oInteractive  = 'i',
-    oKOption     = 'k',
+    aListKeys    = 'k',
+    aListSecretKeys = 'K',
     oDryRun      = 'n',
     oOutput      = 'o',
     oQuiet       = 'q',
@@ -93,15 +94,11 @@ enum cmd_and_opt_values { aNull = 0,
     aDeleteKeys,
     aDeleteSecretKeys,
     aDeleteSecretAndPublicKeys,
-    aKMode,
-    aKModeC,
     aImport,
     aFastImport,
     aVerify,
     aVerifyFiles,
-    aListKeys,
     aListSigs,
-    aListSecretKeys,
     aSendKeys,
     aRecvKeys,
     aSearchKeys,
@@ -213,7 +210,6 @@ enum cmd_and_opt_values { aNull = 0,
     oTrustModel,
     oForceOwnertrust,
     oEmuChecksumBug,
-    oRunAsShmCP,
     oSetFilename,
     oForYourEyesOnly,
     oNoForYourEyesOnly,
@@ -514,7 +510,6 @@ static ARGPARSE_OPTS opts[] = {
     /* Not yet used */
     /* { aListTrustPath, "list-trust-path",0, "@"}, */
     { aPipeMode,  "pipemode", 0, "@" },
-    { oKOption, NULL,   0, "@"},
     { oPasswdFD, "passphrase-fd",1, "@" },
 #ifdef __riscos__
     { oPasswdFile, "passphrase-file",2, "@" },
@@ -549,7 +544,6 @@ static ARGPARSE_OPTS opts[] = {
     { oTrustModel, "trust-model", 2, "@"},
     { oForceOwnertrust, "force-ownertrust", 2, "@"},
     { oEmuChecksumBug, "emulate-checksum-bug", 0, "@"},
-    { oRunAsShmCP, "run-as-shm-coprocess", 4, "@" },
     { oSetFilename, "set-filename", 2, "@" },
     { oForYourEyesOnly, "for-your-eyes-only", 0, "@" },
     { oNoForYourEyesOnly, "no-for-your-eyes-only", 0, "@" },
@@ -879,8 +873,6 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
        cmd = aSignSym;
     else if( cmd == aSym && new_cmd == aSign )
        cmd = aSignSym;
-    else if( cmd == aKMode && new_cmd == aSym )
-       cmd = aKModeC;
     else if(   ( cmd == aSign     && new_cmd == aClearsign )
             || ( cmd == aClearsign && new_cmd == aSign )  )
        cmd = aClearsign;
@@ -1167,9 +1159,6 @@ main( int argc, char **argv )
     int pwfd = -1;
     int with_fpr = 0; /* make an option out of --fingerprint */
     int any_explicit_recipient = 0;
-#ifdef USE_SHM_COPROCESSING
-    ulong requested_shm_size=0;
-#endif
 
 #ifdef __riscos__
     riscos_global_defaults();
@@ -1276,19 +1265,6 @@ main( int argc, char **argv )
            opt.strict=0;
            log_set_strict(0);
          }
-#ifdef USE_SHM_COPROCESSING
-       else if( pargs.r_opt == oRunAsShmCP ) {
-           /* does not make sense in a options file, we do it here,
-            * so that we are the able to drop setuid as soon as possible */
-           opt.shm_coprocess = 1;
-           requested_shm_size = pargs.r.ret_ulong;
-       }
-       else if ( pargs.r_opt == oStatusFD ) {
-           /* this is needed to ensure that the status-fd filedescriptor is
-            * initialized when init_shm_coprocessing() is called */
-           set_status_fd( iobuf_translate_file_handle (pargs.r.ret_int, 1) );
-       }
-#endif
     }
 
 #ifdef HAVE_DOSISH_SYSTEM
@@ -1301,11 +1277,7 @@ main( int argc, char **argv )
         set_homedir (buf);
     }
 #endif
-#ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess ) {
-       init_shm_coprocessing(requested_shm_size, 1 );
-    }
-#endif
+
     /* Initialize the secure memory. */
     gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
     maybe_setuid = 0;
@@ -1318,9 +1290,14 @@ main( int argc, char **argv )
 
     if( default_config )
       {
-       /* Try for a version specific config file first */
+       /* Try for a version specific config file first but strip our
+          usual cvs suffix.  That suffix indicates that it is not yet
+          the given version but we already want this config file.  */
        configname = make_filename(opt.homedir,
                                   "gpg" EXTSEP_S "conf-" SAFE_VERSION, NULL );
+        if (!strcmp (configname + strlen (configname) - 4, "-cvs"))
+          configname[strlen (configname)-4] = 0;
+
        if(access(configname,R_OK))
          {
            xfree (configname);
@@ -1458,7 +1435,6 @@ main( int argc, char **argv )
          case oInteractive: opt.interactive = 1; break;
          case oVerbose: g10_opt_verbose++;
                    opt.verbose++; opt.list_sigs=1; break;
-         case oKOption: set_cmd( &cmd, aKMode ); break;
 
          case oBatch: opt.batch = 1; nogreeting = 1; break;
           case oUseAgent:
@@ -1631,17 +1607,6 @@ main( int argc, char **argv )
          case oGnuPG: opt.compliance = CO_GNUPG; break;
          case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break;
          case oCompressSigs: opt.compress_sigs = 1; break;
-         case oRunAsShmCP:
-#ifndef __riscos__
-# ifndef USE_SHM_COPROCESSING
-           /* not possible in the option file,
-            * but we print the warning here anyway */
-           log_error("shared memory coprocessing is not available\n");
-# endif
-#else /* __riscos__ */
-            riscos_not_implemented("run-as-shm-coprocess");
-#endif /* __riscos__ */
-           break;
          case oSetFilename: opt.set_filename = pargs.r.ret_str; break;
          case oForYourEyesOnly: eyes_only = 1; break;
          case oNoForYourEyesOnly: eyes_only = 0; break;
@@ -2276,21 +2241,6 @@ main( int argc, char **argv )
        set_cmd( &cmd, aListKeys);
     }
 
-    if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */
-       if( cmd == aKModeC ) {
-           opt.fingerprint = 1;
-           cmd = aKMode;
-       }
-       opt.list_sigs = 0;
-       if( opt.verbose > 2 )
-           opt.check_sigs++;
-       if( opt.verbose > 1 )
-           opt.list_sigs++;
-
-       opt.verbose = opt.verbose > 1;
-       g10_opt_verbose = opt.verbose;
-    }
-
     /* Compression algorithm 0 means no compression at all */
     if( opt.def_compress_algo == 0)
         opt.compress = 0;
@@ -2302,12 +2252,11 @@ main( int argc, char **argv )
     if( opt.verbose > 1 )
        set_packet_list_mode(1);
 
-    /* Add the keyrings, but not for some special commands and not in
-       case of "-kvv userid keyring".  Also avoid adding the secret
-       keyring for a couple of commands to avoid unneeded access in
-       case the secrings are stored on a floppy */
-    if( cmd != aDeArmor && cmd != aEnArmor
-       && !(cmd == aKMode && argc == 2 ) ) 
+    /* Add the keyrings, but not for some special commands.  Also
+       avoid adding the secret keyring for a couple of commands to
+       avoid unneeded access in case the secrings are stored on a
+       floppy */
+    if( cmd != aDeArmor && cmd != aEnArmor )
       {
         if (cmd != aCheckKeys && cmd != aListSigs && cmd != aListKeys
             && cmd != aVerify && cmd != aVerifyFiles
@@ -2544,34 +2493,6 @@ main( int argc, char **argv )
        free_strlist(sl);
        break;
 
-      case aKMode: /* list keyring -- NOTE: This will be removed soon */
-       if( argc < 2 ) { /* -kv [userid] */
-           sl = NULL;
-           if (argc && **argv)
-               add_to_strlist2( &sl, *argv, utf8_strings );
-           public_key_list( sl );
-           free_strlist(sl);
-       }
-       else if( argc == 2 ) { /* -kv userid keyring */
-           if( access( argv[1], R_OK ) ) {
-               log_error(_("can't open %s: %s\n"),
-                              print_fname_stdin(argv[1]), strerror(errno));
-           }
-           else {
-               /* add keyring (default keyrings are not registered in this
-                * special case */
-               keydb_add_resource( argv[1], 0, 0 );
-               sl = NULL;
-               if (**argv)
-                   add_to_strlist2( &sl, *argv, utf8_strings );
-               public_key_list( sl );
-               free_strlist(sl);
-           }
-       }
-       else
-           wrong_args(_("-k[v][v][v][c] [user-id] [keyring]") );
-       break;
-
       case aKeygen: /* generate a key */
        if( opt.batch ) {
            if( argc > 1 )
index 7920a52..015aaf9 100644 (file)
@@ -287,8 +287,39 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
 }
 
 
+/* Check whether SKEY is a suitable secret key. */
+int
+pk_check_secret_key (int algo, gcry_mpi_t *skey)
+{
+  gcry_sexp_t s_skey;
+  int rc;
 
+  if (algo == GCRY_PK_DSA)
+    {
+      rc = gcry_sexp_build (&s_skey, NULL,
+                           "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
+                           skey[0], skey[1], skey[2], skey[3], skey[4]);
+    }
+  else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
+    {
+      rc = gcry_sexp_build (&s_skey, NULL,
+                           "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
+                           skey[0], skey[1], skey[2], skey[3]);
+    }
+  else if (algo == GCRY_PK_RSA)
+    {
+      rc = gcry_sexp_build (&s_skey, NULL,
+                           "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
+                           skey[0], skey[1], skey[2], skey[3], skey[4],
+                           skey[5]);
+    }
+  else
+    return GPG_ERR_PUBKEY_ALGO;
 
-
-
-
+  if (!rc)
+    {
+      rc = gcry_pk_testkey (s_skey);
+      gcry_sexp_release (s_skey);
+    }
+  return rc;
+}
index 3065d66..43b8278 100644 (file)
@@ -29,6 +29,7 @@ int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
                 gcry_mpi_t *pkey);
 int pk_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
                 gcry_mpi_t *skey);
+int pk_check_secret_key (int algo, gcry_mpi_t *skey);
 
 
 #endif /*GNUPG_G10_PKGLUE_H*/
index 5a7db4c..5b02382 100644 (file)
@@ -215,14 +215,13 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode,
            return gpg_error (GPG_ERR_BAD_PASSPHRASE);
        }
        /* the checksum may fail, so we also check the key itself */
-#warning fixme - we need to reenable this
-/*     res = pubkey_check_secret_key( sk->pubkey_algo, sk->skey ); */
-/*     if( res ) { */
-/*         copy_secret_key( sk, save_sk ); */
-/*              passphrase_clear_cache ( keyid, sk->pubkey_algo ); */
-/*         free_secret_key( save_sk ); */
-/*         return gpg_error (GPG_ERR_BAD_PASSPHRASE); */
-/*     } */
+       res = pk_check_secret_key (sk->pubkey_algo, sk->skey);
+       if (res) {
+            copy_secret_key( sk, save_sk );
+            passphrase_clear_cache ( keyid, sk->pubkey_algo );
+            free_secret_key( save_sk );
+           return gpg_error (GPG_ERR_BAD_PASSPHRASE);
+       }
        free_secret_key( save_sk );
        sk->is_protected = 0;
     }
index 432ec57..4414b33 100644 (file)
@@ -1,5 +1,6 @@
 /* status.c
- * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002,
+ *               2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <errno.h>
 #include <unistd.h>
 #include <signal.h>
-#ifdef USE_SHM_COPROCESSING
-#ifdef USE_CAPABILITIES
-#include <sys/capability.h>
-#endif
-#ifdef HAVE_SYS_IPC_H
-#include <sys/types.h>
-#include <sys/ipc.h>
-#endif
-#ifdef HAVE_SYS_SHM_H
-#include <sys/shm.h>
-#endif
-#if defined(HAVE_MLOCK)
-#include <sys/mman.h>
-#endif
-#endif
 
 #include "gpg.h"
 #include "util.h"
 
 static FILE *statusfp;
 
-#ifdef USE_SHM_COPROCESSING
-  static int shm_id = -1;
-  static volatile char *shm_area;
-  static size_t shm_size;
-  static int shm_is_locked;
-#endif /*USE_SHM_COPROCESSING*/
-
 
 static void
 progress_cb (void *ctx, const char *what, int printchar, int current, int total)
@@ -291,179 +270,6 @@ write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
 
 
 
-#ifdef USE_SHM_COPROCESSING
-
-#ifndef IPC_RMID_DEFERRED_RELEASE
-static void
-remove_shmid( void )
-{
-    if( shm_id != -1 ) {
-       shmctl ( shm_id, IPC_RMID, 0);
-       shm_id = -1;
-    }
-}
-#endif
-
-void
-init_shm_coprocessing ( ulong requested_shm_size, int lock_mem )
-{
-    char buf[100];
-    struct shmid_ds shmds;
-
-#ifndef IPC_RMID_DEFERRED_RELEASE
-    atexit( remove_shmid );
-#endif
-    requested_shm_size = (requested_shm_size + 4095) & ~4095;
-    if ( requested_shm_size > 2 * 4096 )
-       log_fatal("too much shared memory requested; only 8k are allowed\n");
-    shm_size = 4096 /* one page for us */ + requested_shm_size;
-
-    shm_id = shmget( IPC_PRIVATE, shm_size, IPC_CREAT | 0700 );
-    if ( shm_id == -1 )
-       log_fatal("can't get %uk of shared memory: %s\n",
-                               (unsigned)shm_size/1024, strerror(errno));
-
-#if !defined(IPC_HAVE_SHM_LOCK) \
-      && defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
-    /* part of the old code which uses mlock */
-    shm_area = shmat( shm_id, 0, 0 );
-    if ( shm_area == (char*)-1 )
-       log_fatal("can't attach %uk shared memory: %s\n",
-                               (unsigned)shm_size/1024, strerror(errno));
-    log_debug("mapped %uk shared memory at %p, id=%d\n",
-                           (unsigned)shm_size/1024, shm_area, shm_id );
-    if( lock_mem ) {
-#ifdef USE_CAPABILITIES
-       cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
-#endif
-       /* (need the cast for Solaris with Sun's workshop compilers) */
-       if ( mlock ( (char*)shm_area, shm_size) )
-           log_info("locking shared memory %d failed: %s\n",
-                               shm_id, strerror(errno));
-       else
-           shm_is_locked = 1;
-#ifdef USE_CAPABILITIES
-       cap_set_proc( cap_from_text("cap_ipc_lock+p") );
-#endif
-    }
-
-#ifdef IPC_RMID_DEFERRED_RELEASE
-    if( shmctl( shm_id, IPC_RMID, 0) )
-       log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
-                                           shm_id, strerror(errno));
-#endif
-
-    if( shmctl( shm_id, IPC_STAT, &shmds ) )
-       log_fatal("shmctl IPC_STAT of %d failed: %s\n",
-                                           shm_id, strerror(errno));
-    if( shmds.shm_perm.uid != getuid() ) {
-       shmds.shm_perm.uid = getuid();
-       if( shmctl( shm_id, IPC_SET, &shmds ) )
-           log_fatal("shmctl IPC_SET of %d failed: %s\n",
-                                               shm_id, strerror(errno));
-    }
-
-#else /* this is the new code which handles the changes in the SHM
-       * semantics introduced with Linux 2.4.  The changes is that we
-       * now change the permissions and then attach to the memory.
-       */
-
-    if( lock_mem ) {
-#ifdef USE_CAPABILITIES
-       cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
-#endif
-#ifdef IPC_HAVE_SHM_LOCK
-       if ( shmctl (shm_id, SHM_LOCK, 0) )
-           log_info("locking shared memory %d failed: %s\n",
-                               shm_id, strerror(errno));
-       else
-           shm_is_locked = 1;
-#else
-       log_info("Locking shared memory %d failed: No way to do it\n", shm_id );
-#endif
-#ifdef USE_CAPABILITIES
-       cap_set_proc( cap_from_text("cap_ipc_lock+p") );
-#endif
-    }
-
-    if( shmctl( shm_id, IPC_STAT, &shmds ) )
-       log_fatal("shmctl IPC_STAT of %d failed: %s\n",
-                                           shm_id, strerror(errno));
-    if( shmds.shm_perm.uid != getuid() ) {
-       shmds.shm_perm.uid = getuid();
-       if( shmctl( shm_id, IPC_SET, &shmds ) )
-           log_fatal("shmctl IPC_SET of %d failed: %s\n",
-                                               shm_id, strerror(errno));
-    }
-
-    shm_area = shmat( shm_id, 0, 0 );
-    if ( shm_area == (char*)-1 )
-       log_fatal("can't attach %uk shared memory: %s\n",
-                               (unsigned)shm_size/1024, strerror(errno));
-    log_debug("mapped %uk shared memory at %p, id=%d\n",
-                           (unsigned)shm_size/1024, shm_area, shm_id );
-
-#ifdef IPC_RMID_DEFERRED_RELEASE
-    if( shmctl( shm_id, IPC_RMID, 0) )
-       log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
-                                           shm_id, strerror(errno));
-#endif
-
-#endif
-    /* write info; Protocol version, id, size, locked size */
-    sprintf( buf, "pv=1 pid=%d shmid=%d sz=%u lz=%u", (int)getpid(),
-           shm_id, (unsigned)shm_size, shm_is_locked? (unsigned)shm_size:0 );
-    write_status_text( STATUS_SHM_INFO, buf );
-}
-
-/****************
- * Request a string from client
- * If bool, returns static string on true (do not free) or NULL for false
- */
-static char *
-do_shm_get( const char *keyword, int hidden, int bool )
-{
-    size_t n;
-    byte *p;
-    char *string;
-
-    if( !shm_area )
-       BUG();
-
-    shm_area[0] = 0;  /* msb of length of control block */
-    shm_area[1] = 32; /* and lsb */
-    shm_area[2] = 1;  /* indicate that we are waiting on a reply */
-    shm_area[3] = 0;  /* clear data available flag */
-
-    write_status_text( bool? STATUS_SHM_GET_BOOL :
-                      hidden? STATUS_SHM_GET_HIDDEN : STATUS_SHM_GET, keyword );
-
-    do {
-       pause_on_sigusr(1);
-       if( shm_area[0] || shm_area[1] != 32 || shm_area[2] != 1 )
-           log_fatal("client modified shm control block - abort\n");
-    } while( !shm_area[3] );
-    shm_area[2] = 0; /* reset request flag */
-    p = (byte*)shm_area+32;
-    n = p[0] << 8 | p[1];
-    p += 2;
-    if( n+32+2+1 > 4095 )
-       log_fatal("client returns too large data (%u bytes)\n", (unsigned)n );
-
-    if( bool )
-       return p[0]? "" : NULL;
-
-    string = hidden? xmalloc_secure ( n+1 ) : xmalloc ( n+1 );
-    memcpy(string, p, n );
-    string[n] = 0; /* make sure it is a string */
-    if( hidden ) /* invalidate the memory */
-       memset( p, 0, n );
-
-    return string;
-}
-
-#endif /* USE_SHM_COPROCESSING */
-
 static int
 myread(int fd, void *buf, size_t count)
 {
@@ -541,10 +347,6 @@ cpr_enabled()
 {
     if( opt.command_fd != -1 )
        return 1;
-#ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess )
-       return 1;
-#endif
     return 0;
 }
 
@@ -555,10 +357,6 @@ cpr_get_no_help( const char *keyword, const char *prompt )
 
     if( opt.command_fd != -1 )
        return do_get_from_fd ( keyword, 0, 0 );
-#ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess )
-       return do_shm_get( keyword, 0, 0 );
-#endif
     for(;;) {
        p = tty_get( prompt );
         return p;
@@ -572,10 +370,6 @@ cpr_get( const char *keyword, const char *prompt )
 
     if( opt.command_fd != -1 )
        return do_get_from_fd ( keyword, 0, 0 );
-#ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess )
-       return do_shm_get( keyword, 0, 0 );
-#endif
     for(;;) {
        p = tty_get( prompt );
        if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
@@ -608,10 +402,6 @@ cpr_get_hidden( const char *keyword, const char *prompt )
 
     if( opt.command_fd != -1 )
        return do_get_from_fd ( keyword, 1, 0 );
-#ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess )
-       return do_shm_get( keyword, 1, 0 );
-#endif
     for(;;) {
        p = tty_get_hidden( prompt );
        if( *p == '?' && !p[1] ) {
@@ -628,10 +418,6 @@ cpr_kill_prompt(void)
 {
     if( opt.command_fd != -1 )
        return;
-#ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess )
-       return;
-#endif
     tty_kill_prompt();
     return;
 }
@@ -644,10 +430,6 @@ cpr_get_answer_is_yes( const char *keyword, const char *prompt )
 
     if( opt.command_fd != -1 )
        return !!do_get_from_fd ( keyword, 0, 1 );
-#ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess )
-       return !!do_shm_get( keyword, 0, 1 );
-#endif
     for(;;) {
        p = tty_get( prompt );
        trim_spaces(p); /* it is okay to do this here */
@@ -672,10 +454,6 @@ cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
 
     if( opt.command_fd != -1 )
        return !!do_get_from_fd ( keyword, 0, 1 );
-#ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess )
-       return !!do_shm_get( keyword, 0, 1 );
-#endif
     for(;;) {
        p = tty_get( prompt );
        trim_spaces(p); /* it is okay to do this here */
index 44a7d6d..4a0bcd4 100644 (file)
@@ -110,10 +110,6 @@ void write_status_buffer ( int no,
 void write_status_text_and_buffer ( int no, const char *text,
                                     const char *buffer, size_t len, int wrap );
 
-#ifdef USE_SHM_COPROCESSING
-  void init_shm_coprocessing ( ulong requested_shm_size, int lock_mem );
-#endif /*USE_SHM_COPROCESSING*/
-
 int cpr_enabled(void);
 char *cpr_get( const char *keyword, const char *prompt );
 char *cpr_get_no_help( const char *keyword, const char *prompt );
index ad4b051..ae2e6ce 100644 (file)
@@ -1,3 +1,25 @@
+2003-08-05  Werner Koch  <wk@gnupg.org>
+
+       * app-openpgp.c (dump_all_do): Don't analyze constructed DOs after
+       an error.
+
+2003-08-04  Werner Koch  <wk@gnupg.org>
+
+       * app.c (app_set_default_reader_port): New.
+       (select_application): Use it here.
+       * scdaemon.c (main): and here.
+       * sc-copykeys.c: --reader-port does now take a string.
+       * sc-investigate.c, scdaemon.c: Ditto.
+       * apdu.c (apdu_open_reader): Ditto.  Load pcsclite if no ctapi
+       driver is configured.  Always include code for ctapi.
+       (new_reader_slot): Don't test for already used ports and remove
+       port arg.
+       (open_pcsc_reader, pcsc_send_apdu, pcsc_error_string): New.
+       (apdu_send_le): Changed RC to long to cope with PC/SC.
+
+       * scdaemon.c, scdaemon.h: New option --ctapi-driver.
+       * sc-investigate.c, sc-copykeys.c: Ditto.
+       
 2003-07-31  Werner Koch  <wk@gnupg.org>
 
        * Makefile.am (scdaemon_LDADD): Added INTLLIBS.
index 6fec584..60de5b9 100644 (file)
@@ -29,8 +29,6 @@
 #include "scdaemon.h"
 #include "apdu.h"
 
-#define HAVE_CTAPI 1
-
 #define MAX_READER 4 /* Number of readers we support concurrently. */
 #define CARD_CONNECT_TIMEOUT 1 /* Number of seconds to wait for
                                   insertion of the card (1 = don't wait). */
 /* A global table to keep track of active readers. */
 static struct {
   int used;            /* True if slot is used. */
-  unsigned short port; /* port number0 = unused, 1 - dev/tty */
+  unsigned short port; /* Port number:  0 = unused, 1 - dev/tty */
+  int is_ctapi;        /* This is a ctAPI driver. */
+  struct {
+    unsigned long context;
+    unsigned long card;
+    unsigned long protocol;
+  } pcsc;
   int status;
   unsigned char atr[33];
   size_t atrlen;
@@ -55,6 +59,61 @@ static char (*CT_data) (unsigned short ctn, unsigned char *dad,
                         unsigned char *rsp);
 static char (*CT_close) (unsigned short ctn);
 
+/* 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;
+
+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);
+
 
 
 
@@ -64,28 +123,16 @@ static char (*CT_close) (unsigned short ctn);
  */
  
 
-/* Find an unused reader slot for PORT and put it into the reader
+/* Find an unused reader slot for PORTSTR and put it into the reader
    table.  Return -1 on error or the index into the reader table. */
 static int 
-new_reader_slot (int port)    
+new_reader_slot (void)    
 {
   int i, reader = -1;
 
-  if (port < 0 || port > 0xffff)
-    {
-      log_error ("new_reader_slot: invalid port %d requested\n", port);
-      return -1;
-    }
-
   for (i=0; i < MAX_READER; i++)
     {
-      if (reader_table[i].used && reader_table[i].port == port)
-        {
-          log_error ("new_reader_slot: requested port %d already in use\n",
-                     reader);
-          return -1; 
-        }
-      else if (!reader_table[i].used && reader == -1)
+      if (!reader_table[i].used && reader == -1)
         reader = i;
     }
   if (reader == -1)
@@ -94,7 +141,7 @@ new_reader_slot (int port)
       return -1;
     }
   reader_table[reader].used = 1;
-  reader_table[reader].port = port;
+  reader_table[reader].is_ctapi = 0;
   return reader;
 }
 
@@ -102,11 +149,25 @@ new_reader_slot (int port)
 static void
 dump_reader_status (int reader)
 {
-  log_info ("reader %d: %s\n", reader,
-            reader_table[reader].status == 1? "Processor ICC present" :
-            reader_table[reader].status == 0? "Memory ICC present" :
-                                              "ICC not present" );
+  if (reader_table[reader].is_ctapi)
+    {
+      log_info ("reader slot %d: %s\n", reader,
+                reader_table[reader].status == 1? "Processor ICC present" :
+                reader_table[reader].status == 0? "Memory ICC present" :
+                "ICC not present" );
+    }
+  else
+    {
+      log_info ("reader slot %d: active protocol:", reader);
+      if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_T0))
+        log_printf (" T0");
+      else if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_T1))
+        log_printf (" T1");
+      else if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_RAW))
+        log_printf (" raw");
+      log_printf ("\n");
+    }
+
   if (reader_table[reader].status != -1)
     {
       log_info ("reader %d: ATR=", reader);
@@ -117,13 +178,12 @@ dump_reader_status (int reader)
 
 
 \f
-#ifdef HAVE_CTAPI
 /* 
        ct API Interface 
  */
 
 static const char *
-ct_error_string (int err)
+ct_error_string (long err)
 {
   switch (err)
     {
@@ -150,7 +210,7 @@ ct_activate_card (int reader)
       unsigned short buflen;
 
       if (count)
-        sleep (1); /* FIXME: we should use a more reliable timer. */
+        ; /* FIXME: we should use a more reliable timer than sleep. */
 
       /* Check whether card has been inserted. */
       dad[0] = 1;     /* Destination address: CT. */    
@@ -221,9 +281,15 @@ open_ct_reader (int port)
 {
   int rc, reader;
 
-  reader = new_reader_slot (port);
+  if (port < 0 || port > 0xffff)
+    {
+      log_error ("open_ct_reader: invalid port %d requested\n", port);
+      return -1;
+    }
+  reader = new_reader_slot ();
   if (reader == -1)
     return reader;
+  reader_table[reader].port = port;
 
   rc = CT_init (reader, (unsigned short)port);
   if (rc)
@@ -241,6 +307,7 @@ open_ct_reader (int port)
       return -1;
     }
 
+  reader_table[reader].is_ctapi = 1;
   dump_reader_status (reader);
   return reader;
 }
@@ -271,16 +338,205 @@ ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
 }
 
 
-#endif /*HAVE_CTAPI*/
-
 \f
-#ifdef HAVE_PCSC
+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;
+}
+
 /* 
        PC/SC Interface
  */
 
+static int
+open_pcsc_reader (const char *portstr)
+{
+  long err;
+  int slot;
+  char *list = NULL;
+  unsigned long nreader, listlen, atrlen;
+  char *p;
+  unsigned long card_state, card_protocol;
+
+  slot = new_reader_slot ();
+  if (slot == -1)
+    return -1;
+
+  err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
+                                &reader_table[slot].pcsc.context);
+  if (err)
+    {
+      log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      reader_table[slot].used = 0;
+      return -1;
+    }
+  
+  err = pcsc_list_readers (reader_table[slot].pcsc.context,
+                           NULL, NULL, &nreader);
+  if (!err)
+    {
+      list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
+      if (!list)
+        {
+          log_error ("error allocating memory for reader list\n");
+          pcsc_release_context (reader_table[slot].pcsc.context);
+          reader_table[slot].used = 0;
+          return -1;
+        }
+      err = pcsc_list_readers (reader_table[slot].pcsc.context,
+                               NULL, list, &nreader);
+    }
+  if (err)
+    {
+      log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      pcsc_release_context (reader_table[slot].pcsc.context);
+      reader_table[slot].used = 0;
+      xfree (list);
+      return -1;
+    }
+
+  listlen = nreader;
+  p = list;
+  while (nreader)
+    {
+      if (!*p && !p[1])
+        break;
+      log_info ("detected reader `%s'\n", p);
+      if (nreader < (strlen (p)+1))
+        {
+          log_error ("invalid response from pcsc_list_readers\n");
+          break;
+        }
+      nreader -= strlen (p)+1;
+      p += strlen (p) + 1;
+    }
+
+  err = pcsc_connect (reader_table[slot].pcsc.context,
+                      portstr? portstr : list,
+                      PCSC_SHARE_EXCLUSIVE,
+                      PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
+                      &reader_table[slot].pcsc.card,
+                      &reader_table[slot].pcsc.protocol);
+  if (err)
+    {
+      log_error ("pcsc_connect failed: %s (0x%lx)\n",
+                  pcsc_error_string (err), err);
+      pcsc_release_context (reader_table[slot].pcsc.context);
+      reader_table[slot].used = 0;
+      xfree (list);
+      return -1;
+    }      
+  
+  atrlen = 32;
+  /* (We need to pass a dummy buffer.  We use LIST because it ought to
+     be large enough.) */
+  err = pcsc_status (reader_table[slot].pcsc.card,
+                     list, &listlen,
+                     &card_state, &card_protocol,
+                     reader_table[slot].atr, &atrlen);
+  xfree (list);
+  if (err)
+    {
+      log_error ("pcsc_status failed: %s (0x%lx)\n",
+                  pcsc_error_string (err), err);
+      pcsc_release_context (reader_table[slot].pcsc.context);
+      reader_table[slot].used = 0;
+      return -1;
+    }
+  if (atrlen >= DIM (reader_table[0].atr))
+    log_bug ("ATR returned by pcsc_status is too large\n");
+  reader_table[slot].atrlen = atrlen;
+/*   log_debug ("state    from pcsc_status: 0x%lx\n", card_state); */
+/*   log_debug ("protocol from pcsc_status: 0x%lx\n", card_protocol); */
+
+  dump_reader_status (slot); 
+  return slot;
+}
+
+
+/* Actually send the APDU of length APDULEN to SLOT and return a
+   maximum of *BUFLEN data in BUFFER, the actual returned size will be
+   set to BUFLEN.  Returns: CT API error code. */
+static int
+pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
+                unsigned char *buffer, size_t *buflen)
+{
+  long err;
+  struct pcsc_io_request_s send_pci;
+  unsigned long recv_len;
+  
+  if (DBG_CARD_IO)
+    log_printhex ("  CT_data:", apdu, apdulen);
+
+  if ((reader_table[slot].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 = *buflen;
+  err = pcsc_transmit (reader_table[slot].pcsc.card,
+                       &send_pci, apdu, apdulen,
+                       NULL, buffer, &recv_len);
+  *buflen = recv_len;
+  if (err)
+    log_error ("pcsc_transmit failed: %s (0x%lx)\n",
+               pcsc_error_string (err), err);
+  
+  return err? -1:0;
+}
+
+
 
-#endif /*HAVE_PCSC*/
 
 \f
 /* 
@@ -288,35 +544,86 @@ ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
  */
 
 /* Open the reader and return an internal slot number or -1 on
-   error. */
+   error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
+   the first USB reader.  For PCSC/ the first listed reader. */
 int
-apdu_open_reader (int port)
+apdu_open_reader (const char *portstr)
 {
-  static int ct_api_loaded;
+  static int pcsc_api_loaded, ct_api_loaded;
+
+  if (opt.ctapi_driver && *opt.ctapi_driver)
+    {
+      int port = portstr? atoi (portstr) : 32768;
+
+      if (!ct_api_loaded)
+        {
+          void *handle;
+          
+          handle = dlopen (opt.ctapi_driver, RTLD_LAZY);
+          if (!handle)
+            {
+              log_error ("apdu_open_reader: failed to open driver: %s",
+                         dlerror ());
+              return -1;
+            }
+          CT_init = dlsym (handle, "CT_init");
+          CT_data = dlsym (handle, "CT_data");
+          CT_close = dlsym (handle, "CT_close");
+          if (!CT_init || !CT_data || !CT_close)
+            {
+              log_error ("apdu_open_reader: invalid ctAPI driver\n");
+              dlclose (handle);
+              return -1;
+            }
+          ct_api_loaded = 1;
+        }
+      return open_ct_reader (port);
+    }
 
-  if (!ct_api_loaded)
+  
+  /* No ctAPI configured, so lets try the PC/SC API */
+  if (!pcsc_api_loaded)
     {
       void *handle;
 
-      handle = dlopen ("libtowitoko.so", RTLD_LAZY);
+      handle = dlopen ("libpcsclite.so", RTLD_LAZY);
       if (!handle)
         {
           log_error ("apdu_open_reader: failed to open driver: %s",
                      dlerror ());
           return -1;
         }
-      CT_init = dlsym (handle, "CT_init");
-      CT_data = dlsym (handle, "CT_data");
-      CT_close = dlsym (handle, "CT_close");
-      if (!CT_init || !CT_data || !CT_close)
+
+      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)
         {
-          log_error ("apdu_open_reader: invalid driver\n");
+          log_error ("apdu_open_reader: invalid PC/SC driver\n");
           dlclose (handle);
           return -1;
         }
-      ct_api_loaded = 1;
+      pcsc_api_loaded = 1;
     }
-  return open_ct_reader (port);
+  
+  return open_pcsc_reader (portstr);
 }
 
 
@@ -338,15 +645,14 @@ apdu_get_atr (int slot, size_t *atrlen)
   
     
 static const char *
-error_string (int slot, int rc)
+error_string (int slot, long rc)
 {
-#ifdef HAVE_CTAPI
-  return ct_error_string (rc);
-#elif defined(HAVE_PCSC)
-  return "?";
-#else
-  return "?";
-#endif
+  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+    return "[invalid slot]";
+  if (reader_table[slot].is_ctapi)
+    return ct_error_string (rc);
+  else
+    return pcsc_error_string (rc);
 }
 
 
@@ -355,13 +661,12 @@ static int
 send_apdu (int slot, unsigned char *apdu, size_t apdulen,
            unsigned char *buffer, size_t *buflen)
 {
-#ifdef HAVE_CTAPI
-  return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
-#elif defined(HAVE_PCSC)
-  return SW_HOST_NO_DRIVER;
-#else
-  return SW_HOST_NO_DRIVER;
-#endif
+  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+    return SW_HOST_NO_DRIVER;
+  if (reader_table[slot].is_ctapi)
+    return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
+  else
+    return pcsc_send_apdu (slot, apdu, apdulen, buffer, buflen);
 }
 
 /* Send an APDU to the card in SLOT.  The APDU is created from all
@@ -382,7 +687,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
   size_t resultlen = 256;
   unsigned char apdu[5+256+1];
   size_t apdulen;
-  int rc, sw;
+  int sw;
+  long rc; /* we need a long here due to PC/SC. */
 
   if (DBG_CARD_IO)
     log_debug ("send apdu: c=%02X i=%02X p0=%02X p1=%02X lc=%d le=%d\n",
index 44166a3..6e4244b 100644 (file)
@@ -47,12 +47,13 @@ enum {
                                      between errnos on a failed malloc. */
   SW_HOST_INV_VALUE   = 0x10002,
   SW_HOST_INCOMPLETE_CARD_RESPONSE = 0x10003,
+  SW_HOST_NO_DRIVER   = 0x10004
 };
 
 
 
 /* Note , that apdu_open_reader returns no status word but -1 on error. */
-int apdu_open_reader (int port);
+int apdu_open_reader (const char *portstr);
 unsigned char *apdu_get_atr (int slot, size_t *atrlen);
 
 
index 282f827..1243ca3 100644 (file)
@@ -69,6 +69,7 @@ struct app_ctx_s {
 };
 
 /*-- app.c --*/
+void app_set_default_reader_port (const char *portstr);
 APP select_application (void);
 int app_get_serial_and_stamp (APP app, char **serial, time_t *stamp);
 int app_write_learn_status (APP app, CTRL ctrl);
index 09a1969..7f61142 100644 (file)
@@ -214,71 +214,6 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes)
   return NULL;
 }
 
-#if 0 /* not used */
-static void
-dump_one_do (int slot, int tag)
-{
-  int rc, i;
-  unsigned char *buffer;
-  size_t buflen;
-  const char *desc;
-  int binary;
-  const unsigned char *value;
-  size_t valuelen;
-
-  for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++)
-    ;
-  desc = data_objects[i].tag? data_objects[i].desc : "?";
-  binary = data_objects[i].tag? data_objects[i].binary : 1;
-
-  value = NULL;
-  rc = -1;
-  if (data_objects[i].tag && data_objects[i].get_from)
-    {
-      rc = iso7816_get_data (slot, data_objects[i].get_from,
-                             &buffer, &buflen);
-      if (!rc)
-        {
-          value = find_tlv (buffer, buflen, tag, &valuelen, 0);
-          if (!value)
-            ; /* not found */
-          else if (valuelen > buflen - (value - buffer))
-            {
-              log_error ("warning: constructed DO too short\n");
-              value = NULL;
-              xfree (buffer); buffer = NULL;
-            }
-        }
-    }
-
-  if (!value) /* Not in a constructed DO, try simple. */
-    {
-      rc = iso7816_get_data (slot, tag, &buffer, &buflen);
-      if (!rc)
-        {
-          value = buffer;
-          valuelen = buflen;
-        }
-    }
-  if (rc == 0x6a88)
-    log_info ("DO `%s' not available\n", desc);
-  else if (rc) 
-    log_info ("DO `%s' not available (rc=%04X)\n", desc, rc);
-  else
-    {
-      if (binary)
-        {
-          log_info ("DO `%s': ", desc);
-          log_printhex ("", value, valuelen);
-        }
-      else
-        log_info ("DO `%s': `%.*s'\n",
-                  desc, (int)valuelen, value); /* FIXME: sanitize */
-      xfree (buffer);
-    }
-}
-#endif /*not used*/
-
 
 static void
 dump_all_do (int slot)
@@ -293,11 +228,11 @@ dump_all_do (int slot)
         continue;
 
       rc = iso7816_get_data (slot, data_objects[i].tag, &buffer, &buflen);
-      if (rc == 0x6a88)
+      if (gpg_error (rc) == GPG_ERR_NO_OBJ)
         ;
       else if (rc) 
-        log_info ("DO `%s' not available (rc=%04X)\n",
-                  data_objects[i].desc, rc);
+        log_info ("DO `%s' not available: %s\n",
+                  data_objects[i].desc, gpg_strerror (rc));
       else
         {
           if (data_objects[i].binary)
@@ -309,34 +244,34 @@ dump_all_do (int slot)
             log_info ("DO `%s': `%.*s'\n",
                       data_objects[i].desc,
                       (int)buflen, buffer); /* FIXME: sanitize */
-        }
 
-      if (data_objects[i].constructed)
-        {
-          for (j=0; data_objects[j].tag; j++)
+          if (data_objects[i].constructed)
             {
-              const unsigned char *value;
-              size_t valuelen;
-
-              if (j==i || data_objects[i].tag != data_objects[j].get_from)
-                continue;
-              value = find_tlv (buffer, buflen,
-                                data_objects[j].tag, &valuelen, 0);
-              if (!value)
-                ; /* not found */
-              else if (valuelen > buflen - (value - buffer))
-                log_error ("warning: constructed DO too short\n");
-              else
+              for (j=0; data_objects[j].tag; j++)
                 {
-                  if (data_objects[j].binary)
+                  const unsigned char *value;
+                  size_t valuelen;
+                  
+                  if (j==i || data_objects[i].tag != data_objects[j].get_from)
+                    continue;
+                  value = find_tlv (buffer, buflen,
+                                    data_objects[j].tag, &valuelen, 0);
+                  if (!value)
+                    ; /* not found */
+                  else if (valuelen > buflen - (value - buffer))
+                    log_error ("warning: constructed DO too short\n");
+                  else
                     {
-                      log_info ("DO `%s': ", data_objects[j].desc);
-                      log_printhex ("", value, valuelen);
+                      if (data_objects[j].binary)
+                        {
+                          log_info ("DO `%s': ", data_objects[j].desc);
+                          log_printhex ("", value, valuelen);
+                        }
+                      else
+                        log_info ("DO `%s': `%.*s'\n",
+                                  data_objects[j].desc,
+                                  (int)valuelen, value); /* FIXME: sanitize */
                     }
-                  else
-                    log_info ("DO `%s': `%.*s'\n",
-                              data_objects[j].desc,
-                              (int)valuelen, value); /* FIXME: sanitize */
                 }
             }
         }
@@ -410,7 +345,7 @@ store_fpr (int slot, int keynumber, u32 timestamp,
   rc = iso7816_put_data (slot, (card_version > 0x0007? 0xC7 : 0xC6)
                                + keynumber, fpr, 20);
   if (rc)
-    log_error ("failed to store the fingerprint: rc=%04X\n", rc);
+    log_error ("failed to store the fingerprint: %s\n",gpg_strerror (rc));
 
   return rc;
 }
@@ -582,7 +517,7 @@ do_setattr (APP app, const char *name,
       xfree (pinvalue);
       if (rc)
         {
-          log_error ("verify CHV3 failed\n");
+          log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc));
           rc = gpg_error (GPG_ERR_GENERAL);
           return rc;
         }
@@ -626,7 +561,7 @@ do_change_pin (APP app, CTRL ctrl,  const char *chvnostr, int reset_mode,
       xfree (pinvalue);
       if (rc)
         {
-          log_error ("verify CHV3 failed: rc=%04X\n", rc);
+          log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc));
           goto leave;
         }
     }
@@ -642,7 +577,7 @@ do_change_pin (APP app, CTRL ctrl,  const char *chvnostr, int reset_mode,
       xfree (pinvalue);
       if (rc)
         {
-          log_error ("verify CHV1 failed: rc=%04X\n", rc);
+          log_error ("verify CHV1 failed: rc=%s\n", gpg_strerror (rc));
           goto leave;
         }
     }
@@ -658,7 +593,7 @@ do_change_pin (APP app, CTRL ctrl,  const char *chvnostr, int reset_mode,
       xfree (pinvalue);
       if (rc)
         {
-          log_error ("verify CHV2 failed: rc=%04X\n", rc);
+          log_error ("verify CHV2 failed: rc=%s\n", gpg_strerror (rc));
           goto leave;
         }
     }
@@ -757,7 +692,7 @@ do_genkey (APP app, CTRL ctrl,  const char *keynostr, unsigned int flags,
   }
   if (rc)
     {
-      log_error ("verify CHV3 failed: rc=%04X\n", rc);
+      log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc));
       goto leave;
     }
 
@@ -1224,8 +1159,6 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen)
   rc = iso7816_select_application (slot, aid, sizeof aid);
   if (!rc)
     {
-      /* fixme: get the full AID and check that the version is okay
-         with us. */
       rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen);
       if (rc)
         goto leave;
@@ -1386,7 +1319,7 @@ app_openpgp_storekey (APP app, int keyno,
   }
   if (rc)
     {
-      log_error ("verify CHV3 failed: rc=%04X\n", rc);
+      log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc));
       goto leave;
     }
 
@@ -1395,7 +1328,7 @@ app_openpgp_storekey (APP app, int keyno,
                          template, template_len);
   if (rc)
     {
-      log_error ("failed to store the key: rc=%04X\n", rc);
+      log_error ("failed to store the key: rc=%s\n", gpg_strerror (rc));
       rc = gpg_error (GPG_ERR_CARD);
       goto leave;
     }
index 7a85df3..04b421b 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
 #include "apdu.h"
 #include "iso7816.h"
 
+static char *default_reader_port;
+
+void
+app_set_default_reader_port (const char *portstr)
+{
+  xfree (default_reader_port);
+  default_reader_port = portstr? xstrdup (portstr): NULL;
+}
+
+
 /* The select the best fitting application and return a context.
    Returns NULL if no application was found or no card is present. */
 APP
 select_application (void)
 {
-  int reader_port = 32768; /* First USB reader. */
   int slot;
   int rc;
   APP app;
 
-  slot = apdu_open_reader (reader_port);
+  slot = apdu_open_reader (default_reader_port);
   if (slot == -1)
     {
       log_error ("card reader not available\n");
index 9caf39a..b56b885 100644 (file)
@@ -44,6 +44,7 @@
 enum cmd_and_opt_values 
 { oVerbose       = 'v',
   oReaderPort     = 500,
+  octapiDriver,
   oDebug,
   oDebugAll,
 
@@ -55,7 +56,8 @@ static ARGPARSE_OPTS opts[] = {
   { 301, NULL, 0, "@Options:\n " },
 
   { oVerbose, "verbose",   0, "verbose" },
-  { oReaderPort, "reader-port", 1, "|N|connect to reader at port N"},
+  { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
+  { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"},
   { oDebug,    "debug"     ,4|16, "set debugging flags"},
   { oDebugAll, "debug-all" ,0, "enable full debugging"},
   {0}
@@ -115,7 +117,7 @@ main (int argc, char **argv )
 {
   ARGPARSE_ARGS pargs;
   int slot, rc;
-  int reader_port = 32768; /* First USB reader. */
+  const char *reader_port = NULL;
   struct app_ctx_s appbuf;
 
   memset (&appbuf, 0, sizeof appbuf);
@@ -146,6 +148,8 @@ main (int argc, char **argv )
         case oVerbose: opt.verbose++; break;
         case oDebug: opt.debug |= pargs.r.ret_ulong; break;
         case oDebugAll: opt.debug = ~0; break;
+        case oReaderPort: reader_port = pargs.r.ret_str; break;
+        case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
         default : pargs.err = 2; break;
        }
     }
index e8f0eb8..ecd3856 100644 (file)
@@ -39,6 +39,7 @@
 enum cmd_and_opt_values 
 { oVerbose       = 'v',
   oReaderPort     = 500,
+  octapiDriver,
   oDebug,
   oDebugAll,
 
@@ -52,7 +53,8 @@ static ARGPARSE_OPTS opts[] = {
   { 301, NULL, 0, "@Options:\n " },
 
   { oVerbose, "verbose",   0, "verbose" },
-  { oReaderPort, "reader-port", 1, "|N|connect to reader at port N"},
+  { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
+  { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"},
   { oDebug,    "debug"     ,4|16, "set debugging flags"},
   { oDebugAll, "debug-all" ,0, "enable full debugging"},
   { oGenRandom, "gen-random", 4, "|N|generate N bytes of random"},
@@ -108,7 +110,7 @@ main (int argc, char **argv )
 {
   ARGPARSE_ARGS pargs;
   int slot, rc;
-  int reader_port = 32768; /* First USB reader. */
+  const char *reader_port = NULL;
   struct app_ctx_s appbuf;
   unsigned long gen_random = 0;
 
@@ -139,6 +141,8 @@ main (int argc, char **argv )
         case oVerbose: opt.verbose++; break;
         case oDebug: opt.debug |= pargs.r.ret_ulong; break;
         case oDebugAll: opt.debug = ~0; break;
+        case oReaderPort: reader_port = pargs.r.ret_str; break;
+        case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
         case oGenRandom: gen_random = pargs.r.ret_ulong; break;
         default : pargs.err = 2; break;
        }
index 8e0ef37..1195261 100644 (file)
@@ -43,7 +43,7 @@
 
 #include "i18n.h"
 #include "sysutils.h"
-
+#include "app-common.h"
 
 
 enum cmd_and_opt_values 
@@ -69,6 +69,7 @@ enum cmd_and_opt_values
   oDaemon,
   oBatch,
   oReaderPort,
+  octapiDriver,
 
 aTest };
 
@@ -91,8 +92,8 @@ static ARGPARSE_OPTS opts[] = {
   { oDebugSC,  "debug-sc",  1, N_("|N|set OpenSC debug level to N")},
   { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
   { oLogFile,  "log-file"   ,2, N_("use a log file for the server")},
-  { oReaderPort, "reader-port", 1, N_("|N|connect to reader at port N")},
-
+  { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")},
+  { octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ctAPI driver")},
   {0}
 };
 
@@ -230,7 +231,6 @@ main (int argc, char **argv )
   int csh_style = 0;
   char *logfile = NULL;
   int debug_wait = 0;
-  int reader_port = 32768; /* First USB reader. */
 
   set_strusage (my_strusage);
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
@@ -299,6 +299,7 @@ main (int argc, char **argv )
 
   if (default_config)
     configname = make_filename (opt.homedir, "scdaemon.conf", NULL );
+
   
   argc = orig_argc;
   argv = orig_argv;
@@ -365,7 +366,8 @@ main (int argc, char **argv )
         case oServer: pipe_server = 1; break;
         case oDaemon: is_daemon = 1; break;
 
-        case oReaderPort: reader_port = pargs.r.ret_int; break;
+        case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break;
+        case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
 
         default : pargs.err = configfp? 1:2; break;
        }
index b21e19f..bdc4c21 100644 (file)
@@ -53,6 +53,7 @@ struct {
   int dry_run;      /* don't change any persistent data */
   int batch;        /* batch mode */
   const char *homedir; /* configuration directory name */
+  const char *ctapi_driver; /* Library to access the ctAPI. */
 } opt;