* Makefile.am: Add OPENSC_LIBS to all programs.
authorWerner Koch <wk@gnupg.org>
Mon, 18 Aug 2003 17:34:28 +0000 (17:34 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 18 Aug 2003 17:34:28 +0000 (17:34 +0000)
* scdaemon.c, scdaemon.h: New option --disable-opensc.
* card.c (card_open): Implement it.
* apdu.c (open_osc_reader, osc_send_apdu): New.
(apdu_open_reader) [HAVE_OPENSC]: Use the opensc driver if not
disabled.
(error_string) [HAVE_OPENSC]: Use sc_strerror.
(send_apdu) [HAVE_OPENSC]: Call osc_apdu_send.

ChangeLog
NEWS
acinclude.m4
configure.ac
scd/ChangeLog
scd/Makefile.am
scd/apdu.c
scd/scdaemon.c
scd/scdaemon.h

index 00acca1..7e17224 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2003-08-06  Werner Koch  <wk@gnupg.org>
+
+       * configure.ac: Check for libgpg-error.  Print infos about missing
+       libraries more nicely.
+       * acinclude.m4 (AM_PATH_GPG_ERROR): Added.
+
 2003-08-05  Werner Koch  <wk@gnupg.org>
 
        Released 1.9.0.
diff --git a/NEWS b/NEWS
index d275fdd..14722fb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,10 @@
 Noteworthy changes in version 1.9.1 (unreleased)
 ------------------------------------------------
 
+ * Support for OpenSC is back. scdaemon support a --disable-opensc to
+   disable OpenSC use at runtime, so that PC/SC or ct-API can still be
+   used directly.
+
 
 Noteworthy changes in version 1.9.0 (2003-08-05)
 ------------------------------------------------
index 4237738..0235634 100644 (file)
@@ -636,3 +636,59 @@ AC_DEFUN(AM_PATH_OPENSC,
 ])
 
 
+dnl AM_PATH_GPG_ERROR([MINIMUM-VERSION,
+dnl                   [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgpg-error and define GPG_ERROR_CFLAGS and GPG_ERROR_LIBS
+dnl
+AC_DEFUN(AM_PATH_GPG_ERROR,
+[ AC_ARG_WITH(gpg-error-prefix,
+            AC_HELP_STRING([--with-gpg-error-prefix=PFX],
+                           [prefix where GPG Error is installed (optional)]),
+     gpg_error_config_prefix="$withval", gpg_error_config_prefix="")
+  if test x$gpg_error_config_prefix != x ; then
+     gpg_error_config_args="$gpg_error_config_args --prefix=$gpg_error_config_prefix"
+     if test x${GPG_ERROR_CONFIG+set} != xset ; then
+        GPG_ERROR_CONFIG=$gpg_error_config_prefix/bin/gpg-error-config
+     fi
+  fi
+
+  AC_PATH_PROG(GPG_ERROR_CONFIG, gpg-error-config, no)
+  min_gpg_error_version=ifelse([$1], ,0.0,$1)
+  AC_MSG_CHECKING(for GPG Error - version >= $min_gpg_error_version)
+  ok=no
+  if test "$GPG_ERROR_CONFIG" != "no" ; then
+    req_major=`echo $min_gpg_error_version | \
+               sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+    req_minor=`echo $min_gpg_error_version | \
+               sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+    gpg_error_config_version=`$GPG_ERROR_CONFIG $gpg_error_config_args --version`
+    major=`echo $gpg_error_config_version | \
+               sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+    minor=`echo $gpg_error_config_version | \
+               sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+    if test "$major" -gt "$req_major"; then
+        ok=yes
+    else 
+        if test "$major" -eq "$req_major"; then
+            if test "$minor" -ge "$req_minor"; then
+               ok=yes
+            fi
+        fi
+    fi
+  fi
+  if test $ok = yes; then
+    GPG_ERROR_CFLAGS=`$GPG_ERROR_CONFIG $gpg_error_config_args --cflags`
+    GPG_ERROR_LIBS=`$GPG_ERROR_CONFIG $gpg_error_config_args --libs`
+    AC_MSG_RESULT(yes)
+    ifelse([$2], , :, [$2])
+  else
+    GPG_ERROR_CFLAGS=""
+    GPG_ERROR_LIBS=""
+    AC_MSG_RESULT(no)
+    ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(GPG_ERROR_CFLAGS)
+  AC_SUBST(GPG_ERROR_LIBS)
+])
+
+
index 0d12770..0bf39ba 100644 (file)
@@ -27,8 +27,9 @@ AC_INIT(gnupg, 1.9.1-cvs, gnupg-devel@gnupg.org)
 # feel that the default check for a development version is not
 # sufficient.
 development_version=yes
+NEED_GPG_ERROR_VERSION=0.2
 NEED_LIBGCRYPT_VERSION=1.1.42
-NEED_LIBASSUAN_VERSION=0.0.1
+NEED_LIBASSUAN_VERSION=0.6.0
 NEED_KSBA_VERSION=0.4.6
 NEED_OPENSC_VERSION=0.7.0
 
@@ -47,7 +48,9 @@ AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
 AC_GNU_SOURCE
 
 # Some status variables to give feedback at the end of a configure run
-habe_libassuan=no
+have_gpg_error=no
+have_libgcrypt=no 
+have_libassuan=no
 have_ksba=no
 have_opensc=no
 have_pth=no
@@ -347,58 +350,31 @@ AM_CONDITIONAL(HAVE_DOSISH_SYSTEM, test "$have_dosish_system" = yes)
 #
 
 #
+# libgpg-error is a library with error codes shared between GnuPG
+# related projects.
+#
+AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION"
+                  have_gpg_error=yes,have_gpg_error=no)
+
+
+#
 # Libgcrypt is our generic crypto library
 #
-#AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config)
-#if test -n "$LIBGCRYPT_CONFIG"; then
-#      LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
-#      LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
-#else
-#    AC_MSG_ERROR([[
-#***
-#*** You need libgcrypt to build this program.
-#*** It should be available at the same place you 
-#*** got this software.
-#***]])
-#fi
-#AC_SUBST(LIBGCRYPT_CFLAGS)
-#AC_SUBST(LIBGCRYPT_LIBS)
-AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_VERSION",,
-       AC_MSG_ERROR([[
-***  
-*** libgcrypt was not found. You may want to get it from
-*** ftp://ftp.gnupg.org/pub/gcrypt/alpha/libgcrypt/
-***
-]]))
+AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_VERSION",
+        have_libgcrypt=yes,have_libgcrypt=no)
 
 
 #
 # libassuan is used for IPC
 #
 AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_VERSION",
