* agent.h (server_control_s): Add connection_fd field.

* command.c (start_command_handler): Init it here.
* gpg-agent.c (agent_init_default_ctrl): and here.
* call-scd.c: Add the CTRL arg to all functions calling start_scd
and pass it to start_scd.  Changed all callers
(start_scd): Keep track of the current active connection.
(agent_reset_scd): New.
* command.c (start_command_handler): Call it here.
* learncard.c (agent_handle_learn): Add arg CTRL; changed caller.
(send_cert_back): Ditto.
This commit is contained in:
Werner Koch 2004-01-29 20:17:27 +00:00
parent e4587ba874
commit b11106ebf0
7 changed files with 138 additions and 46 deletions

View File

@ -1,3 +1,16 @@
2004-01-29 Werner Koch <wk@gnupg.org>
* agent.h (server_control_s): Add connection_fd field.
* command.c (start_command_handler): Init it here.
* gpg-agent.c (agent_init_default_ctrl): and here.
* call-scd.c: Add the CTRL arg to all functions calling start_scd
and pass it to start_scd. Changed all callers
(start_scd): Keep track of the current active connection.
(agent_reset_scd): New.
* command.c (start_command_handler): Call it here.
* learncard.c (agent_handle_learn): Add arg CTRL; changed caller.
(send_cert_back): Ditto.
2004-01-28 Werner Koch <wk@gnupg.org>
* trustlist.c (agent_marktrusted): Check whether the trustlist is
@ -18,7 +31,7 @@
* findkey.c (agent_key_from_file): Now return an error code so
that we have more detailed error messages in the upper layers.
This fixes the handling pinentry's cancel button.
This fixes the handling of pinentry's cancel button.
* pksign.c (agent_pksign): Changed accordingly.
* pkdecrypt.c (agent_pkdecrypt): Ditto.
* command.c (cmd_passwd): Ditto.

View File

