Forgot to commit the recent fixed to scd and logging - doing it now

This commit is contained in:
Werner Koch 2005-02-03 13:20:57 +00:00
parent bbe6101177
commit 625bafa4da
8 changed files with 188 additions and 101 deletions

View File

@ -1,3 +1,8 @@
2005-01-17 Werner Koch <wk@g10code.com>
* configure.ac: Make --without-included-regex work as expected.
Fixed FTP location info for some libraries.
2005-01-13 Werner Koch <wk@g10code.com>
Released 1.9.15.

View File

@ -889,7 +889,7 @@ if test "$use_regex" = yes ; then
AC_MSG_CHECKING([whether the included regex lib is requested])
AC_ARG_WITH(included-regex,
[ --with-included-regex use the included GNU regex library],
[gnupg_cv_included_regex=yes],[gnupg_cv_included_regex=no])
[gnupg_cv_included_regex="$withval"],[gnupg_cv_included_regex=no])
AC_MSG_RESULT($gnupg_cv_included_regex)
if test $gnupg_cv_included_regex = no ; then
@ -1060,7 +1060,7 @@ if test "$have_gpg_error" = "no"; then
***
*** You need libgpg-error to build this program.
** This library is for example available at
*** ftp://ftp.gnupg.org/gcrypt/alpha/libgpg-error
*** ftp://ftp.gnupg.org/gcrypt/libgpg-error
*** (at least version $NEED_GPG_ERROR_VERSION is required.)
***]])
fi
@ -1070,7 +1070,7 @@ if test "$have_libgcrypt" = "no"; then
***
*** You need libgcrypt to build this program.
** This library is for example available at
*** ftp://ftp.gnupg.org/gcrypt/alpha/libgcrypt/
*** ftp://ftp.gnupg.org/gcrypt/libgcrypt/
*** (at least version $NEED_LIBGCRYPT_VERSION using API $NEED_LIBGCRYPT_API) is required.)
***]])
fi

View File

@ -1,3 +1,8 @@
2005-01-19 Werner Koch <wk@g10code.com>
* logging.c (fun_writer): Don't fallback to stderr. Print to
stderr only if connected to a tty.
2004-12-20 Werner Koch <wk@g10code.com>
* w32-pth.c (do_pth_event_free): The events are hold in a ring

View File