-                  have_libasssuan=yes,have_libasssun=no)
-if test "$have_libassuan" = "no"; then
-    AC_MSG_ERROR([[
-***
-*** You need libassuan to build this program..
-*** It should be available at the same place you 
-*** got this software.
-***]])
-fi
+                  have_libassuan=yes,have_libassuan=no)
 
 
 #
 # libksba is our X.509 support library
 #
 AM_PATH_KSBA("$NEED_KSBA_VERSION",have_ksba=yes,have_ksba=no)
-if test "$have_ksba" = "no"; then
-    AC_MSG_ERROR([[
-***
-*** You need libksba to build this program..
-*** It should be available at the same place you 
-*** got this software.
-***]])
-fi
 
 
 #
@@ -910,6 +886,64 @@ AC_SUBST(NETLIBS)
 AC_DEFINE(HAVE_JNLIB_LOGGING, 1,
         [Defined if jnlib style logging fucntions are available])
 
+
+
+
+#
+# Print errors here so that they are visible all
+# together and the user can acquire them all together.
+#
+die=no
+if test "$have_gpg_error" = "no"; then
+   die=yes
+   AC_MSG_NOTICE([[
+***  
+*** You need libgpg-error to build this program.
+**  This library is for example available at
+***   ftp://ftp.gnupg.org/pub/gcrypt/alpha/libgpg-error
+*** (at least version $NEED_GPG_ERROR_VERSION is required.)
+***]])
+fi
+if test "$have_libgcrypt" = "no"; then
+   die=yes
+   AC_MSG_NOTICE([[
+***  
+*** You need libgcrypt to build this program.
+**  This library is for example available at
+***   ftp://ftp.gnupg.org/pub/gcrypt/alpha/libgcrypt/
+*** (at least version $NEED_LIBGCRYPT_VERSION is required.)
+***]])
+fi
+if test "$have_libassuan" = "no"; then
+   die=yes
+   AC_MSG_NOTICE([[
+***
+*** You need libassuan to build this program.
+*** This library is for example available at
+***   ftp://ftp.gnupg.org/pub/gcrypt/alpha/libassuan/
+*** (at least version $NEED_LIBASSUAN_VERSION is required).
+***]])
+fi
+if test "$have_ksba" = "no"; then
+   die=yes
+    AC_MSG_NOTICE([[
+***
+*** You need libksba to build this program.
+*** This library is for example available at
+***   ftp://ftp.gnupg.org/pub/gcrypt/alpha/aegypten/
+*** (at least version $NEED_KSBA_VERSION is required).
+***]])
+fi
+
+if test "$die" = "yes"; then
+    AC_MSG_ERROR([[
+***
+*** Required libraries not found. Please consult the above messages
+*** and install them before running configure again.
+***]])
+fi
+
+
 #
 # Decide what to build
 #
