mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-18 14:17:03 +01:00
* gpg-agent.c (handle_connections): Need to check for events if
select returns with -1. * tools.texi (gpg-connect-agent): New. * app-openpgp.c (get_one_do): Never try to get a non cacheable object from the cache. (get_one_do): Add new arg to return an error code. Changed all callers. (do_getattr): Let it return a proper error code. * app.c (select_application): Return an error code and the application context in an new arg. * command.c (open_card): Adjusted for that. Don't use the fallback if no card is present. Return an error if the card has been removed without a reset. (do_reset, cmd_serialno): Clear that error flag. (TEST_CARD_REMOVAL): New. Use it with all command handlers. * scdaemon.c (ticker_thread): Termintate if a shutdown is pending. * apdu.c: Added some PCSC error codes. (pcsc_error_to_sw): New. (reset_pcsc_reader, pcsc_get_status, pcsc_send_apdu) (open_pcsc_reader): Do proper error code mapping. * gpg-connect-agent.c: New. * Makefile.am: Add it.
This commit is contained in:
parent
4e5bf2fd93
commit
3af261572b
@ -1,3 +1,8 @@
|
||||
2005-02-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg-agent.c (handle_connections): Need to check for events if
|
||||
select returns with -1.
|
||||
|
||||
2005-02-23 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command-ssh.c (get_passphrase): Removed.
|
||||
|
@ -1463,6 +1463,11 @@ handle_connections (int listen_fd, int listen_fd_ssh)
|
||||
ret = pth_select_ev (FD_SETSIZE, &read_fdset, NULL, NULL, NULL, ev);
|
||||
if (ret == -1)
|
||||
{
|
||||
if (pth_event_occurred (ev))
|
||||
{
|
||||
handle_signal (signo);
|
||||
continue;
|
||||
}
|
||||
log_error (_("pth_select failed: %s - waiting 1s\n"),
|
||||
strerror (errno));
|
||||
pth_sleep (1);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* simple-pwquery.c - A simple password query cleint for gpg-agent
|
||||
/* simple-pwquery.c - A simple password query client for gpg-agent
|
||||
* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
|
@ -39,7 +39,7 @@
|
||||
memory was enable and ERRNO is set accordingly.
|
||||
|
||||
If a line has been truncated, the file pointer is moved forward to
|
||||
the end of the line so that the next read start with tghe next
|
||||
the end of the line so that the next read start with the next
|
||||
line. Note that MAX_LENGTH must be re-initialzied in this case..
|
||||
|
||||
Note: The returned buffer is allocated with enough extra space to
|
||||
|
@ -1,3 +1,7 @@
|
||||
2005-02-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* tools.texi (gpg-connect-agent): New.
|
||||
|
||||
2005-02-14 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgsm.texi (Certificate Management): Document --import.
|
||||
|
@ -326,10 +326,8 @@ Ignore requests to change change the current @sc{tty} respective the X
|
||||
window system's @code{DISPLAY} variable. This is useful to lock the
|
||||
pinentry to pop up at the @sc{tty} or display you started the agent.
|
||||
|
||||
@item --ssh-support
|
||||
@itemx --ssh-support
|
||||
@opindex ssh-support
|
||||
@opindex ssh
|
||||
@item --enable-ssh-support
|
||||
@opindex enable-ssh-support
|
||||
|
||||
Enable emulation of the OpenSSH Agent protocol.
|
||||
|
||||
@ -350,13 +348,11 @@ Once, a key has been added to the gpg-agent this way, the gpg-agent
|
||||
will be ready to use the key.
|
||||
|
||||
Note: in case the gpg-agent receives a signature request, the user
|
||||
might need to be prompted for a passphrased, which is necessary for
|
||||
might need to be prompted for a passphrase, which is necessary for
|
||||
decrypting the stored key. Since the ssh-agent protocol does not
|
||||
contain a mechanism for telling the agent on which display/terminal it
|
||||
is running, gpg-agent's --ssh-support switch implies --keep-display
|
||||
and --keep-tty. This strategy causes the gpg-agent to open a pinentry
|
||||
on the display or on the terminal, on which it (the gpg-agent) was
|
||||
started.
|
||||
is running, gpg-agent's ssh-support will use the TTY or X display where
|
||||
gpg-agent has been started.
|
||||
|
||||
@end table
|
||||
|
||||
|
@ -13,6 +13,7 @@ GnuPG comes with a couple of smaller tools:
|
||||
* gpgconf:: Modify .gnupg home directories.
|
||||
* gpgsm-gencert.sh:: Generate an X.509 certificate request.
|
||||
* gpg-preset-passphrase:: Put a passphrase into the cache.
|
||||
* gpg-connect-agent:: Communicate with a running agent.
|
||||
@end menu
|
||||
|
||||
@c
|
||||
@ -665,3 +666,64 @@ for other users.
|
||||
|
||||
|
||||
|
||||
|
||||
@c
|
||||
@c GPG-CONNECT-AGENT
|
||||
@c
|
||||
@node gpg-connect-agent
|
||||
@section Communicate with a runnig agent.
|
||||
|
||||
The @command{gpg-connect-agent} is a utility to communicate with a
|
||||
running @command{gpg-agent}. It is useful to check out the commands
|
||||
gpg-agent provides using the Assuan interface. It might also be useful
|
||||
for scripting simple applications. Inputis expected at stdin and out
|
||||
put gets printed to stdout.
|
||||
|
||||
It is very similar to running @command{gpg-agent} in server mode; but
|
||||
here we connect to a running instance.
|
||||
|
||||
@menu
|
||||
* Invoking gpg-connect-agent:: List of all commands and options.
|
||||
@end menu
|
||||
|
||||
|
||||
@node Invoking gpg-connect-agent
|
||||
@subsection List of all commands and options.
|
||||
|
||||
@noindent
|
||||
@command{gpg-connect-agent} is invoked this way:
|
||||
|
||||
@example
|
||||
gpg-connect-agent [options]
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
The following options may be used:
|
||||
|
||||
@table @gnupgtabopt
|
||||
@item -v
|
||||
@itemx --verbose
|
||||
@opindex verbose
|
||||
Output additional information while running.
|
||||
|
||||
@item -q
|
||||
@item --quiet
|
||||
@opindex q
|
||||
@opindex quiet
|
||||
Try to be as quiet as possible.
|
||||
|
||||
@item --homedir @var{dir}
|
||||
@opindex homedir
|
||||
Set the name of the home directory to @var{dir}. If his option is not
|
||||
used, the home directory defaults to @file{~/.gnupg}. It is only
|
||||
recognized when given on the command line. It also overrides any home
|
||||
directory stated through the environment variable @env{GNUPGHOME} or
|
||||
(on W32 systems) by means on the Registry entry
|
||||
@var{HKCU\Software\GNU\GnuPG:HomeDir}.
|
||||
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +1,26 @@
|
||||
2005-02-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-openpgp.c (get_one_do): Never try to get a non cacheable
|
||||
object from the cache.
|
||||
(get_one_do): Add new arg to return an error code. Changed all
|
||||
callers.
|
||||
(do_getattr): Let it return a proper error code.
|
||||
|
||||
* app.c (select_application): Return an error code and the
|
||||
application context in an new arg.
|
||||
* command.c (open_card): Adjusted for that. Don't use the
|
||||
fallback if no card is present. Return an error if the card has
|
||||
been removed without a reset.
|
||||
(do_reset, cmd_serialno): Clear that error flag.
|
||||
(TEST_CARD_REMOVAL): New. Use it with all command handlers.
|
||||
|
||||
* scdaemon.c (ticker_thread): Termintate if a shutdown is pending.
|
||||
|
||||
* apdu.c: Added some PCSC error codes.
|
||||
(pcsc_error_to_sw): New.
|
||||
(reset_pcsc_reader, pcsc_get_status, pcsc_send_apdu)
|
||||
(open_pcsc_reader): Do proper error code mapping.
|
||||
|
||||
2005-02-22 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-openpgp.c (app_local_s): New field PK.
|
||||
|
121
scd/apdu.c
121
scd/apdu.c
@ -196,6 +196,28 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
|
||||
#define PCSC_STATE_INUSE 0x0100 /* Shared mode. */
|
||||
#define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */
|
||||
|
||||
/* Some PC/SC error codes. */
|
||||
#define PCSC_E_CANCELLED 0x80100002
|
||||
#define PCSC_E_CANT_DISPOSE 0x8010000E
|
||||
#define PCSC_E_INSUFFICIENT_BUFFER 0x80100008
|
||||
#define PCSC_E_INVALID_ATR 0x80100015
|
||||
#define PCSC_E_INVALID_HANDLE 0x80100003
|
||||
#define PCSC_E_INVALID_PARAMETER 0x80100004
|
||||
#define PCSC_E_INVALID_TARGET 0x80100005
|
||||
#define PCSC_E_INVALID_VALUE 0x80100011
|
||||
#define PCSC_E_NO_MEMORY 0x80100006
|
||||
#define PCSC_E_UNKNOWN_READER 0x80100009
|
||||
#define PCSC_E_TIMEOUT 0x8010000A
|
||||
#define PCSC_E_SHARING_VIOLATION 0x8010000B
|
||||
#define PCSC_E_NO_SMARTCARD 0x8010000C
|
||||
#define PCSC_E_UNKNOWN_CARD 0x8010000D
|
||||
#define PCSC_E_PROTO_MISMATCH 0x8010000F
|
||||
#define PCSC_E_NOT_READY 0x80100010
|
||||
#define PCSC_E_SYSTEM_CANCELLED 0x80100012
|
||||
#define PCSC_E_NOT_TRANSACTED 0x80100016
|
||||
#define PCSC_E_READER_UNAVAILABLE 0x80100017
|
||||
#define PCSC_W_REMOVED_CARD 0x80100069
|
||||
|
||||
|
||||
struct pcsc_io_request_s
|
||||
{
|
||||
@ -582,6 +604,10 @@ open_ct_reader (int port)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
PC/SC Interface
|
||||
*/
|
||||
|
||||
#ifdef NEED_PCSC_WRAPPER
|
||||
static int
|
||||
writen (int fd, const void *buf, size_t nbytes)
|
||||
@ -695,9 +721,34 @@ pcsc_error_string (long err)
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
PC/SC Interface
|
||||
*/
|
||||
/* Map PC/SC error codes to our special host status words. */
|
||||
static int
|
||||
pcsc_error_to_sw (long ec)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (ec)
|
||||
{
|
||||
case 0: rc = 0; break;
|
||||
|
||||
case PCSC_E_CANCELLED: rc = SW_HOST_ABORTED; break;
|
||||
case PCSC_E_NO_MEMORY: rc = SW_HOST_OUT_OF_CORE; break;
|
||||
case PCSC_E_TIMEOUT: rc = SW_HOST_CARD_IO_ERROR; break;
|
||||
case PCSC_E_SHARING_VIOLATION: rc = SW_HOST_LOCKING_FAILED; break;
|
||||
case PCSC_E_NO_SMARTCARD: rc = SW_HOST_NO_CARD; break;
|
||||
case PCSC_W_REMOVED_CARD: rc = SW_HOST_NO_CARD; break;
|
||||
|
||||
case PCSC_E_INVALID_TARGET:
|
||||
case PCSC_E_INVALID_VALUE:
|
||||
case PCSC_E_INVALID_HANDLE:
|
||||
case PCSC_E_INVALID_PARAMETER:
|
||||
case PCSC_E_INSUFFICIENT_BUFFER: rc = SW_HOST_INV_VALUE; break;
|
||||
|
||||
default: rc = SW_HOST_GENERAL_ERROR; break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_pcsc_reader_status (int slot)
|
||||
@ -713,6 +764,8 @@ dump_pcsc_reader_status (int slot)
|
||||
}
|
||||
|
||||
|
||||
/* Send an PC/SC reset command and return a status word on error or 0
|
||||
on success. */
|
||||
static int
|
||||
reset_pcsc_reader (int slot)
|
||||
{
|
||||
@ -722,6 +775,7 @@ reset_pcsc_reader (int slot)
|
||||
size_t len;
|
||||
int i, n;
|
||||
unsigned char msgbuf[9];
|
||||
int sw = SW_HOST_CARD_IO_ERROR;
|
||||
|
||||
slotp = reader_table + slot;
|
||||
|
||||
@ -730,7 +784,7 @@ reset_pcsc_reader (int slot)
|
||||
|| slotp->pcsc.pid == (pid_t)(-1) )
|
||||
{
|
||||
log_error ("pcsc_get_status: pcsc-wrapper not running\n");
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return sw;
|
||||
}
|
||||
|
||||
msgbuf[0] = 0x05; /* RESET command. */
|
||||
@ -763,16 +817,23 @@ reset_pcsc_reader (int slot)
|
||||
if (len > DIM (slotp->atr))
|
||||
{
|
||||
log_error ("PC/SC returned a too large ATR (len=%x)\n", len);
|
||||
sw = SW_HOST_GENERAL_ERROR;
|
||||
goto command_failed;
|
||||
}
|
||||
err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
|
||||
if (err)
|
||||
{
|
||||
log_error ("PC/SC RESET failed: %s\n", pcsc_error_string (err));
|
||||
log_error ("PC/SC RESET failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
/* If the error code is no smart card, we should not considere
|
||||
this a major error and close the wrapper. */
|
||||
sw = pcsc_error_to_sw (err);
|
||||
if (err == PCSC_E_NO_SMARTCARD)
|
||||
return sw;
|
||||
goto command_failed;
|
||||
}
|
||||
|
||||
/* The open fucntion may return a zero for the ATR length to
|
||||
/* The open function may return a zero for the ATR length to
|
||||
indicate that no card is present. */
|
||||
n = len;
|
||||
if (n)
|
||||
@ -796,7 +857,7 @@ reset_pcsc_reader (int slot)
|
||||
kill (slotp->pcsc.pid, SIGTERM);
|
||||
slotp->pcsc.pid = (pid_t)(-1);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
return sw;
|
||||
|
||||
#else /* !NEED_PCSC_WRAPPER */
|
||||
long err;
|
||||
@ -827,7 +888,7 @@ reset_pcsc_reader (int slot)
|
||||
log_error ("pcsc_connect failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
reader_table[slot].pcsc.card = 0;
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
|
||||
|
||||
@ -842,7 +903,7 @@ reset_pcsc_reader (int slot)
|
||||
log_error ("pcsc_status failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
reader_table[slot].atrlen = 0;
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
if (atrlen >= DIM (reader_table[0].atr))
|
||||
log_bug ("ATR returned by pcsc_status is too large\n");
|
||||
@ -863,6 +924,7 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
int i, n;
|
||||
unsigned char msgbuf[9];
|
||||
unsigned char buffer[12];
|
||||
int sw = SW_HOST_CARD_IO_ERROR;
|
||||
|
||||
slotp = reader_table + slot;
|
||||
|
||||
@ -871,7 +933,7 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
|| slotp->pcsc.pid == (pid_t)(-1) )
|
||||
{
|
||||
log_error ("pcsc_get_status: pcsc-wrapper not running\n");
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return sw;
|
||||
}
|
||||
|
||||
msgbuf[0] = 0x04; /* STATUS command. */
|
||||
@ -906,7 +968,8 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
{
|
||||
log_error ("pcsc_status failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
/* This is a proper error code, so return immediately. */
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
|
||||
full_len = len;
|
||||
@ -950,7 +1013,7 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
kill (slotp->pcsc.pid, SIGTERM);
|
||||
slotp->pcsc.pid = (pid_t)(-1);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
return sw;
|
||||
|
||||
#else /*!NEED_PCSC_WRAPPER*/
|
||||
|
||||
@ -963,13 +1026,13 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
err = pcsc_get_status_change (reader_table[slot].pcsc.context,
|
||||
0,
|
||||
rdrstates, 1);
|
||||
if (err == 0x8010000a) /* Timeout. */
|
||||
err = 0;
|
||||
if (err == PCSC_E_TIMEOUT)
|
||||
err = 0; /* Timeout is no error error here. */
|
||||
if (err)
|
||||
{
|
||||
log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
|
||||
|
||||
@ -1016,6 +1079,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
size_t len, full_len;
|
||||
int i, n;
|
||||
unsigned char msgbuf[9];
|
||||
int sw = SW_HOST_CARD_IO_ERROR;
|
||||
|
||||
if (!reader_table[slot].atrlen
|
||||
&& (err = reset_pcsc_reader (slot)))
|
||||
@ -1031,7 +1095,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
|| slotp->pcsc.pid == (pid_t)(-1) )
|
||||
{
|
||||
log_error ("pcsc_send_apdu: pcsc-wrapper not running\n");
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return sw;
|
||||
}
|
||||
|
||||
msgbuf[0] = 0x03; /* TRANSMIT command. */
|
||||
@ -1067,7 +1131,7 @@ 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 SW_HOST_CARD_IO_ERROR;
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
|
||||
full_len = len;
|
||||
@ -1113,7 +1177,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
kill (slotp->pcsc.pid, SIGTERM);
|
||||
slotp->pcsc.pid = (pid_t)(-1);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
return sw;
|
||||
|
||||
#else /*!NEED_PCSC_WRAPPER*/
|
||||
|
||||
@ -1142,7 +1206,7 @@ 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? SW_HOST_CARD_IO_ERROR:0;
|
||||
return pcsc_error_to_sw (err);
|
||||
#endif /*!NEED_PCSC_WRAPPER*/
|
||||
}
|
||||
|
||||
@ -1199,7 +1263,7 @@ close_pcsc_reader (int slot)
|
||||
log_error ("pcsc_close failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
|
||||
/* We will the wrapper in any case - errors are merely
|
||||
/* We will close the wrapper in any case - errors are merely
|
||||
informational. */
|
||||
|
||||
command_failed:
|
||||
@ -1222,6 +1286,7 @@ close_pcsc_reader (int slot)
|
||||
#endif /*!NEED_PCSC_WRAPPER*/
|
||||
}
|
||||
|
||||
/* Note: It is a pitty that we can't return proper error codes. */
|
||||
static int
|
||||
open_pcsc_reader (const char *portstr)
|
||||
{
|
||||
@ -1237,6 +1302,7 @@ open_pcsc_reader (const char *portstr)
|
||||
size_t len;
|
||||
unsigned char msgbuf[9];
|
||||
int err;
|
||||
int sw = SW_HOST_CARD_IO_ERROR;
|
||||
|
||||
slot = new_reader_slot ();
|
||||
if (slot == -1)
|
||||
@ -1373,6 +1439,7 @@ open_pcsc_reader (const char *portstr)
|
||||
if (err)
|
||||
{
|
||||
log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
|
||||
sw = pcsc_error_to_sw (err);
|
||||
goto command_failed;
|
||||
}
|
||||
|
||||
@ -1412,7 +1479,9 @@ open_pcsc_reader (const char *portstr)
|
||||
kill (slotp->pcsc.pid, SIGTERM);
|
||||
slotp->pcsc.pid = (pid_t)(-1);
|
||||
slotp->used = 0;
|
||||
/* There is no way to return SW. */
|
||||
return -1;
|
||||
|
||||
#else /*!NEED_PCSC_WRAPPER */
|
||||
long err;
|
||||
int slot;
|
||||
@ -1445,7 +1514,7 @@ open_pcsc_reader (const char *portstr)
|
||||
log_error ("error allocating memory for reader list\n");
|
||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||
reader_table[slot].used = 0;
|
||||
return -1;
|
||||
return -1 /*SW_HOST_OUT_OF_CORE*/;
|
||||
}
|
||||
err = pcsc_list_readers (reader_table[slot].pcsc.context,
|
||||
NULL, list, &nreader);
|
||||
@ -1457,7 +1526,7 @@ open_pcsc_reader (const char *portstr)
|
||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||
reader_table[slot].used = 0;
|
||||
xfree (list);
|
||||
return -1;
|
||||
return -1 /*pcsc_error_to_sw (err)*/;
|
||||
}
|
||||
|
||||
listlen = nreader;
|
||||
@ -1483,7 +1552,7 @@ open_pcsc_reader (const char *portstr)
|
||||
log_error ("error allocating memory for reader name\n");
|
||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||
reader_table[slot].used = 0;
|
||||
return -1;
|
||||
return -1 /*SW_HOST_OUT_OF_CORE*/;
|
||||
}
|
||||
strcpy (reader_table[slot].rdrname, portstr? portstr : list);
|
||||
xfree (list);
|
||||
@ -1494,7 +1563,7 @@ open_pcsc_reader (const char *portstr)
|
||||
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
|
||||
&reader_table[slot].pcsc.card,
|
||||
&reader_table[slot].pcsc.protocol);
|
||||
if (err == 0x8010000c) /* No smartcard. */
|
||||
if (err == PCSC_E_NO_SMARTCARD)
|
||||
reader_table[slot].pcsc.card = 0;
|
||||
else if (err)
|
||||
{
|
||||
@ -1505,7 +1574,7 @@ open_pcsc_reader (const char *portstr)
|
||||
reader_table[slot].rdrname = NULL;
|
||||
reader_table[slot].used = 0;
|
||||
xfree (list);
|
||||
return -1;
|
||||
return -1 /*pcsc_error_to_sw (err)*/;
|
||||
}
|
||||
|
||||
reader_table[slot].atrlen = 0;
|
||||
@ -3049,5 +3118,3 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
|
||||
return 0;
|
||||
#undef RESULTLEN
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,7 +104,8 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
|
||||
|
||||
|
||||
/*-- app.c --*/
|
||||
app_t select_application (ctrl_t ctrl, int slot, const char *name);
|
||||
gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name,
|
||||
app_t *r_app);
|
||||
void release_application (app_t app);
|
||||
int app_munge_serialno (app_t app);
|
||||
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||
|
@ -306,23 +306,33 @@ flush_cache (app_t app)
|
||||
NULL if not found or a pointer which must be used to release the
|
||||
buffer holding value. */
|
||||
static void *
|
||||
get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
|
||||
get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
|
||||
int *r_rc)
|
||||
{
|
||||
int rc, i;
|
||||
unsigned char *buffer;
|
||||
size_t buflen;
|
||||
unsigned char *value;
|
||||
size_t valuelen;
|
||||
int dummyrc;
|
||||
|
||||
if (!r_rc)
|
||||
r_rc = &dummyrc;
|
||||
|
||||
*result = NULL;
|
||||
*nbytes = 0;
|
||||
*r_rc = 0;
|
||||
for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++)
|
||||
;
|
||||
|
||||
if (app->card_version > 0x0100 && data_objects[i].get_immediate_in_v11)
|
||||
{
|
||||
if( iso7816_get_data (app->slot, tag, &buffer, &buflen))
|
||||
rc = iso7816_get_data (app->slot, tag, &buffer, &buflen);
|
||||
if (rc)
|
||||
{
|
||||
*r_rc = rc;
|
||||
return NULL;
|
||||
}
|
||||
*result = buffer;
|
||||
*nbytes = buflen;
|
||||
return buffer;
|
||||
@ -334,7 +344,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
|
||||
{
|
||||
rc = get_cached_data (app, data_objects[i].get_from,
|
||||
&buffer, &buflen,
|
||||
data_objects[i].get_immediate_in_v11);
|
||||
(data_objects[i].dont_cache
|
||||
|| data_objects[i].get_immediate_in_v11));
|
||||
if (!rc)
|
||||
{
|
||||
const unsigned char *s;
|
||||
@ -356,7 +367,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,
|
||||
data_objects[i].get_immediate_in_v11);
|
||||
(data_objects[i].dont_cache
|
||||
|| data_objects[i].get_immediate_in_v11));
|
||||
if (!rc)
|
||||
{
|
||||
value = buffer;
|
||||
@ -370,6 +382,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
|
||||
*result = value;
|
||||
return buffer;
|
||||
}
|
||||
*r_rc = rc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -488,7 +501,7 @@ parse_login_data (app_t app)
|
||||
app->app_local->flags.def_chv2 = 0;
|
||||
|
||||
/* Read the DO. */
|
||||
relptr = get_one_do (app, 0x005E, &buffer, &buflen);
|
||||
relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL);
|
||||
if (!relptr)
|
||||
return; /* Ooops. */
|
||||
for (; buflen; buflen--, buffer++)
|
||||
@ -678,7 +691,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
{ "PRIVATE-DO-4", 0x0104 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
int idx, i;
|
||||
int idx, i, rc;
|
||||
void *relptr;
|
||||
unsigned char *value;
|
||||
size_t valuelen;
|
||||
@ -723,7 +736,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
relptr = get_one_do (app, table[idx].tag, &value, &valuelen);
|
||||
relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc);
|
||||
if (relptr)
|
||||
{
|
||||
if (table[idx].special == 1)
|
||||
@ -760,7 +773,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
|
||||
xfree (relptr);
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -1075,7 +1088,7 @@ verify_chv3 (app_t app,
|
||||
unsigned char *value;
|
||||
size_t valuelen;
|
||||
|
||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
|
||||
if (!relptr || valuelen < 7)
|
||||
{
|
||||
log_error (_("error retrieving CHV status from card\n"));
|
||||
@ -1442,7 +1455,7 @@ get_sig_counter (app_t app)
|
||||
size_t valuelen;
|
||||
unsigned long ul;
|
||||
|
||||
relptr = get_one_do (app, 0x0093, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x0093, &value, &valuelen, NULL);
|
||||
if (!relptr)
|
||||
return 0;
|
||||
ul = convert_sig_counter_value (value, valuelen);
|
||||
@ -1880,7 +1893,7 @@ app_select_openpgp (app_t app)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
relptr = get_one_do (app, 0x00C4, &buffer, &buflen);
|
||||
relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
|
||||
if (!relptr)
|
||||
{
|
||||
log_error (_("can't access %s - invalid OpenPGP card?\n"),
|
||||
@ -1890,7 +1903,7 @@ app_select_openpgp (app_t app)
|
||||
app->force_chv1 = (buflen && *buffer == 0);
|
||||
xfree (relptr);
|
||||
|
||||
relptr = get_one_do (app, 0x00C0, &buffer, &buflen);
|
||||
relptr = get_one_do (app, 0x00C0, &buffer, &buflen, NULL);
|
||||
if (!relptr)
|
||||
{
|
||||
log_error (_("can't access %s - invalid OpenPGP card?\n"),
|
||||
@ -1973,7 +1986,7 @@ app_openpgp_cardinfo (app_t app,
|
||||
if (disp_name)
|
||||
{
|
||||
*disp_name = NULL;
|
||||
relptr = get_one_do (app, 0x005B, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x005B, &value, &valuelen, NULL);
|
||||
if (relptr)
|
||||
{
|
||||
*disp_name = make_printable_string (value, valuelen, 0);
|
||||
@ -1984,7 +1997,7 @@ app_openpgp_cardinfo (app_t app,
|
||||
if (pubkey_url)
|
||||
{
|
||||
*pubkey_url = NULL;
|
||||
relptr = get_one_do (app, 0x5F50, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x5F50, &value, &valuelen, NULL);
|
||||
if (relptr)
|
||||
{
|
||||
*pubkey_url = make_printable_string (value, valuelen, 0);
|
||||
@ -1998,7 +2011,7 @@ app_openpgp_cardinfo (app_t app,
|
||||
*fpr2 = NULL;
|
||||
if (fpr3)
|
||||
*fpr3 = NULL;
|
||||
relptr = get_one_do (app, 0x00C5, &value, &valuelen);
|
||||
relptr = get_one_do (app, 0x00C5, &value, &valuelen, NULL);
|
||||
if (relptr && valuelen >= 60)
|
||||
{
|
||||
if (fpr1)
|
||||
|
26
scd/app.c
26
scd/app.c
@ -1,5 +1,5 @@
|
||||
/* app.c - Application selection.
|
||||
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -49,21 +49,23 @@ is_app_allowed (const char *name)
|
||||
/* If called with NAME as NULL, select the best fitting application
|
||||
and return a context; otherwise select the application with NAME
|
||||
and return a context. SLOT identifies the reader device. Returns
|
||||
NULL if no application was found or no card is present. */
|
||||
APP
|
||||
select_application (ctrl_t ctrl, int slot, const char *name)
|
||||
an error code and stores NULL at R_APP if no application was found
|
||||
or no card is present. */
|
||||
gpg_error_t
|
||||
select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
|
||||
{
|
||||
int rc;
|
||||
APP app;
|
||||
app_t app;
|
||||
unsigned char *result = NULL;
|
||||
size_t resultlen;
|
||||
|
||||
*r_app = NULL;
|
||||
app = xtrycalloc (1, sizeof *app);
|
||||
if (!app)
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
rc = gpg_error_from_errno (errno);
|
||||
log_info ("error allocating context: %s\n", gpg_strerror (rc));
|
||||
return NULL;
|
||||
return rc;
|
||||
}
|
||||
app->slot = slot;
|
||||
|
||||
@ -111,7 +113,12 @@ select_application (ctrl_t ctrl, int slot, const char *name)
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
/* For certain error codes, there is no need to try more. */
|
||||
if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT)
|
||||
goto leave;
|
||||
|
||||
|
||||
/* Figure out the application to use. */
|
||||
rc = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
|
||||
if (rc && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp")))
|
||||
@ -135,11 +142,12 @@ select_application (ctrl_t ctrl, int slot, const char *name)
|
||||
log_info ("no supported card application found: %s\n",
|
||||
gpg_strerror (rc));
|
||||
xfree (app);
|
||||
return NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
app->initialized = 1;
|
||||
return app;
|
||||
*r_app = app;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,10 +45,24 @@ static ctrl_t primary_connection;
|
||||
|
||||
#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
|
||||
|
||||
|
||||
/* Macro to flag a a removed card. */
|
||||
#define TEST_CARD_REMOVAL(c,r) \
|
||||
do { \
|
||||
int _r = (r); \
|
||||
if (gpg_err_code (_r) == GPG_ERR_CARD_NOT_PRESENT \
|
||||
|| gpg_err_code (_r) == GPG_ERR_CARD_REMOVED) \
|
||||
(c)->server_local->card_removed = 1; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Data used to associate an Assuan context with local server data */
|
||||
struct server_local_s {
|
||||
ASSUAN_CONTEXT assuan_ctx;
|
||||
assuan_context_t assuan_ctx;
|
||||
int event_signal; /* Or 0 if not used. */
|
||||
int card_removed; /* True if the card has been removed and a
|
||||
reset is required to continue
|
||||
operation. */
|
||||
};
|
||||
|
||||
|
||||
@ -89,6 +103,7 @@ do_reset (ctrl_t ctrl, int do_close)
|
||||
ctrl->reader_slot = -1;
|
||||
}
|
||||
}
|
||||
ctrl->server_local->card_removed = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -122,11 +137,18 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
|
||||
/* If the card has not yet been opened, do it. Note that this
|
||||
function returns an Assuan error, so don't map the error a second
|
||||
time */
|
||||
static AssuanError
|
||||
static assuan_error_t
|
||||
open_card (ctrl_t ctrl, const char *apptype)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int slot;
|
||||
|
||||
/* If we ever got a card not present error code, return that. Only
|
||||
the SERIALNO command and a reset are able to clear from that
|
||||
state. */
|
||||
if (ctrl->server_local->card_removed)
|
||||
return map_to_assuan_status (gpg_error (GPG_ERR_CARD_REMOVED));
|
||||
|
||||
if (ctrl->app_ctx)
|
||||
return 0; /* Already initialized for one specific application. */
|
||||
if (ctrl->card_ctx)
|
||||
@ -137,24 +159,28 @@ open_card (ctrl_t ctrl, const char *apptype)
|
||||
else
|
||||
slot = apdu_open_reader (opt.reader_port);
|
||||
ctrl->reader_slot = slot;
|
||||
if (slot != -1)
|
||||
ctrl->app_ctx = select_application (ctrl, slot, apptype);
|
||||
if (!ctrl->app_ctx)
|
||||
{ /* No application found - fall back to old mode. */
|
||||
if (slot == -1)
|
||||
err = gpg_error (GPG_ERR_CARD);
|
||||
else
|
||||
err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
|
||||
if (!ctrl->app_ctx
|
||||
&& gpg_err_code (err) != GPG_ERR_CARD_NOT_PRESENT)
|
||||
{
|
||||
/* No application found - fall back to old mode. */
|
||||
/* Note that we should rework the old code to use the
|
||||
application paradigma too. */
|
||||
int rc;
|
||||
|
||||
/* If an APPTYPE was requested and it is not pkcs#15, we return
|
||||
an error here. */
|
||||
if (apptype && !(!strcmp (apptype, "P15") || !strcmp (apptype, "p15")))
|
||||
rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
else
|
||||
rc = card_open (&ctrl->card_ctx);
|
||||
if (rc)
|
||||
return map_to_assuan_status (rc);
|
||||
err = card_open (&ctrl->card_ctx);
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
|
||||
ctrl->server_local->card_removed = 1;
|
||||
|
||||
return map_to_assuan_status (err);
|
||||
}
|
||||
|
||||
|
||||
@ -215,12 +241,15 @@ percent_plus_unescape (unsigned char *string)
|
||||
static int
|
||||
cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
int rc = 0;
|
||||
char *serial_and_stamp;
|
||||
char *serial;
|
||||
time_t stamp;
|
||||
|
||||
/* Clear the remove flag so that the open_card is able to reread it. */
|
||||
ctrl->server_local->card_removed = 0;
|
||||
|
||||
if ((rc = open_card (ctrl, *line? line:NULL)))
|
||||
return rc;
|
||||
|
||||
@ -443,6 +472,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -485,6 +515,7 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
|
||||
return rc;
|
||||
}
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -575,6 +606,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
|
||||
leave:
|
||||
ksba_cert_release (kc);
|
||||
xfree (cert);
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -697,6 +729,7 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
|
||||
return rc; /* that is already an assuan error code */
|
||||
}
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -743,6 +776,7 @@ cmd_pkauth (ASSUAN_CONTEXT ctx, char *line)
|
||||
return rc; /* that is already an assuan error code */
|
||||
}
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -789,6 +823,7 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
|
||||
return rc; /* that is already an assuan error code */
|
||||
}
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -824,6 +859,7 @@ cmd_getattr (ASSUAN_CONTEXT ctx, char *line)
|
||||
|
||||
rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -871,6 +907,7 @@ cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line)
|
||||
rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx, line, nbytes);
|
||||
xfree (linebuf);
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -927,6 +964,8 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx);
|
||||
xfree (keyno);
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -966,6 +1005,7 @@ cmd_random (ASSUAN_CONTEXT ctx, char *line)
|
||||
}
|
||||
xfree (buffer);
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -1010,6 +1050,8 @@ cmd_passwd (ASSUAN_CONTEXT ctx, char *line)
|
||||
if (rc)
|
||||
log_error ("command passwd failed: %s\n", gpg_strerror (rc));
|
||||
xfree (chvnostr);
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -1044,6 +1086,7 @@ cmd_checkpin (ASSUAN_CONTEXT ctx, char *line)
|
||||
if (rc)
|
||||
log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
|
||||
|
||||
TEST_CARD_REMOVAL (ctrl, rc);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
@ -1226,7 +1269,9 @@ send_status_info (CTRL ctrl, const char *keyword, ...)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This fucntion is called by the ticker thread to check for changes
|
||||
of the reader stati. It updates the reader status files and if
|
||||
requested by the caller also send a signal to the caller. */
|
||||
void
|
||||
scd_update_reader_status_file (void)
|
||||
{
|
||||
@ -1239,10 +1284,10 @@ scd_update_reader_status_file (void)
|
||||
int used;
|
||||
unsigned int status, changed;
|
||||
|
||||
/* Note, that we only try to get the status, becuase it does not
|
||||
/* Note, that we only try to get the status, because it does not
|
||||
make sense to wait here for a operation to complete. If we are
|
||||
so busy working with the card, delays in the status file updated
|
||||
are should be acceptable. */
|
||||
busy working with a card, delays in the status file update should
|
||||
be acceptable. */
|
||||
for (slot=0; (slot < DIM(last)
|
||||
&&!apdu_enum_reader (slot, &used)); slot++)
|
||||
if (used && !apdu_get_status (slot, 0, &status, &changed))
|
||||
|
@ -936,7 +936,7 @@ ticker_thread (void *dummy_arg)
|
||||
sigs_ev = NULL;
|
||||
#endif
|
||||
|
||||
for (;;)
|
||||
while (!shutdown_pending)
|
||||
{
|
||||
if (!time_ev)
|
||||
{
|
||||
@ -968,6 +968,7 @@ ticker_thread (void *dummy_arg)
|
||||
}
|
||||
|
||||
pth_event_free (sigs_ev, PTH_FREE_ALL);
|
||||
return NULL;
|
||||
}
|
||||
#endif /*USE_GNU_PTH*/
|
||||
#endif /*!HAVE_OPENSC*/
|
||||
|
@ -59,10 +59,10 @@
|
||||
Print VALUE.
|
||||
|
||||
openfile <filename>
|
||||
Open file FILENAME for read access and retrun the file descriptor.
|
||||
Open file FILENAME for read access and return the file descriptor.
|
||||
|
||||
createfile <filename>
|
||||
Create file FILENAME, open for write access and retrun the file
|
||||
Create file FILENAME, open for write access and return the file
|
||||
descriptor.
|
||||
|
||||
pipeserver <program>
|
||||
|
@ -1,3 +1,8 @@
|
||||
2005-02-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg-connect-agent.c: New.
|
||||
* Makefile.am: Add it.
|
||||
|
||||
2004-12-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgconf-comp.c (get_config_pathname) [DOSISH]: Detect absolute
|
||||
|
@ -24,15 +24,13 @@ EXTRA_DIST = Manifest watchgnupg.c \
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/intl -I$(top_srcdir)/common
|
||||
include $(top_srcdir)/am/cmacros.am
|
||||
|
||||
# Note, that we require GPG_ERROR_CFLAGS only because some share header files
|
||||
# require that file. It is not actually used in gpgconf.
|
||||
AM_CFLAGS = @GPG_ERROR_CFLAGS@
|
||||
AM_CFLAGS = $(GPG_ERROR_CFLAGS) $(LIBASSUAN_CFLAGS)
|
||||
|
||||
sbin_SCRIPTS = addgnupghome
|
||||
|
||||
bin_SCRIPTS = gpgsm-gencert.sh
|
||||
|
||||
bin_PROGRAMS = gpgconf
|
||||
bin_PROGRAMS = gpgconf gpg-connect-agent
|
||||
if !HAVE_W32_SYSTEM
|
||||
bin_PROGRAMS += watchgnupg
|
||||
endif
|
||||
@ -42,3 +40,8 @@ gpgconf_SOURCES = gpgconf.c gpgconf.h gpgconf-comp.c no-libgcrypt.c
|
||||
gpgconf_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a @LIBINTL@
|
||||
|
||||
watchgnupg_SOURCES = watchgnupg.c
|
||||
|
||||
gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c
|
||||
gpg_connect_agent_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \
|
||||
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL)
|
||||
|
||||
|
362
tools/gpg-connect-agent.c
Normal file
362
tools/gpg-connect-agent.c
Normal file
@ -0,0 +1,362 @@
|
||||
/* gpg-connect-agent.c - Tool to connect to the agent.
|
||||
* Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assuan.h>
|
||||
|
||||
#include "i18n.h"
|
||||
#include "../common/util.h"
|
||||
#include "../common/asshelp.h"
|
||||
|
||||
|
||||
|
||||
/* Constants to identify the commands and options. */
|
||||
enum cmd_and_opt_values
|
||||
{
|
||||
aNull = 0,
|
||||
oQuiet = 'q',
|
||||
oVerbose = 'v',
|
||||
|
||||
oNoVerbose = 500,
|
||||
oHomedir
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* The list of commands and options. */
|
||||
static ARGPARSE_OPTS opts[] =
|
||||
{
|
||||
{ 301, NULL, 0, N_("@\nOptions:\n ") },
|
||||
|
||||
{ oVerbose, "verbose", 0, N_("verbose") },
|
||||
{ oQuiet, "quiet", 0, N_("quiet") },
|
||||
|
||||
/* hidden options */
|
||||
{ oNoVerbose, "no-verbose", 0, "@"},
|
||||
{ oHomedir, "homedir", 2, "@" },
|
||||
{0}
|
||||
};
|
||||
|
||||
|
||||
/* We keep all global options in the structure OPT. */
|
||||
struct
|
||||
{
|
||||
int verbose; /* Verbosity level. */
|
||||
int quiet; /* Be extra quiet. */
|
||||
const char *homedir; /* Configuration directory name */
|
||||
|
||||
} opt;
|
||||
|
||||
|
||||
/*-- local prototypes --*/
|
||||
static int read_and_print_response (assuan_context_t ctx);
|
||||
static assuan_context_t start_agent (void);
|
||||
|
||||
|
||||
|
||||
|
||||
/* Print usage information and and provide strings for help. */
|
||||
static const char *
|
||||
my_strusage( int level )
|
||||
{
|
||||
const char *p;
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case 11: p = "gpg-connect-agent (GnuPG)";
|
||||
break;
|
||||
case 13: p = VERSION; break;
|
||||
case 17: p = PRINTABLE_OS_NAME; break;
|
||||
case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
|
||||
break;
|
||||
case 1:
|
||||
case 40: p = _("Usage: gpg-connect-agent [options] (-h for help)");
|
||||
break;
|
||||
case 41:
|
||||
p = _("Syntax: gpg-connect-agent [options]\n"
|
||||
"Connect to a running agent and send commands\n");
|
||||
break;
|
||||
case 31: p = "\nHome: "; break;
|
||||
case 32: p = opt.homedir; break;
|
||||
case 33: p = "\n"; break;
|
||||
|
||||
default: p = NULL; break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize the gettext system. */
|
||||
static void
|
||||
i18n_init(void)
|
||||
{
|
||||
#ifdef USE_SIMPLE_GETTEXT
|
||||
set_gettext_file (PACKAGE_GT);
|
||||
#else
|
||||
# ifdef ENABLE_NLS
|
||||
setlocale (LC_ALL, "" );
|
||||
bindtextdomain (PACKAGE_GT, LOCALEDIR);
|
||||
textdomain (PACKAGE_GT);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* gpg-connect-agent's entry point. */
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
ARGPARSE_ARGS pargs;
|
||||
const char *fname;
|
||||
int no_more_options = 0;
|
||||
assuan_context_t ctx;
|
||||
char *line;
|
||||
size_t linesize;
|
||||
int rc;
|
||||
|
||||
set_strusage (my_strusage);
|
||||
log_set_prefix ("gpg-connect-agent", 1);
|
||||
|
||||
i18n_init();
|
||||
|
||||
opt.homedir = default_homedir ();
|
||||
|
||||
/* Parse the command line. */
|
||||
pargs.argc = &argc;
|
||||
pargs.argv = &argv;
|
||||
pargs.flags = 1; /* Do not remove the args. */
|
||||
while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
|
||||
{
|
||||
switch (pargs.r_opt)
|
||||
{
|
||||
case oQuiet: opt.quiet = 1; break;
|
||||
case oVerbose: opt.verbose++; break;
|
||||
case oNoVerbose: opt.verbose = 0; break;
|
||||
case oHomedir: opt.homedir = pargs.r.ret_str; break;
|
||||
|
||||
default: pargs.err = 2; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (log_get_errorcount (0))
|
||||
exit (2);
|
||||
|
||||
fname = argc ? *argv : NULL;
|
||||
|
||||
ctx = start_agent ();
|
||||
line = NULL;
|
||||
linesize = 0;
|
||||
for (;;)
|
||||
{
|
||||
int n;
|
||||
size_t maxlength;
|
||||
|
||||
maxlength = 2048;
|
||||
n = read_line (stdin, &line, &linesize, &maxlength);
|
||||
if (n < 0)
|
||||
{
|
||||
log_error (_("error reading input: %s\n"), strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
if (!n)
|
||||
break; /* EOF */
|
||||
if (!maxlength)
|
||||
{
|
||||
log_error (_("line too long - skipped\n"));
|
||||
continue;
|
||||
}
|
||||
if (memchr (line, 0, n))
|
||||
log_info (_("line shortened due to embedded Nul character\n"));
|
||||
if (line[n-1] == '\n')
|
||||
line[n-1] = 0;
|
||||
rc = assuan_write_line (ctx, line);
|
||||
if (rc)
|
||||
{
|
||||
log_info (_("sending line failed: %s\n"), assuan_strerror (rc) );
|
||||
continue;
|
||||
}
|
||||
if (*line == '#' || !*line)
|
||||
continue; /* Don't expect a response for a coment line. */
|
||||
|
||||
rc = read_and_print_response (ctx);
|
||||
if (rc)
|
||||
log_info (_("receiving line failed: %s\n"), assuan_strerror (rc) );
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("closing connection to agent\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read all response lines from server and print them. Returns 0 on
|
||||
success or an assuan error code. */
|
||||
static int
|
||||
read_and_print_response (assuan_context_t ctx)
|
||||
{
|
||||
char *line;
|
||||
int linelen;
|
||||
assuan_error_t rc;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
do
|
||||
{
|
||||
rc = assuan_read_line (ctx, &line, &linelen);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
while (*line == '#' || !linelen);
|
||||
|
||||
if (linelen >= 1
|
||||
&& line[0] == 'D' && line[1] == ' ')
|
||||
{
|
||||
fwrite (line, linelen, 1, stdout);
|
||||
putchar ('\n');
|
||||
}
|
||||
else if (linelen >= 1
|
||||
&& line[0] == 'S'
|
||||
&& (line[1] == '\0' || line[1] == ' '))
|
||||
{
|
||||
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');
|
||||
return 0;
|
||||
}
|
||||
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 ASSUAN_Invalid_Response;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Connect to teh agebnt and send the standard options. */
|
||||
static assuan_context_t
|
||||
start_agent (void)
|
||||
{
|
||||
int rc = 0;
|
||||
char *infostr, *p;
|
||||
assuan_context_t ctx;
|
||||
|
||||
infostr = getenv ("GPG_AGENT_INFO");
|
||||
if (!infostr || !*infostr)
|
||||
{
|
||||
char *sockname;
|
||||
|
||||
/* Check whether we can connect at the standard socket. */
|
||||
sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
|
||||
rc = assuan_socket_connect (&ctx, sockname, 0);
|
||||
xfree (sockname);
|
||||
}
|
||||
else
|
||||
{
|
||||
int prot;
|
||||
int pid;
|
||||
|
||||
infostr = xstrdup (infostr);
|
||||
if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
|
||||
{
|
||||
log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
|
||||
xfree (infostr);
|
||||
exit (1);
|
||||
}
|
||||
*p++ = 0;
|
||||
pid = atoi (p);
|
||||
while (*p && *p != ':')
|
||||
p++;
|
||||
prot = *p? atoi (p+1) : 0;
|
||||
if (prot != 1)
|
||||
{
|
||||
log_error (_("gpg-agent protocol version %d is not supported\n"),
|
||||
prot);
|
||||
xfree (infostr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
rc = assuan_socket_connect (&ctx, infostr, pid);
|
||||
xfree (infostr);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("connection to agent established\n");
|
||||
|
||||
rc = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
{
|
||||
log_error (_("error sending %s command: %s\n"), "RESET",
|
||||
assuan_strerror (rc));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
rc = send_pinentry_environment (ctx, GPG_ERR_SOURCE_DEFAULT,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
{
|
||||
log_error (_("error sending standard options: %s\n"), gpg_strerror (rc));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user