@ -83,6 +83,7 @@ struct server_local_s;
struct server_control_s {
struct server_local_s *server_local;
int connection_fd; /* -1 or an identifier for the current connection. */
char *display;
char *ttyname;
char *ttytype;
@ -98,6 +99,7 @@ struct server_control_s {
};
typedef struct server_control_s *CTRL;
typedef struct server_control_s *ctrl_t;
struct pin_entry_info_s {
@ -194,33 +196,38 @@ int divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context);
/*-- call-scd.c --*/
int agent_card_learn (void (*kpinfo_cb)(void*, const char *),
int agent_reset_scd (ctrl_t ctrl);
int agent_card_learn (ctrl_t ctrl,
void (*kpinfo_cb)(void*, const char *),
void *kpinfo_cb_arg,
void (*certinfo_cb)(void*, const char *),
void *certinfo_cb_arg,
void (*sinfo_cb)(void*, const char *,
size_t, const char *),
void *sinfo_cb_arg);
int agent_card_serialno (char **r_serialno);
int agent_card_pksign (const char *keyid,
int agent_card_serialno (ctrl_t ctrl, char **r_serialno);
int agent_card_pksign (ctrl_t ctrl,
const char *keyid,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg,
const unsigned char *indata, size_t indatalen,
char **r_buf, size_t *r_buflen);
int agent_card_pkdecrypt (const char *keyid,
int agent_card_pkdecrypt (ctrl_t ctrl,
const char *keyid,
int (*getpin_cb)(void *, const char *, char*,size_t),
void *getpin_cb_arg,
const unsigned char *indata, size_t indatalen,
char **r_buf, size_t *r_buflen);
int agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen);
int agent_card_readkey (const char *id, unsigned char **r_buf);
int agent_card_scd (const char *cmdline,
int agent_card_readcert (ctrl_t ctrl,
const char *id, char **r_buf, size_t *r_buflen);
int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf);
int agent_card_scd (ctrl_t ctrl, const char *cmdline,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg, void *assuan_context);
/*-- learncard.c --*/
int agent_handle_learn (void *assuan_context);
int agent_handle_learn (ctrl_t ctrl, void *assuan_context);
#endif /*AGENT_H*/

View File

@ -50,6 +50,17 @@ static ASSUAN_CONTEXT scd_ctx = NULL;
#ifdef USE_GNU_PTH
static pth_mutex_t scd_lock = PTH_MUTEX_INIT;
#endif
/* We need to keep track of the connection currently using the SCD.
For a pipe server this is all a NOP becuase the connection will
always have the conenction indicator -1. agent_reset_scd releases
the active connection; i.e. sets it back to -1, so that a new
connection can start using the SCD. If we eventually allow
multiple SCD session we will either make scdaemon multi-threaded or
fork of a new scdaemon and let it see how it can get access to a
reader.
*/
static int active_connection_fd = -1;
static int active_connection = 0;
/* callback parameter for learn card */
struct learn_parm_s {
@ -162,9 +173,10 @@ atfork_cb (void *opaque, int where)
}
/* Fork off the SCdaemon if this has not already been done */
/* Fork off the SCdaemon if this has not already been done. Note that
this fucntion alos locks the daemon. */
static int
start_scd (void)
start_scd (ctrl_t ctrl)
{
int rc;
const char *pgmname;
@ -182,9 +194,20 @@ start_scd (void)
#endif
if (scd_ctx)
return 0; /* No need to serialize things because the agent is
expected to tun as a single-thread (or may be in
future using libpth) */
{
/* If we are not the connection currently using the SCD, return
an error. */
if (!active_connection)
{
active_connection_fd = ctrl->connection_fd;
active_connection = 1;
}
else if (ctrl->connection_fd != active_connection_fd)
return unlock_scd (gpg_error (GPG_ERR_CONFLICT));
/* Okay, we scdaemon already started and used by us. */
return 0;
}
if (opt.verbose)
log_info ("no running SCdaemon - starting it\n");
@ -226,13 +249,45 @@ start_scd (void)
return unlock_scd (gpg_error (GPG_ERR_NO_SCDAEMON));
}
scd_ctx = ctx;
active_connection_fd = ctrl->connection_fd;
active_connection = 1;
if (DBG_ASSUAN)
log_debug ("connection to SCdaemon established\n");
return 0;
}
/* Reset the SCD if it has been used. */
int
agent_reset_scd (ctrl_t ctrl)
{
int rc = 0;
#ifdef USE_GNU_PTH
if (!pth_mutex_acquire (&scd_lock, 0, NULL))
{
log_error ("failed to acquire the SCD lock for reset\n");
return gpg_error (GPG_ERR_INTERNAL);
}
#endif
if (active_connection && active_connection_fd == ctrl->connection_fd)
{
if (scd_ctx)
rc = assuan_transact (scd_ctx, "RESET", NULL, NULL,
NULL, NULL, NULL, NULL);
active_connection_fd = -1;
active_connection = 0;
}
return unlock_scd (map_assuan_err (rc));
}
static AssuanError
learn_status_cb (void *opaque, const char *line)
@ -264,7 +319,8 @@ learn_status_cb (void *opaque, const char *line)
/* Perform the learn command and return a list of all private keys
stored on the card. */
int
agent_card_learn (void (*kpinfo_cb)(void*, const char *),
agent_card_learn (ctrl_t ctrl,
void (*kpinfo_cb)(void*, const char *),
void *kpinfo_cb_arg,
void (*certinfo_cb)(void*, const char *),
void *certinfo_cb_arg,
@ -274,7 +330,7 @@ agent_card_learn (void (*kpinfo_cb)(void*, const char *),
int rc;
struct learn_parm_s parm;
rc = start_scd ();
rc = start_scd (ctrl);
if (rc)
return rc;
@ -330,12 +386,12 @@ get_serialno_cb (void *opaque, const char *line)
/* Return the serial number of the card or an appropriate error. The
serial number is returned as a hexstring. */
int
agent_card_serialno (char **r_serialno)
agent_card_serialno (ctrl_t ctrl, char **r_serialno)
{
int rc;
char *serialno = NULL;
rc = start_scd ();
rc = start_scd (ctrl);
if (rc)
return rc;
@ -405,7 +461,8 @@ inq_needpin (void *opaque, const char *line)
/* Create a signature using the current card */
int
agent_card_pksign (const char *keyid,
agent_card_pksign (ctrl_t ctrl,
const char *keyid,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg,
const unsigned char *indata, size_t indatalen,
@ -420,7 +477,7 @@ agent_card_pksign (const char *keyid,
size_t sigbuflen;
*r_buf = NULL;
rc = start_scd ();
rc = start_scd (ctrl);
if (rc)
return rc;
@ -476,11 +533,12 @@ agent_card_pksign (const char *keyid,
/* Decipher INDATA using the current card. Note that the returned value is */
int
agent_card_pkdecrypt (const char *keyid,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg,
const unsigned char *indata, size_t indatalen,
char **r_buf, size_t *r_buflen)
agent_card_pkdecrypt (ctrl_t ctrl,
const char *keyid,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg,
const unsigned char *indata, size_t indatalen,
char **r_buf, size_t *r_buflen)
{
int rc, i;
char *p, line[ASSUAN_LINELENGTH];
@ -489,7 +547,7 @@ agent_card_pkdecrypt (const char *keyid,
size_t len;
*r_buf = NULL;
rc = start_scd ();
rc = start_scd (ctrl);
if (rc)
return rc;
@ -531,7 +589,8 @@ agent_card_pkdecrypt (const char *keyid,
/* Read a certificate with ID into R_BUF and R_BUFLEN. */
int
agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
agent_card_readcert (ctrl_t ctrl,
const char *id, char **r_buf, size_t *r_buflen)
{
int rc;
char line[ASSUAN_LINELENGTH];
@ -539,7 +598,7 @@ agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
size_t len;
*r_buf = NULL;
rc = start_scd ();
rc = start_scd (ctrl);
if (rc)
return rc;
@ -567,7 +626,7 @@ agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
/* Read a key with ID and return it in an allocate buffer pointed to
by r_BUF as a valid S-expression. */
int
agent_card_readkey (const char *id, unsigned char **r_buf)
agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf)
{
int rc;
char line[ASSUAN_LINELENGTH];
@ -575,7 +634,7 @@ agent_card_readkey (const char *id, unsigned char **r_buf)
size_t len, buflen;
*r_buf = NULL;
rc = start_scd ();
rc = start_scd (ctrl);
if (rc)
return rc;
@ -642,14 +701,14 @@ pass_data_thru (void *opaque, const void *buffer, size_t length)
mechanism to pass everything verbatim to SCDAEMOPN. The PIN
inquirey is handled inside gpg-agent. */
int
agent_card_scd (const char *cmdline,
agent_card_scd (ctrl_t ctrl, const char *cmdline,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg, void *assuan_context)
{
int rc;
struct inq_needpin_s inqparm;
rc = start_scd ();
rc = start_scd (ctrl);
if (rc)
return rc;

View File

@ -579,9 +579,10 @@ cmd_get_confirmation (ASSUAN_CONTEXT ctx, char *line)
static int
cmd_learn (ASSUAN_CONTEXT ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
rc = agent_handle_learn (has_option (line, "--send")? ctx : NULL);
rc = agent_handle_learn (ctrl, has_option (line, "--send")? ctx : NULL);
if (rc)
log_error ("command learn failed: %s\n", gpg_strerror (rc));
return map_to_assuan_status (rc);
@ -771,6 +772,7 @@ start_command_handler (int listen_fd, int fd)
else
{
rc = assuan_init_connected_socket_server (&ctx, fd);
ctrl.connection_fd = fd;
}
if (rc)
{
@ -816,6 +818,8 @@ start_command_handler (int listen_fd, int fd)
}
}
/* Reset the SCD if needed. */
agent_reset_scd (&ctrl);
assuan_deinit_server (ctx);
if (ctrl.display)

View File

@ -81,7 +81,7 @@ ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid)
for (;;)
{
rc = agent_card_serialno (&serialno);
rc = agent_card_serialno (ctrl, &serialno);
if (!rc)
{
log_debug ("detected card with S/N %s\n", serialno);
@ -108,6 +108,13 @@ ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid)
if (!rc)
{
/* We better reset the SCD now. This is kludge requred
because the scdaemon is currently not always able to
detect the presence of a card. With a fully working
scdaemon this would not be required; i.e. the pkcs#15
support does not require it becuase OpenSC correclty
detects a present card. */
agent_reset_scd (ctrl);
if (asprintf (&desc,
"%s:%%0A%%0A"
" \"%.*s\"",
@ -230,7 +237,7 @@ divert_pksign (CTRL ctrl,
if (rc)
return rc;
rc = agent_card_pksign (kid, getpin_cb, ctrl,
rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
data, ndata, &sigval, &siglen);
if (!rc)
*r_sig = sigval;
@ -294,7 +301,7 @@ divert_pkdecrypt (CTRL ctrl,
if (rc)
return rc;
rc = agent_card_pkdecrypt (kid, getpin_cb, ctrl,
rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl,
ciphertext, ciphertextlen,
&plaintext, &plaintextlen);
if (!rc)
@ -310,7 +317,7 @@ divert_pkdecrypt (CTRL ctrl,
int
divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context)
{
return agent_card_scd (cmdline, getpin_cb, ctrl, assuan_context);
return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
}

View File

@ -784,6 +784,8 @@ agent_exit (int rc)
void
agent_init_default_ctrl (struct server_control_s *ctrl)
{
ctrl->connection_fd = -1;
/* Note we ignore malloc errors because we can't do much about it
and the request will fail anyway shortly after this
initialization. */

View File

@ -255,13 +255,13 @@ make_shadow_info (const char *serialno, const char *idstring)
}
static int
send_cert_back (const char *id, void *assuan_context)
send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
{
int rc;
char *derbuf;
size_t derbuflen;
rc = agent_card_readcert (id, &derbuf, &derbuflen);
rc = agent_card_readcert (ctrl, id, &derbuf, &derbuflen);
if (rc)
{
log_error ("error reading certificate: %s\n",
@ -287,7 +287,7 @@ send_cert_back (const char *id, void *assuan_context)
/* Perform the learn operation. If ASSUAN_CONTEXT is not NULL all new
certificates are send via Assuan */
int
agent_handle_learn (void *assuan_context)
agent_handle_learn (ctrl_t ctrl, void *assuan_context)
{
int rc;
struct kpinfo_cb_parm_s parm;
@ -313,12 +313,12 @@ agent_handle_learn (void *assuan_context)
memset (&sparm, 0, sizeof sparm);
/* Check whether a card is present and get the serial number */
rc = agent_card_serialno (&serialno);
rc = agent_card_serialno (ctrl, &serialno);
if (rc)
goto leave;
/* now gather all the available info */
rc = agent_card_learn (kpinfo_cb, &parm, certinfo_cb, &cparm,
rc = agent_card_learn (ctrl, kpinfo_cb, &parm, certinfo_cb, &cparm,
sinfo_cb, &sparm);
if (!rc && (parm.error || cparm.error || sparm.error))
rc = parm.error? parm.error : cparm.error? cparm.error : sparm.error;
@ -354,7 +354,7 @@ agent_handle_learn (void *assuan_context)
if (assuan_context)
{
rc = send_cert_back (citem->id, assuan_context);
rc = send_cert_back (ctrl, citem->id, assuan_context);
if (rc)
goto leave;
citem->done = 1;
@ -380,7 +380,7 @@ agent_handle_learn (void *assuan_context)
continue;
/* unknown - store it */
rc = agent_card_readkey (item->id, &pubkey);
rc = agent_card_readkey (ctrl, item->id, &pubkey);
if (rc)
{
log_debug ("agent_card_readkey failed: %s\n", gpg_strerror (rc));
@ -430,7 +430,7 @@ agent_handle_learn (void *assuan_context)
}
if (!citem)
{
rc = send_cert_back (item->id, assuan_context);
rc = send_cert_back (ctrl, item->id, assuan_context);
if (rc)
goto leave;
}