index d78c4aa..a1cb11e 100644 (file)
@@ -1,9 +1,24 @@
+2003-08-18  Werner Koch  <wk@gnupg.org>
+
+       * Makefile.am: Add OPENSC_LIBS to all programs. 
+
+       * scdaemon.c, scdaemon.h: New option --disable-opensc.
+       * card.c (card_open): Implement it.
+       * apdu.c (open_osc_reader, osc_send_apdu): New.
+       (apdu_open_reader) [HAVE_OPENSC]: Use the opensc driver if not
+       disabled.
+       (error_string) [HAVE_OPENSC]: Use sc_strerror.
+       (send_apdu) [HAVE_OPENSC]: Call osc_apdu_send.
+
+       * card-p15.c (p15_enum_keypairs, p15_prepare_key): Adjusted for
+       libgpg-error.
+
 2003-08-14  Timo Schulz  <twoaday@freakmail.de>
 
        * apdu.c (ct_activate_card): Change the code a little to avoid
        problems with other readers.
        * Always use 'dynload.h' instead of 'dlfcn.h'.
-       
+
 2003-08-05  Werner Koch  <wk@gnupg.org>
 
        * app-openpgp.c (dump_all_do): Don't analyze constructed DOs after
index 0771beb..5ecadd2 100644 (file)
@@ -50,7 +50,7 @@ sc_investigate_SOURCES = \
 
 sc_investigate_LDADD = \
        ../jnlib/libjnlib.a ../common/libcommon.a \
-       $(LIBGCRYPT_LIBS) @INTLLIBS@ -lgpg-error -ldl
+       $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) @INTLLIBS@ -lgpg-error -ldl
 
 
 sc_copykeys_SOURCES = \
@@ -64,7 +64,7 @@ sc_copykeys_SOURCES = \
 sc_copykeys_LDADD = \
        ../jnlib/libjnlib.a ../common/libcommon.a \
        ../common/libsimple-pwquery.a \
-       $(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@ -ldl
+       $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@ -ldl
 
 
 
index 6afcd67..978d9ae 100644 (file)
@@ -24,6 +24,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#ifdef HAVE_OPENSC
+# include <opensc/opensc.h>
+#endif
 
 #include "scdaemon.h"
 #include "apdu.h"
@@ -34,9 +37,9 @@
                                   insertion of the card (1 = don't wait). */
 
 
-
-/* A global table to keep track of active readers. */
-static struct {
+/* A structure to collect information pertaining to one reader
+   slot. */
+struct reader_table_s {
   int used;            /* True if slot is used. */
   unsigned short port; /* Port number:  0 = unused, 1 - dev/tty */
   int is_ctapi;        /* This is a ctAPI driver. */
@@ -45,10 +48,21 @@ static struct {
     unsigned long card;
     unsigned long protocol;
   } pcsc;
+#ifdef HAVE_OPENSC
+  int is_osc;          /* We are using the OpenSC driver layer. */
+  struct {
+    struct sc_context *ctx;
+    struct sc_card *scard;
+  } osc;
+#endif /*HAVE_OPENSC*/
   int status;
   unsigned char atr[33];
   size_t atrlen;
-} reader_table[MAX_READER];                          
+};
+typedef struct reader_table_s *reader_table_t;
+
+/* A global table to keep track of active readers. */
+static struct reader_table_s reader_table[MAX_READER];
 
 
 /* ct API function pointer. */
@@ -142,6 +156,7 @@ new_reader_slot (void)
     }
   reader_table[reader].used = 1;
   reader_table[reader].is_ctapi = 0;
+  reader_table[reader].is_osc = 0;
   return reader;
 }
 
@@ -513,7 +528,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
   unsigned long recv_len;
   
   if (DBG_CARD_IO)
-    log_printhex ("  CT_data:", apdu, apdulen);
+    log_printhex ("  PCSC_data:", apdu, apdulen);
 
   if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
       send_pci.protocol = PCSC_PROTOCOL_T1;
@@ -529,10 +544,199 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
     log_error ("pcsc_transmit failed: %s (0x%lx)\n",
                pcsc_error_string (err), err);
   
