Add a way to get a listing of available CCID readers.

This commit is contained in:
Werner Koch 2007-04-03 16:57:37 +00:00
parent 12cc96a176
commit 3bbc481935
10 changed files with 170 additions and 52 deletions

View File

@ -1,4 +1,4 @@
/* sexputil.c - Utility fnctions for S-expressions. /* sexputil.c - Utility functions for S-expressions.
* Copyright (C) 2005 Free Software Foundation, Inc. * Copyright (C) 2005 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.

View File

@ -501,7 +501,7 @@ checking of some root certificate requirements.
As a special feature a line @code{include-default} will include a global As a special feature a line @code{include-default} will include a global
list of trusted certificates (e.g. @file{/etc/gnupg/trustlist.txt}). list of trusted certificates (e.g. @file{/etc/gnupg/trustlist.txt}).
This global list is also used if the local list ios not available. This global list is also used if the local list is not available.
@item sshcontrol @item sshcontrol

View File

@ -251,6 +251,13 @@ readers might need a string here; run the program in verbose mode to get
a list of available readers. The default is then the first reader a list of available readers. The default is then the first reader
found. found.
To get a list of available CCID readers you may use this command:
@smallexample
echo scd getinfo reader_list | gpg-connect-agent --decode | awk '/^D/ @{print $2@}'
@end smallexample
@item --disable-keypad @item --disable-keypad
@opindex disable-keypad @opindex disable-keypad
Even if a card reader features a keypad, do not try to use it. Even if a card reader features a keypad, do not try to use it.

View File

@ -955,6 +955,16 @@ When using @option{-S} or @option{--exec}, @command{gpg-connect-agent}
connects to the assuan server in extended mode to allow descriptor connects to the assuan server in extended mode to allow descriptor
passing. This option makes it use the old mode. passing. This option makes it use the old mode.
@item --hex
@opindex hex
Print data lines in a hex format and the ASCII representation of
non-control characters.
@item --decode
@opindex decode
Decode data lines. That is to remove percent escapes but make sure that
a new line always starts with a D and a space.
@end table @end table
@mansect control commands @mansect control commands
@ -995,6 +1005,14 @@ input source for other commands.
@item /recvfd @item /recvfd
Not yet implemented. Not yet implemented.
@item /hex
@itemx /nohex
Same as the command line option @option{--hex}.
@item /decode
@itemx /nodecode
Same as the command line option @option{--decode}.
@item /help @item /help
Print a list of available control commands. Print a list of available control commands.

View File

@ -1,3 +1,9 @@
2007-04-03 Werner Koch <wk@g10code.com>
* command.c (cmd_getinfo): New subcommand "reader_list".
* ccid-driver.c (scan_or_find_devices): Ignore EBUSY in scan mode
for special transports.
2007-03-07 Werner Koch <wk@g10code.com> 2007-03-07 Werner Koch <wk@g10code.com>
* app-dinsig.c: Include i18n.h. * app-dinsig.c: Include i18n.h.

View File

@ -989,7 +989,13 @@ scan_or_find_devices (int readerno, const char *readerid,
char *rid, *p; char *rid, *p;
fd = open (transports[i].name, O_RDWR); fd = open (transports[i].name, O_RDWR);
if (fd == -1) if (fd == -1 && scan_mode && errno == EBUSY)
{
/* Ignore this error in scan mode because it indicates that
the device exists but is already open (most likely by us)
and thus in general suitable as a reader. */
}
else if (fd == -1)
{ {
DEBUGOUT_2 ("failed to open `%s': %s\n", DEBUGOUT_2 ("failed to open `%s': %s\n",
transports[i].name, strerror (errno)); transports[i].name, strerror (errno));
@ -999,7 +1005,8 @@ scan_or_find_devices (int readerno, const char *readerid,
rid = malloc (strlen (transports[i].name) + 30 + 10); rid = malloc (strlen (transports[i].name) + 30 + 10);
if (!rid) if (!rid)
{ {
close (fd); if (fd != -1)
close (fd);
free (rid_list); free (rid_list);
return -1; /* Error. */ return -1; /* Error. */
} }
@ -1010,7 +1017,8 @@ scan_or_find_devices (int readerno, const char *readerid,
p = malloc ((rid_list? strlen (rid_list):0) + 1 + strlen (rid) + 1); p = malloc ((rid_list? strlen (rid_list):0) + 1 + strlen (rid) + 1);
if (!p) if (!p)
{ {
close (fd); if (fd != -1)
close (fd);
free (rid_list); free (rid_list);
free (rid); free (rid);
return -1; /* Error. */ return -1; /* Error. */
@ -1046,7 +1054,8 @@ scan_or_find_devices (int readerno, const char *readerid,
--readerno; --readerno;
} }
free (rid); free (rid);
close (fd); if (fd != -1)
close (fd);
} }
if (scan_mode) if (scan_mode)

View File

@ -38,6 +38,9 @@
#include "app-common.h" #include "app-common.h"
#include "apdu.h" /* Required for apdu_*_reader (). */ #include "apdu.h" /* Required for apdu_*_reader (). */
#include "exechelp.h" #include "exechelp.h"
#ifdef HAVE_LIBUSB
#include "ccid-driver.h"
#endif
/* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */ /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
#define MAXLEN_PIN 100 #define MAXLEN_PIN 100
@ -1382,12 +1385,16 @@ cmd_unlock (assuan_context_t ctx, char *line)
Supported values of WHAT are: Supported values of WHAT are:
socket_name - Return the name of the socket. socket_name - Return the name of the socket.
status - Return the status of the current slot (in the future, may status - Return the status of the current slot (in the future, may
also return the status of all slots). The status is a list of also return the status of all slots). The status is a list of
one-character flags. The following flags are currently defined: one-character flags. The following flags are currently defined:
'u' Usable card present. This is the normal state during operation. 'u' Usable card present. This is the normal state during operation.
'r' Card removed. A reset is necessary. 'r' Card removed. A reset is necessary.
These flags are exclusive. These flags are exclusive.
reader_list - Return a list of detected card readers. Does
currently only work with the internal CCID driver.
*/ */
static int static int
@ -1427,6 +1434,20 @@ cmd_getinfo (assuan_context_t ctx, char *line)
} }
rc = assuan_send_data (ctx, &flag, 1); rc = assuan_send_data (ctx, &flag, 1);
} }
else if (!strcmp (line, "reader_list"))
{
#ifdef HAVE_LIBUSB
char *s = ccid_get_reader_list ();
#else
char *s = NULL;
#endif
if (s)
rc = assuan_send_data (ctx, s, strlen (s));
else
rc = gpg_error (GPG_ERR_NO_DATA);
xfree (s);
}
else else
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
return rc; return rc;