@ -1,6 +1,6 @@
/* logging.c - useful logging functions
* Copyright (C) 1998, 1999, 2000, 2001, 2003,
* 2004 Free Software Foundation, Inc.
* 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -20,11 +20,6 @@
*/
/* This file should replace logger.c in the future - for now it is not
* used by GnuPG but by GPA.
* It is a quite simple implemenation but sufficient for most purposes.
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
@ -64,23 +59,6 @@ static int force_prefixes;
static int missing_lf;
static int errorcount;
#if 0
static void
write2stderr( const char *s )
{
write( 2, s, strlen(s) );
}
static void
do_die(int rc, const char *text )
{
write2stderr("\nFatal error: ");
write2stderr(text);
write2stderr("\n");
abort();
}
#endif
int
log_get_errorcount (int clear)
@ -150,7 +128,8 @@ fun_writer (void *cookie_arg, const char *buffer, size_t size)
cookie->fd = socket (PF_LOCAL, SOCK_STREAM, 0);
if (cookie->fd == -1)
{
if (!cookie->quiet && !running_detached)
if (!cookie->quiet && !running_detached
&& isatty (fileno (stderr)))
fprintf (stderr, "failed to create socket for logging: %s\n",
strerror(errno));
}
@ -168,7 +147,8 @@ fun_writer (void *cookie_arg, const char *buffer, size_t size)
if (connect (cookie->fd, (struct sockaddr *) &addr, addrlen) == -1)
{
if (!cookie->quiet && !running_detached)
if (!cookie->quiet && !running_detached
&& isatty (fileno (stderr)))
fprintf (stderr, "can't connect to `%s': %s\n",
cookie->name, strerror(errno));
close (cookie->fd);
@ -180,12 +160,16 @@ fun_writer (void *cookie_arg, const char *buffer, size_t size)
{
if (!running_detached)
{
/* Due to all the problems with apps not running
detahced but beeing caled with stderr closed or
used for a different purposes, it does not make
sense to switch to stderr. We tehrefore disable it. */
if (!cookie->quiet)
{
fputs ("switching logging to stderr\n", stderr);
/* fputs ("switching logging to stderr\n", stderr);*/
cookie->quiet = 1;
}
cookie->fd = fileno (stderr);
cookie->fd = -1; /*fileno (stderr);*/
}
}
else /* Connection has been established. */
@ -199,7 +183,8 @@ fun_writer (void *cookie_arg, const char *buffer, size_t size)
if (cookie->fd != -1 && !writen (cookie->fd, buffer, size))
return size; /* Okay. */
if (!running_detached && cookie->fd != -1)
if (!running_detached && cookie->fd != -1
&& isatty (fileno (stderr)))
{
if (*cookie->name)
fprintf (stderr, "error writing to `%s': %s\n",

View File

@ -1,3 +1,28 @@
2005-01-26 Werner Koch <wk@g10code.com>
* ccid-driver.c (parse_ccid_descriptor): Need the CSM workaround
also for newer firmware versions. Need to get a list of fixed
firmware versions and use that.
2005-01-25 Werner Koch <wk@g10code.com>
* apdu.c (apdu_send_le, apdu_send_direct): Fix some compiler
warnings.
* app-openpgp.c (get_cached_data): New arg GET_IMMEDIATE to bypass
the cache. Changed all callers.
(get_one_do): Bypass the cache if the value would have been read
directly for v1.1 cards.It makes things a bit slower but obnly for
1.0 cards and there are not that many cards out in the wild. This
is required to fix a caching bug when generating new keys; as a
side effect of the retrieval of the the C4 DO from the 6E DO the
cached fingerprint will get updated to the old value and later
when signing the generated key the checking of the fingerprint
fails becuase it won't match the new one. Thanks to Moritz for
analyzing this problem.
(verify_chv3): Removed the CHV status reread logic because we
won't cache the C4 DO anymore.
2004-12-28 Werner Koch <wk@g10code.com>
* ccid-driver.c (find_endpoint): New.

View File

@ -2721,7 +2721,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
resultlen -= 2;
if (DBG_CARD_IO)
{
log_debug (" response: sw=%04X datalen=%d\n", sw, resultlen);
log_debug (" response: sw=%04X datalen=%d\n",
sw, (unsigned int)resultlen);
if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
log_printhex (" dump: ", result, resultlen);
}
@ -2787,7 +2788,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
resultlen -= 2;
if (DBG_CARD_IO)
{
log_debug (" more: sw=%04X datalen=%d\n", sw, resultlen);
log_debug (" more: sw=%04X datalen=%d\n",
sw, (unsigned int)resultlen);
if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
log_printhex (" dump: ", result, resultlen);
}
@ -2920,7 +2922,8 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
resultlen -= 2;
if (DBG_CARD_IO)
{
log_debug (" response: sw=%04X datalen=%d\n", sw, resultlen);
log_debug (" response: sw=%04X datalen=%d\n",
sw, (unsigned int)resultlen);
if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
log_printhex (" dump: ", result, resultlen);
}
@ -2972,7 +2975,8 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
resultlen -= 2;
if (DBG_CARD_IO)
{
log_debug (" more: sw=%04X datalen=%d\n", sw, resultlen);
log_debug (" more: sw=%04X datalen=%d\n",
sw, (unsigned int)resultlen);
if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
log_printhex (" dump: ", result, resultlen);
}

View File

@ -1,5 +1,5 @@
/* app-openpgp.c - The OpenPGP card application.
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -79,8 +79,13 @@ static struct {
{ 0x00C4, 0, 0x6E, 1, 0, 1, 1, "CHV Status Bytes" },
{ 0x00C5, 0, 0x6E, 1, 0, 0, 0, "Fingerprints" },
{ 0x00C6, 0, 0x6E, 1, 0, 0, 0, "CA Fingerprints" },
{ 0x00CD, 0, 0x6E, 1, 0, 0, 0, "Generation time" },
{ 0x007A, 1, 0, 1, 0, 0, 0, "Security Support Template" },
{ 0x0093, 0, 0x7A, 1, 1, 0, 0, "Digital Signature Counter" },
{ 0x0101, 0, 0, 0, 0, 0, 0, "Private DO 1"},
{ 0x0102, 0, 0, 0, 0, 0, 0, "Private DO 2"},
{ 0x0103, 0, 0, 0, 0, 0, 0, "Private DO 3"},
{ 0x0104, 0, 0, 0, 0, 0, 0, "Private DO 4"},
{ 0 }
};
@ -133,10 +138,12 @@ do_deinit (app_t app)
/* Wrapper around iso7816_get_data which first tries to get the data
from the cache. */
from the cache. With GET_IMMEDIATE passed as true, the cache is
bypassed. */
static gpg_error_t
get_cached_data (app_t app, int tag,
unsigned char **result, size_t *resultlen)
unsigned char **result, size_t *resultlen,
int get_immediate)
{
gpg_error_t err;
int i;
@ -147,23 +154,25 @@ get_cached_data (app_t app, int tag,
*result = NULL;
*resultlen = 0;
for (c=app->app_local->cache; c; c = c->next)
if (c->tag == tag)
{
if(c->length)
if (!get_immediate)
{
for (c=app->app_local->cache; c; c = c->next)
if (c->tag == tag)
{
p = xtrymalloc (c->length);
if (!p)
return gpg_error (gpg_err_code_from_errno (errno));
memcpy (p, c->data, c->length);
*result = p;
if(c->length)
{
p = xtrymalloc (c->length);
if (!p)
return gpg_error (gpg_err_code_from_errno (errno));
memcpy (p, c->data, c->length);
*result = p;
}
*resultlen = c->length;
return 0;
}
*resultlen = c->length;
return 0;
}
}
err = iso7816_get_data (app->slot, tag, &p, &len);
if (err)
@ -172,6 +181,9 @@ get_cached_data (app_t app, int tag,
*resultlen = len;
/* Check whether we should cache this object. */
if (get_immediate)
return 0;
for (i=0; data_objects[i].tag; i++)
if (data_objects[i].tag == tag)
{
@ -180,8 +192,7 @@ get_cached_data (app_t app, int tag,
break;
}
/* No, cache it. */
/* Okay, cache it. */
for (c=app->app_local->cache; c; c = c->next)
assert (c->tag != tag);
@ -294,7 +305,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
if (data_objects[i].tag && data_objects[i].get_from)
{
rc = get_cached_data (app, data_objects[i].get_from,
&buffer, &buflen);
&buffer, &buflen,
data_objects[i].get_immediate_in_v11);
if (!rc)
{
const unsigned char *s;
@ -315,7 +327,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
if (!value) /* Not in a constructed DO, try simple. */
{
rc = get_cached_data (app, tag, &buffer, &buflen);
rc = get_cached_data (app, tag, &buffer, &buflen,
data_objects[i].get_immediate_in_v11);
if (!rc)
{
value = buffer;
@ -421,7 +434,7 @@ count_bits (const unsigned char *a, size_t len)
at any time and should be called after changing the login-data DO.
Everything up to a LF is considered a mailbox or account name. If
the first LF is follewed by DC4 (0x14) control sequence are
the first LF is followed by DC4 (0x14) control sequence are
expected up to the next LF. Control sequences are separated by FS
(0x28) and consist of key=value pairs. There is one key defined:
@ -575,6 +588,23 @@ send_fpr_if_not_null (ctrl_t ctrl, const char *keyword,
buf, (size_t)strlen (buf), NULL, 0);
}
static void
send_fprtime_if_not_null (ctrl_t ctrl, const char *keyword,
int number, const unsigned char *stamp)
{
char numbuf1[50], numbuf2[50];
unsigned long value;
value = (stamp[0] << 24) | (stamp[1]<<16) | (stamp[2]<<8) | stamp[3];
if (!value)
return;
sprintf (numbuf1, "%d", number);
sprintf (numbuf2, "%lu", value);
send_status_info (ctrl, keyword,
numbuf1, (size_t)strlen(numbuf1),
numbuf2, (size_t)strlen(numbuf2), NULL, 0);
}
static void
send_key_data (ctrl_t ctrl, const char *name,
const unsigned char *a, size_t alen)
@ -607,12 +637,17 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
{ "DISP-SEX", 0x5F35 },
{ "PUBKEY-URL", 0x5F50 },
{ "KEY-FPR", 0x00C5, 3 },
{ "KEY-TIME", 0x00CD, 4 },
{ "CA-FPR", 0x00C6, 3 },
{ "CHV-STATUS", 0x00C4, 1 },
{ "CHV-STATUS", 0x00C4, 1 },
{ "SIG-COUNTER", 0x0093, 2 },
{ "SERIALNO", 0x004F, -1 },
{ "AID", 0x004F },
{ "EXTCAP", 0x0000, -2 },
{ "PRIVATE-DO-1", 0x0101 },
{ "PRIVATE-DO-2", 0x0102 },
{ "PRIVATE-DO-3", 0x0103 },
{ "PRIVATE-DO-4", 0x0104 },
{ NULL, 0 }
};
int idx, i;
@ -686,6 +721,12 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
for (i=0; i < 3; i++)
send_fpr_if_not_null (ctrl, table[idx].name, i+1, value+i*20);
}
else if (table[idx].special == 4)
{
if (valuelen >= 12)
for (i=0; i < 3; i++)
send_fprtime_if_not_null (ctrl, table[idx].name, i+1, value+i*4);
}
else
send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0);
@ -705,9 +746,20 @@ do_learn_status (app_t app, ctrl_t ctrl)
do_getattr (app, ctrl, "PUBKEY-URL");
do_getattr (app, ctrl, "LOGIN-DATA");
do_getattr (app, ctrl, "KEY-FPR");
if (app->card_version > 0x0100)
do_getattr (app, ctrl, "KEY-TIME");
do_getattr (app, ctrl, "CA-FPR");
do_getattr (app, ctrl, "CHV-STATUS");
do_getattr (app, ctrl, "SIG-COUNTER");
if (app->app_local->extcap.private_dos)
{
do_getattr (app, ctrl, "PRIVATE-DO-1");
do_getattr (app, ctrl, "PRIVATE-DO-2");
if (app->did_chv2)
do_getattr (app, ctrl, "PRIVATE-DO-3");
if (app->did_chv3)
do_getattr (app, ctrl, "PRIVATE-DO-4");
}
return 0;
}
@ -792,8 +844,6 @@ verify_chv3 (app_t app,
void *relptr;
unsigned char *value;
size_t valuelen;
int reread_chv_status;
relptr = get_one_do (app, 0x00C4, &value, &valuelen);
if (!relptr || valuelen < 7)
@ -809,13 +859,14 @@ verify_chv3 (app_t app,
return gpg_error (GPG_ERR_BAD_PIN);
}
reread_chv_status = (value[6] < 3);
log_info(_("%d Admin PIN attempts remaining before card"
" is permanently locked\n"), value[6]);
xfree (relptr);
rc = pincb (pincb_arg, _("Admin PIN"), &pinvalue);
/* TRANSLATORS: Do not translate the "|A|" prefix but
keep it at the start of the string. We need this elsewhere
to get some infos on the string. */
rc = pincb (pincb_arg, _("|A|Admin PIN"), &pinvalue);
if (rc)
{
log_info (_("PIN callback returned error: %s\n"), gpg_strerror (rc));
@ -839,13 +890,6 @@ verify_chv3 (app_t app,
return rc;
}
app->did_chv3 = 1;
/* If the PIN has been entered wrongly before, we need to flush
the cached value so that the next read correctly reflects the
resetted retry counter. Note that version 1.1 of the specs
allow direct reading of that DO, so that we could actually
flush it in all cases. */
if (reread_chv_status)
flush_cache_item (app, 0x00C4);
}
return rc;
}
@ -864,17 +908,22 @@ do_setattr (app_t app, const char *name,
static struct {
const char *name;
int tag;
int need_chv;
int special;
} table[] = {
{ "DISP-NAME", 0x005B },
{ "LOGIN-DATA", 0x005E, 2 },
{ "DISP-LANG", 0x5F2D },
{ "DISP-SEX", 0x5F35 },
{ "PUBKEY-URL", 0x5F50 },
{ "CHV-STATUS-1", 0x00C4, 1 },
{ "CA-FPR-1", 0x00CA },
{ "CA-FPR-2", 0x00CB },
{ "CA-FPR-3", 0x00CC },
{ "DISP-NAME", 0x005B, 3 },
{ "LOGIN-DATA", 0x005E, 3, 2 },
{ "DISP-LANG", 0x5F2D, 3 },
{ "DISP-SEX", 0x5F35, 3 },
{ "PUBKEY-URL", 0x5F50, 3 },
{ "CHV-STATUS-1", 0x00C4, 3, 1 },
{ "CA-FPR-1", 0x00CA, 3 },
{ "CA-FPR-2", 0x00CB, 3 },
{ "CA-FPR-3", 0x00CC, 3 },
{ "PRIVATE-DO-1", 0x0101, 2 },
{ "PRIVATE-DO-2", 0x0102, 3 },
{ "PRIVATE-DO-3", 0x0103, 2 },
{ "PRIVATE-DO-4", 0x0104, 3 },
{ NULL, 0 }
};
@ -884,7 +933,17 @@ do_setattr (app_t app, const char *name,
if (!table[idx].name)
return gpg_error (GPG_ERR_INV_NAME);
rc = verify_chv3 (app, pincb, pincb_arg);
switch (table[idx].need_chv)
{
case 2:
rc = verify_chv2 (app, pincb, pincb_arg);
break;
case 3:
rc = verify_chv3 (app, pincb, pincb_arg);
break;
default:
rc = 0;
}
if (rc)
return rc;
@ -953,10 +1012,14 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode,
else
app->did_chv1 = app->did_chv2 = 0;
rc = pincb (pincb_arg, chvno == 3? "New Admin PIN" : "New PIN", &pinvalue);
/* Note to translators: Do not translate the "|*|" prefixes but
keep it at the start of the string. We need this elsewhere
to get some infos on the string. */
rc = pincb (pincb_arg, chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"),
&pinvalue);
if (rc)
{
log_error ("error getting new PIN: %s\n", gpg_strerror (rc));
log_error (_("error getting new PIN: %s\n"), gpg_strerror (rc));
goto leave;
}
@ -1022,14 +1085,14 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
if (rc)
{
log_error ("error reading application data\n");
log_error (_("error reading application data\n"));
return gpg_error (GPG_ERR_GENERAL);
}
fpr = find_tlv (buffer, buflen, 0x00C5, &n);
if (!fpr || n != 60)
{
rc = gpg_error (GPG_ERR_GENERAL);
log_error ("error reading fingerprint DO\n");
log_error (_("error reading fingerprint DO\n"));
goto leave;
}
fpr += 20*keyno;
@ -1038,13 +1101,13 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
if (i!=20 && !force)
{
rc = gpg_error (GPG_ERR_EEXIST);
log_error ("key already exists\n");
log_error (_("key already exists\n"));
goto leave;
}
else if (i!=20)
log_info ("existing key will be replaced\n");
log_info (_("existing key will be replaced\n"));
else
log_info ("generating new key\n");
log_info (_("generating new key\n"));
rc = verify_chv3 (app, pincb, pincb_arg);
@ -1054,7 +1117,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
xfree (buffer); buffer = NULL;
#if 1
log_info ("please wait while key is being generated ...\n");
log_info (_("please wait while key is being generated ...\n"));
start_at = time (NULL);
rc = iso7816_generate_keypair
#else
@ -1069,16 +1132,16 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
if (rc)
{
rc = gpg_error (GPG_ERR_CARD);
log_error ("generating key failed\n");
log_error (_("generating key failed\n"));
goto leave;
}
log_info ("key generation completed (%d seconds)\n",
log_info (_("key generation completed (%d seconds)\n"),
(int)(time (NULL) - start_at));
keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen);
if (!keydata)
{
rc = gpg_error (GPG_ERR_CARD);
log_error ("response does not contain the public key data\n");
log_error (_("response does not contain the public key data\n"));
goto leave;
}
@ -1086,7 +1149,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
if (!m)
{
rc = gpg_error (GPG_ERR_CARD);
log_error ("response does not contain the RSA modulus\n");
log_error (_("response does not contain the RSA modulus\n"));
goto leave;
}
/* log_printhex ("RSA n:", m, mlen); */
@ -1096,7 +1159,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
if (!e)
{
rc = gpg_error (GPG_ERR_CARD);
log_error ("response does not contain the RSA public exponent\n");
log_error (_("response does not contain the RSA public exponent\n"));
goto leave;
}
/* log_printhex ("RSA e:", e, elen); */
@ -1129,7 +1192,7 @@ convert_sig_counter_value (const unsigned char *value, size_t valuelen)
ul = (value[0] << 16) | (value[1] << 8) | value[2];
else
{
log_error ("invalid structure of OpenPGP card (DO 0x93)\n");
log_error (_("invalid structure of OpenPGP card (DO 0x93)\n"));
ul = 0;
}
return ul;
@ -1161,17 +1224,17 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
assert (keyno >= 1 && keyno <= 3);
rc = get_cached_data (app, 0x006E, &buffer, &buflen);
rc = get_cached_data (app, 0x006E, &buffer, &buflen, 0);
if (rc)
{
log_error ("error reading application data\n");
log_error (_("error reading application data\n"));
return gpg_error (GPG_ERR_GENERAL);
}
fpr = find_tlv (buffer, buflen, 0x00C5, &n);
if (!fpr || n != 60)
{
xfree (buffer);
log_error ("error reading fingerprint DO\n");
log_error (_("error reading fingerprint DO\n"));
return gpg_error (GPG_ERR_GENERAL);
}
fpr += (keyno-1)*20;
@ -1290,7 +1353,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
memcpy (data+15, indata, indatalen);
sigcount = get_sig_counter (app);
log_info ("signatures created so far: %lu\n", sigcount);
log_info (_("signatures created so far: %lu\n"), sigcount);
if (!app->did_chv1 || app->force_chv1 )
{

View File

@ -403,7 +403,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
if (buf[49] == 0xff)
DEBUGOUT_CONT ("echo\n");
else
DEBUGOUT_1 (" %02X\n", buf[48]);
DEBUGOUT_CONT_1 (" %02X\n", buf[48]);
DEBUGOUT ( " wlcdLayout ");
if (!buf[50] && !buf[51])
@ -450,7 +450,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
if (handle->id_vendor == VENDOR_SCM
/* FIXME: check whether it is the same
firmware version for all drivers. */
&& handle->bcd_device < 0x0513
&& handle->bcd_device < 0x0519
&& handle->max_ifsd > 48)
{
DEBUGOUT ("enabling workaround for buggy SCM readers\n");