-  return err? -1:0;
+  return err? -1:0; /* FIXME: Return appropriate error code. */
+}
+
+
+#ifdef HAVE_OPENSC
+/* 
+     OpenSC Interface.
+
+     This uses the OpenSC primitives to send APDUs.  We need this
+     because we can't mix OpenSC and native (i.e. ctAPI or PC/SC)
+     access to a card for resource conflict reasons.
+ */
+
+static int
+open_osc_reader (int portno)
+{
+  int err;
+  int slot;
+  reader_table_t slotp;
+
+  slot = new_reader_slot ();
+  if (slot == -1)
+    return -1;
+  slotp = reader_table + slot;
+
+  err = sc_establish_context (&slotp->osc.ctx, "scdaemon");
+  if (err)
+    {
+      log_error ("failed to establish SC context: %s\n", sc_strerror (err));
+      slotp->used = 0;
+      return -1;
+    }
+  if (portno < 0 || portno >= slotp->osc.ctx->reader_count)
+    {
+      log_error ("no card reader available\n");
+      sc_release_context (slotp->osc.ctx);
+      slotp->used = 0;
+      return -1;
+    }
+
+  /* Redirect to our logging facility. */
+  slotp->osc.ctx->error_file = log_get_stream ();
+  slotp->osc.ctx->debug = opt.debug_sc;
+  slotp->osc.ctx->debug_file = log_get_stream ();
+
+  if (sc_detect_card_presence (slotp->osc.ctx->reader[portno], 0) != 1)
+    {
+      log_error ("no card present\n");
+      sc_release_context (slotp->osc.ctx);
+      slotp->used = 0;
+      return -1;
+    }
+  
+  /* We want the standard ISO driver. */
+  /*FIXME: OpenSC does not like "iso7816", so we use EMV for now. */
+  err = sc_set_card_driver(slotp->osc.ctx, "emv");
+  if (err)
+    {
+      log_error ("failed to select the iso7816 driver: %s\n",
+                 sc_strerror (err));
+      sc_release_context (slotp->osc.ctx);
+      slotp->used = 0;
+      return -1;
+    }
+
+  /* Now connect the card and hope that OpenSC won't try to be too
+     smart. */
+  err = sc_connect_card (slotp->osc.ctx->reader[portno], 0,
+                         &slotp->osc.scard);
+  if (err)
+    {
+      log_error ("failed to connect card in reader %d: %s\n",
+                 portno, sc_strerror (err));
+      sc_release_context (slotp->osc.ctx);
+      slotp->used = 0;
+      return -1;
+    }
+  if (opt.verbose)
+    log_info ("connected to card in opensc reader %d using driver `%s'\n",
+              portno, slotp->osc.scard->driver->name);
+
+  err = sc_lock (slotp->osc.scard);
+  if (err)
+    {
+      log_error ("can't lock card in reader %d: %s\n",
+                 portno, sc_strerror (err));
+      sc_disconnect_card (slotp->osc.scard, 0);
+      sc_release_context (slotp->osc.ctx);
+      slotp->used = 0;
+      return -1;
+    }
+
+  if (slotp->osc.scard->atr_len >= DIM (slotp->atr))
+    log_bug ("ATR returned by opensc is too large\n");
+  slotp->atrlen = slotp->osc.scard->atr_len;
+  memcpy (slotp->atr, slotp->osc.scard->atr, slotp->atrlen);
+
+  slotp->is_osc = 1;
+
+  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: OpenSC error code. */
+static int
+osc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
+                unsigned char *buffer, size_t *buflen)
+{
+  long err;
+  struct sc_apdu a;
+  unsigned char data[SC_MAX_APDU_BUFFER_SIZE];
+  unsigned char result[SC_MAX_APDU_BUFFER_SIZE];
+
+  if (DBG_CARD_IO)
+    log_printhex ("  APDU_data:", apdu, apdulen);
+
+  if (apdulen < 4)
+    {
+      log_error ("osc_send_apdu: APDU is too short\n");
+      return SC_ERROR_CMD_TOO_SHORT;
+    }
+
+  memset(&a, 0, sizeof a);
+  a.cla = *apdu++;
+  a.ins = *apdu++;
+  a.p1 = *apdu++;
+  a.p2 = *apdu++;
+  apdulen -= 4;
+
+  if (!apdulen)
+    a.cse = SC_APDU_CASE_1;
+  else if (apdulen == 1) 
+    {
+      a.le = *apdu? *apdu : 256;
+      apdu++; apdulen--;
+      a.cse = SC_APDU_CASE_2_SHORT;
+    }
+  else
+    {
+      a.lc = *apdu++; apdulen--;
+      if (apdulen < a.lc)
+        {
+          log_error ("osc_send_apdu: APDU shorter than specified in Lc\n");
+          return SC_ERROR_CMD_TOO_SHORT;
+
+        }
+      memcpy(data, apdu, a.lc);
+      apdu += a.lc; apdulen -= a.lc;
+
+      a.data = data;
+      a.datalen = a.lc;
+      
+      if (!apdulen)
+        a.cse = SC_APDU_CASE_3_SHORT;
+      else
+        {
+          a.le = *apdu? *apdu : 256;
+          apdu++; apdulen--;
+          if (apdulen)
+            {
+              log_error ("osc_send_apdu: APDU larger than specified\n");
+              return SC_ERROR_CMD_TOO_LONG;
+            }
+          a.cse = SC_APDU_CASE_4_SHORT;
+        }
+    }
+
+  a.resp = result;
+  a.resplen = DIM(result);
+
+  err = sc_transmit_apdu (reader_table[slot].osc.scard, &a);
+  if (err)
+    {
+      log_error ("sc_apdu_transmit failed: %s\n", sc_strerror (err));
+      return err;
+    }
+
+  if (*buflen < 2 || a.resplen > *buflen - 2)
+    {
+      log_error ("osc_send_apdu: provided buffer too short to store result\n");
+      return SC_ERROR_BUFFER_TOO_SMALL;
+    }
+  memcpy (buffer, a.resp, a.resplen);
+  buffer[a.resplen] = a.sw1;
+  buffer[a.resplen+1] = a.sw2;
+  *buflen = a.resplen + 2;
+  return 0;
+}
+
+#endif /* HAVE_OPENSC */
 
 
 \f