View File

@ -6,9 +6,9 @@
as much memory as required. as much memory as required.
(gpgsm_get_keygrip_hexstring): Use bin2hex. (gpgsm_get_keygrip_hexstring): Use bin2hex.
* certchain.c (gpgsm_validate_chain): Keep terack of the * certchain.c (gpgsm_validate_chain): Keep track of the
certificate chain and reset the ephemeral flags. certificate chain and reset the ephemeral flags.
* keydb.c (keydb_set_cert_flags): New args EPHEMERAL MASK. * keydb.c (keydb_set_cert_flags): New args EPHEMERAL and MASK.
Changed caller to use a mask of ~0. Return a proper error code if Changed caller to use a mask of ~0. Return a proper error code if
the certificate is not available. the certificate is not available.

View File

@ -1,3 +1,9 @@
2007-04-03 Werner Koch <wk@g10code.com>
* gpg-connect-agent.c (main): New option --decode and commands
decode and undecode.
(read_and_print_response): Implement option.
2007-03-20 Werner Koch <wk@g10code.com> 2007-03-20 Werner Koch <wk@g10code.com>
* gpgconf-comp.c (gc_options_gpgsm): Add p12-charset. * gpgconf-comp.c (gc_options_gpgsm): Add p12-charset.

View File

@ -1,5 +1,5 @@
/* gpg-connect-agent.c - Tool to connect to the agent. /* gpg-connect-agent.c - Tool to connect to the agent.
* Copyright (C) 2005 Free Software Foundation, Inc. * Copyright (C) 2005, 2007 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -46,6 +46,7 @@ enum cmd_and_opt_values
oNoVerbose = 500, oNoVerbose = 500,
oHomedir, oHomedir,
oHex, oHex,
oDecode,
oNoExtConnect oNoExtConnect
}; };
@ -59,6 +60,7 @@ static ARGPARSE_OPTS opts[] =
{ oVerbose, "verbose", 0, N_("verbose") }, { oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("quiet") }, { oQuiet, "quiet", 0, N_("quiet") },
{ oHex, "hex", 0, N_("print data out hex encoded") }, { oHex, "hex", 0, N_("print data out hex encoded") },
{ oDecode,"decode", 0, N_("decode received data lines") },
{ oRawSocket, "raw-socket", 2, N_("|NAME|connect to Assuan socket NAME")}, { oRawSocket, "raw-socket", 2, N_("|NAME|connect to Assuan socket NAME")},
{ oExec, "exec", 0, N_("run the Assuan server given on the command line")}, { oExec, "exec", 0, N_("run the Assuan server given on the command line")},
{ oNoExtConnect, "no-ext-connect", { oNoExtConnect, "no-ext-connect",
@ -78,6 +80,7 @@ struct
int quiet; /* Be extra quiet. */ int quiet; /* Be extra quiet. */
const char *homedir; /* Configuration directory name */ const char *homedir; /* Configuration directory name */
int hex; /* Print data lines in hex format. */ int hex; /* Print data lines in hex format. */
int decode; /* Decode received data lines. */
const char *raw_socket; /* Name of socket to connect in raw mode. */ const char *raw_socket; /* Name of socket to connect in raw mode. */
int exec; /* Run the pgm given on the command line. */ int exec; /* Run the pgm given on the command line. */
unsigned int connect_flags; /* Flags used for connecting. */ unsigned int connect_flags; /* Flags used for connecting. */
@ -306,6 +309,7 @@ main (int argc, char **argv)
case oNoVerbose: opt.verbose = 0; break; case oNoVerbose: opt.verbose = 0; break;
case oHomedir: opt.homedir = pargs.r.ret_str; break; case oHomedir: opt.homedir = pargs.r.ret_str; break;
case oHex: opt.hex = 1; break; case oHex: opt.hex = 1; break;
case oDecode: opt.decode = 1; break;
case oRawSocket: opt.raw_socket = pargs.r.ret_str; break; case oRawSocket: opt.raw_socket = pargs.r.ret_str; break;
case oExec: opt.exec = 1; break; case oExec: opt.exec = 1; break;
case oNoExtConnect: opt.connect_flags &= ~(1); break; case oNoExtConnect: opt.connect_flags &= ~(1); break;
@ -436,6 +440,14 @@ main (int argc, char **argv)
do_recvfd (ctx, p); do_recvfd (ctx, p);
continue; continue;
} }
else if (!strcmp (cmd, "hex"))
opt.hex = 1;
else if (!strcmp (cmd, "nohex"))
opt.hex = 0;
else if (!strcmp (cmd, "decode"))
opt.decode = 1;
else if (!strcmp (cmd, "nodecode"))
opt.decode = 0;
else if (!strcmp (cmd, "help")) else if (!strcmp (cmd, "help"))
{ {
puts ( puts (
@ -451,7 +463,9 @@ main (int argc, char **argv)
"/cleardef Delete all definitions.\n" "/cleardef Delete all definitions.\n"
"/sendfd FILE MODE Open FILE and pass descriptor to server.\n" "/sendfd FILE MODE Open FILE and pass descriptor to server.\n"
"/recvfd Receive FD from server and print. \n" "/recvfd Receive FD from server and print. \n"
"/help Print this help."); "/[no]hex Enable hex dumping of received data lines.\n"
"/[no]decode Enable decoding of received data lines.\n"
"/help Print this help.");
} }
else else
log_error (_("unknown command `%s'\n"), cmd ); log_error (_("unknown command `%s'\n"), cmd );
@ -577,6 +591,7 @@ read_and_print_response (assuan_context_t ctx)
size_t linelen; size_t linelen;
assuan_error_t rc; assuan_error_t rc;
int i, j; int i, j;
int need_lf = 0;
for (;;) for (;;)
{ {
@ -628,56 +643,92 @@ read_and_print_response (assuan_context_t ctx)
putchar ('\n'); putchar ('\n');
} }
} }
else if (opt.decode)
{
const unsigned char *s;
int need_d = 1;
int c = 0;
for (j=2, s=(unsigned char*)line+2; j < linelen; j++, s++ )
{
if (need_d)
{
fputs ("D ", stdout);
need_d = 0;
}
if (*s == '%' && j+2 < linelen)
{
s++; j++;
c = xtoi_2 ( s );
s++; j++;
}
else
c = *s;
if (c == '\n')
need_d = 1;
putchar (c);
}
need_lf = (c != '\n');
}
else else
{ {
fwrite (line, linelen, 1, stdout); fwrite (line, linelen, 1, stdout);
putchar ('\n'); putchar ('\n');
} }
} }
else if (linelen >= 1 else
&& line[0] == 'S'
&& (line[1] == '\0' || line[1] == ' '))
{ {
fwrite (line, linelen, 1, stdout); if (need_lf)
putchar ('\n'); {
} putchar ('\n');
else if (linelen >= 2 need_lf = 0;
&& line[0] == 'O' && line[1] == 'K' }
&& (line[2] == '\0' || line[2] == ' '))
{ if (linelen >= 1
fwrite (line, linelen, 1, stdout); && line[0] == 'S'
putchar ('\n'); && (line[1] == '\0' || line[1] == ' '))
return 0; {
fwrite (line, linelen, 1, stdout);
putchar ('\n');
}
else if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
{
fwrite (line, linelen, 1, stdout);
putchar ('\n');
return 0;
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& (line[3] == '\0' || line[3] == ' '))
{
fwrite (line, linelen, 1, stdout);
putchar ('\n');
return 0;
}
else if (linelen >= 7
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
&& line[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
fwrite (line, linelen, 1, stdout);
putchar ('\n');
if (!handle_inquire (ctx, line))
assuan_write_line (ctx, "CANCEL");
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
&& (line[3] == '\0' || line[3] == ' '))
{
fwrite (line, linelen, 1, stdout);
putchar ('\n');
/* Received from server, thus more responses are expected. */
}
else
return gpg_error (GPG_ERR_ASS_INV_RESPONSE);
} }
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& (line[3] == '\0' || line[3] == ' '))
{
fwrite (line, linelen, 1, stdout);
putchar ('\n');
return 0;
}
else if (linelen >= 7
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
&& line[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
fwrite (line, linelen, 1, stdout);
putchar ('\n');
if (!handle_inquire (ctx, line))
assuan_write_line (ctx, "CANCEL");
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
&& (line[3] == '\0' || line[3] == ' '))
{
fwrite (line, linelen, 1, stdout);
putchar ('\n');
/* Received from server, thus more responses are expected. */
}
else
return gpg_error (GPG_ERR_ASS_INV_RESPONSE);
} }
} }