@@ -542,12 +746,23 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
 
 /* Open the reader and return an internal slot number or -1 on
    error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
-   the first USB reader.  For PCSC/ the first listed reader. */
+   the first USB reader.  For PC/SC the first listed reader).  IF
+   OpenSC support is cmpiled in, we first try to use OpenSC. */
 int
 apdu_open_reader (const char *portstr)
 {
   static int pcsc_api_loaded, ct_api_loaded;
 
+#ifdef HAVE_OPENSC
+  if (!opt.disable_opensc)
+    {
+      int port = portstr? atoi (portstr) : 0;
+
+      return open_osc_reader (port);
+    }
+#endif /* HAVE_OPENSC */  
+
+
   if (opt.ctapi_driver && *opt.ctapi_driver)
     {
       int port = portstr? atoi (portstr) : 32768;
@@ -648,6 +863,10 @@ error_string (int slot, long rc)
     return "[invalid slot]";
   if (reader_table[slot].is_ctapi)
     return ct_error_string (rc);
+#ifdef HAVE_OPENSC
+  else if (reader_table[slot].is_osc)
+    return sc_strerror (rc);
+#endif
   else
     return pcsc_error_string (rc);
 }
@@ -662,6 +881,10 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
     return SW_HOST_NO_DRIVER;
   if (reader_table[slot].is_ctapi)
     return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
+#ifdef HAVE_OPENSC
+  else if (reader_table[slot].is_osc)
+    return osc_send_apdu (slot, apdu, apdulen, buffer, buflen);
+#endif
   else
     return pcsc_send_apdu (slot, apdu, apdulen, buffer, buflen);
 }
index 1195261..af813b5 100644 (file)
@@ -70,6 +70,7 @@ enum cmd_and_opt_values
   oBatch,
   oReaderPort,
   octapiDriver,
+  oDisableOpenSC,
 
 aTest };
 
@@ -94,6 +95,16 @@ static ARGPARSE_OPTS opts[] = {
   { oLogFile,  "log-file"   ,2, N_("use a log file for the server")},
   { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")},
   { octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ctAPI driver")},
+  { oDisableOpenSC, "disable-opensc", 0,
+#ifdef HAVE_OPENSC
+                                         N_("Do not use the OpenSC layer")
+#else
+                                         "@"
+#endif
+                                         /* end --disable-opensc */},
+
+
+
   {0}
 };
 
@@ -368,6 +379,7 @@ main (int argc, char **argv )
 
         case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break;
         case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
+        case oDisableOpenSC: opt.disable_opensc = 1; break;
 
         default : pargs.err = configfp? 1:2; break;
        }
index bdc4c21..20e2fa7 100644 (file)
@@ -54,6 +54,7 @@ struct {
   int batch;        /* batch mode */
   const char *homedir; /* configuration directory name */
   const char *ctapi_driver; /* Library to access the ctAPI. */
+  int disable_opensc;  /* Disable the sue of the OpenSC framework. */
 } opt;